From 5c95dc61fcc11126694bfb8c963dfe418bdaa692 Mon Sep 17 00:00:00 2001
From: Stenzek <stenzek@gmail.com>
Date: Sat, 20 Apr 2019 23:39:54 +1000
Subject: [PATCH] OGL: Store shader source in OGLShader

So it can be dumped with info log when linking fails.
---
 Source/Core/VideoBackends/OGL/OGLShader.cpp   | 19 +++++++++--------
 Source/Core/VideoBackends/OGL/OGLShader.h     |  6 ++++--
 .../VideoBackends/OGL/ProgramShaderCache.cpp  | 21 ++++++++++++-------
 .../VideoBackends/OGL/ProgramShaderCache.h    |  4 ++--
 4 files changed, 30 insertions(+), 20 deletions(-)

diff --git a/Source/Core/VideoBackends/OGL/OGLShader.cpp b/Source/Core/VideoBackends/OGL/OGLShader.cpp
index fc13b5b975..ee96f1c352 100644
--- a/Source/Core/VideoBackends/OGL/OGLShader.cpp
+++ b/Source/Core/VideoBackends/OGL/OGLShader.cpp
@@ -24,15 +24,16 @@ static GLenum GetGLShaderTypeForStage(ShaderStage stage)
   }
 }
 
-OGLShader::OGLShader(ShaderStage stage, GLenum gl_type, GLuint gl_id)
+OGLShader::OGLShader(ShaderStage stage, GLenum gl_type, GLuint gl_id, std::string source)
     : AbstractShader(stage), m_id(ProgramShaderCache::GenerateShaderID()), m_type(gl_type),
-      m_gl_id(gl_id)
+      m_gl_id(gl_id), m_source(std::move(source))
 {
 }
 
-OGLShader::OGLShader(GLuint gl_compute_program_id)
+OGLShader::OGLShader(GLuint gl_compute_program_id, std::string source)
     : AbstractShader(ShaderStage::Compute), m_id(ProgramShaderCache::GenerateShaderID()),
-      m_type(GL_COMPUTE_SHADER), m_gl_compute_program_id(gl_compute_program_id)
+      m_type(GL_COMPUTE_SHADER), m_gl_compute_program_id(gl_compute_program_id),
+      m_source(std::move(source))
 {
 }
 
@@ -47,22 +48,22 @@ OGLShader::~OGLShader()
 std::unique_ptr<OGLShader> OGLShader::CreateFromSource(ShaderStage stage, const char* source,
                                                        size_t length)
 {
+  std::string source_str(source, length);
   if (stage != ShaderStage::Compute)
   {
     GLenum shader_type = GetGLShaderTypeForStage(stage);
-    GLuint shader_id =
-        ProgramShaderCache::CompileSingleShader(shader_type, std::string(source, length));
+    GLuint shader_id = ProgramShaderCache::CompileSingleShader(shader_type, source_str);
     if (!shader_id)
       return nullptr;
 
-    return std::make_unique<OGLShader>(stage, shader_type, shader_id);
+    return std::make_unique<OGLShader>(stage, shader_type, shader_id, std::move(source_str));
   }
 
   // Compute shaders.
   SHADER prog;
-  if (!ProgramShaderCache::CompileComputeShader(prog, std::string(source, length)))
+  if (!ProgramShaderCache::CompileComputeShader(prog, source_str))
     return nullptr;
-  return std::make_unique<OGLShader>(prog.glprogid);
+  return std::make_unique<OGLShader>(prog.glprogid, std::move(source_str));
 }
 
 }  // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/OGLShader.h b/Source/Core/VideoBackends/OGL/OGLShader.h
index ad0432ada4..5289e1933f 100644
--- a/Source/Core/VideoBackends/OGL/OGLShader.h
+++ b/Source/Core/VideoBackends/OGL/OGLShader.h
@@ -16,14 +16,15 @@ namespace OGL
 class OGLShader final : public AbstractShader
 {
 public:
-  explicit OGLShader(ShaderStage stage, GLenum gl_type, GLuint gl_id);
-  explicit OGLShader(GLuint gl_compute_program_id);
+  explicit OGLShader(ShaderStage stage, GLenum gl_type, GLuint gl_id, std::string source);
+  explicit OGLShader(GLuint gl_compute_program_id, std::string source);
   ~OGLShader() override;
 
   u64 GetID() const { return m_id; }
   GLenum GetGLShaderType() const { return m_type; }
   GLuint GetGLShaderID() const { return m_gl_id; }
   GLuint GetGLComputeProgramID() const { return m_gl_compute_program_id; }
+  const std::string& GetSource() const { return m_source; }
 
   static std::unique_ptr<OGLShader> CreateFromSource(ShaderStage stage, const char* source,
                                                      size_t length);
@@ -33,6 +34,7 @@ private:
   GLenum m_type;
   GLuint m_gl_id = 0;
   GLuint m_gl_compute_program_id = 0;
+  std::string m_source;
 };
 
 }  // namespace OGL
diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
index 6afdfd05a9..85084979c3 100644
--- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
+++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp
@@ -291,7 +291,7 @@ bool ProgramShaderCache::CompileComputeShader(SHADER& shader, const std::string&
   // original shaders aren't needed any more
   glDeleteShader(shader_id);
 
-  if (!CheckProgramLinkResult(shader.glprogid, full_code, "", ""))
+  if (!CheckProgramLinkResult(shader.glprogid, &full_code, nullptr, nullptr))
   {
     shader.Destroy();
     return false;
@@ -374,8 +374,8 @@ bool ProgramShaderCache::CheckShaderCompileResult(GLuint id, GLenum type, const
   return true;
 }
 
-bool ProgramShaderCache::CheckProgramLinkResult(GLuint id, const std::string& vcode,
-                                                const std::string& pcode, const std::string& gcode)
+bool ProgramShaderCache::CheckProgramLinkResult(GLuint id, const std::string* vcode,
+                                                const std::string* pcode, const std::string* gcode)
 {
   GLint linkStatus;
   glGetProgramiv(id, GL_LINK_STATUS, &linkStatus);
@@ -393,9 +393,13 @@ bool ProgramShaderCache::CheckProgramLinkResult(GLuint id, const std::string& vc
           StringFromFormat("%sbad_p_%d.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
       std::ofstream file;
       File::OpenFStream(file, filename, std::ios_base::out);
-      file << s_glsl_header << vcode << s_glsl_header << pcode;
-      if (!gcode.empty())
-        file << s_glsl_header << gcode;
+      if (vcode)
+        file << s_glsl_header << *vcode << '\n';
+      if (gcode)
+        file << s_glsl_header << *gcode << '\n';
+      if (pcode)
+        file << s_glsl_header << *pcode << '\n';
+
       file << info_log;
       file.close();
 
@@ -573,7 +577,10 @@ PipelineProgram* ProgramShaderCache::GetPipelineProgram(const GLVertexFormat* ve
     if (!s_is_shared_context && vao != s_last_VAO)
       glBindVertexArray(s_last_VAO);
 
-    if (!ProgramShaderCache::CheckProgramLinkResult(prog->shader.glprogid, {}, {}, {}))
+    if (!ProgramShaderCache::CheckProgramLinkResult(
+            prog->shader.glprogid, vertex_shader ? &vertex_shader->GetSource() : nullptr,
+            geometry_shader ? &geometry_shader->GetSource() : nullptr,
+            pixel_shader ? &pixel_shader->GetSource() : nullptr))
     {
       prog->shader.Destroy();
       return nullptr;
diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.h b/Source/Core/VideoBackends/OGL/ProgramShaderCache.h
index 06cabcc689..4aeb40a6c9 100644
--- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.h
+++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.h
@@ -77,8 +77,8 @@ public:
   static bool CompileComputeShader(SHADER& shader, const std::string& code);
   static GLuint CompileSingleShader(GLenum type, const std::string& code);
   static bool CheckShaderCompileResult(GLuint id, GLenum type, const std::string& code);
-  static bool CheckProgramLinkResult(GLuint id, const std::string& vcode, const std::string& pcode,
-                                     const std::string& gcode);
+  static bool CheckProgramLinkResult(GLuint id, const std::string* vcode, const std::string* pcode,
+                                     const std::string* gcode);
   static StreamBuffer* GetUniformBuffer();
   static u32 GetUniformBufferAlignment();
   static void UploadConstants();