summaryrefslogtreecommitdiffstats
path: root/xbmc/guilib/Shader.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:22 +0000
commitc04dcc2e7d834218ef2d4194331e383402495ae1 (patch)
tree7333e38d10d75386e60f336b80c2443c1166031d /xbmc/guilib/Shader.cpp
parentInitial commit. (diff)
downloadkodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz
kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xbmc/guilib/Shader.cpp')
-rw-r--r--xbmc/guilib/Shader.cpp384
1 files changed, 384 insertions, 0 deletions
diff --git a/xbmc/guilib/Shader.cpp b/xbmc/guilib/Shader.cpp
new file mode 100644
index 0000000..37aedcf
--- /dev/null
+++ b/xbmc/guilib/Shader.cpp
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "Shader.h"
+
+#include "ServiceBroker.h"
+#include "filesystem/File.h"
+#include "rendering/RenderSystem.h"
+#include "utils/GLUtils.h"
+#include "utils/StringUtils.h"
+#include "utils/log.h"
+
+#ifdef HAS_GLES
+#define GLchar char
+#endif
+
+#define LOG_SIZE 1024
+
+using namespace Shaders;
+using namespace XFILE;
+
+//////////////////////////////////////////////////////////////////////
+// CShader
+//////////////////////////////////////////////////////////////////////
+bool CShader::LoadSource(const std::string& filename, const std::string& prefix)
+{
+ if(filename.empty())
+ return true;
+
+ CFileStream file;
+
+ std::string path = "special://xbmc/system/shaders/";
+ path += CServiceBroker::GetRenderSystem()->GetShaderPath(filename);
+ path += filename;
+ if(!file.Open(path))
+ {
+ CLog::Log(LOGERROR, "CYUVShaderGLSL::CYUVShaderGLSL - failed to open file {}", filename);
+ return false;
+ }
+ getline(file, m_source, '\0');
+
+ size_t pos = 0;
+ size_t versionPos = m_source.find("#version");
+ if (versionPos != std::string::npos)
+ {
+ versionPos = m_source.find('\n', versionPos);
+ if (versionPos != std::string::npos)
+ pos = versionPos + 1;
+ }
+ m_source.insert(pos, prefix);
+
+ m_filenames = filename;
+
+ return true;
+}
+
+bool CShader::AppendSource(const std::string& filename)
+{
+ if(filename.empty())
+ return true;
+
+ CFileStream file;
+ std::string temp;
+
+ std::string path = "special://xbmc/system/shaders/";
+ path += CServiceBroker::GetRenderSystem()->GetShaderPath(filename);
+ path += filename;
+ if(!file.Open(path))
+ {
+ CLog::Log(LOGERROR, "CShader::AppendSource - failed to open file {}", filename);
+ return false;
+ }
+ getline(file, temp, '\0');
+ m_source.append(temp);
+
+ m_filenames.append(" " + filename);
+
+ return true;
+}
+
+bool CShader::InsertSource(const std::string& filename, const std::string& loc)
+{
+ if(filename.empty())
+ return true;
+
+ CFileStream file;
+ std::string temp;
+
+ std::string path = "special://xbmc/system/shaders/";
+ path += CServiceBroker::GetRenderSystem()->GetShaderPath(filename);
+ path += filename;
+ if(!file.Open(path))
+ {
+ CLog::Log(LOGERROR, "CShader::InsertSource - failed to open file {}", filename);
+ return false;
+ }
+ getline(file, temp, '\0');
+
+ size_t locPos = m_source.find(loc);
+ if (locPos == std::string::npos)
+ {
+ CLog::Log(LOGERROR, "CShader::InsertSource - could not find location {}", loc);
+ return false;
+ }
+
+ m_source.insert(locPos, temp);
+
+ m_filenames.append(" " + filename);
+
+ return true;
+}
+
+std::string CShader::GetSourceWithLineNumbers() const
+{
+ int i{1};
+ auto lines = StringUtils::Split(m_source, "\n");
+ for (auto& line : lines)
+ {
+ line.insert(0, StringUtils::Format("{:3}: ", i));
+ i++;
+ }
+
+ auto output = StringUtils::Join(lines, "\n");
+
+ return output;
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// CGLSLVertexShader
+//////////////////////////////////////////////////////////////////////
+
+bool CGLSLVertexShader::Compile()
+{
+ GLint params[4];
+
+ Free();
+
+ m_vertexShader = glCreateShader(GL_VERTEX_SHADER);
+ const char *ptr = m_source.c_str();
+ glShaderSource(m_vertexShader, 1, &ptr, 0);
+ glCompileShader(m_vertexShader);
+ glGetShaderiv(m_vertexShader, GL_COMPILE_STATUS, params);
+ VerifyGLState();
+ if (params[0] != GL_TRUE)
+ {
+ GLchar log[LOG_SIZE];
+ CLog::Log(LOGERROR, "GL: Error compiling vertex shader");
+ glGetShaderInfoLog(m_vertexShader, LOG_SIZE, NULL, log);
+ CLog::Log(LOGERROR, "{}", log);
+ m_lastLog = log;
+ m_compiled = false;
+ }
+ else
+ {
+ GLchar log[LOG_SIZE];
+ GLsizei length;
+ glGetShaderInfoLog(m_vertexShader, LOG_SIZE, &length, log);
+ if (length > 0)
+ {
+ CLog::Log(LOGDEBUG, "GL: Vertex Shader compilation log:");
+ CLog::Log(LOGDEBUG, "{}", log);
+ }
+ m_lastLog = log;
+ m_compiled = true;
+ }
+ return m_compiled;
+}
+
+void CGLSLVertexShader::Free()
+{
+ if (m_vertexShader)
+ glDeleteShader(m_vertexShader);
+ m_vertexShader = 0;
+}
+
+//////////////////////////////////////////////////////////////////////
+// CGLSLPixelShader
+//////////////////////////////////////////////////////////////////////
+bool CGLSLPixelShader::Compile()
+{
+ GLint params[4];
+
+ Free();
+
+ // Pixel shaders are not mandatory.
+ if (m_source.length()==0)
+ {
+ CLog::Log(LOGINFO, "GL: No pixel shader, fixed pipeline in use");
+ return true;
+ }
+
+ m_pixelShader = glCreateShader(GL_FRAGMENT_SHADER);
+ const char *ptr = m_source.c_str();
+ glShaderSource(m_pixelShader, 1, &ptr, 0);
+ glCompileShader(m_pixelShader);
+ glGetShaderiv(m_pixelShader, GL_COMPILE_STATUS, params);
+ if (params[0] != GL_TRUE)
+ {
+ GLchar log[LOG_SIZE];
+ CLog::Log(LOGERROR, "GL: Error compiling pixel shader");
+ glGetShaderInfoLog(m_pixelShader, LOG_SIZE, NULL, log);
+ CLog::Log(LOGERROR, "{}", log);
+ m_lastLog = log;
+ m_compiled = false;
+ }
+ else
+ {
+ GLchar log[LOG_SIZE];
+ GLsizei length;
+ glGetShaderInfoLog(m_pixelShader, LOG_SIZE, &length, log);
+ if (length > 0)
+ {
+ CLog::Log(LOGDEBUG, "GL: Pixel Shader compilation log:");
+ CLog::Log(LOGDEBUG, "{}", log);
+ }
+ m_lastLog = log;
+ m_compiled = true;
+ }
+ return m_compiled;
+}
+
+void CGLSLPixelShader::Free()
+{
+ if (m_pixelShader)
+ glDeleteShader(m_pixelShader);
+ m_pixelShader = 0;
+}
+
+//////////////////////////////////////////////////////////////////////
+// CGLSLShaderProgram
+//////////////////////////////////////////////////////////////////////
+CGLSLShaderProgram::CGLSLShaderProgram()
+{
+ m_pFP = new CGLSLPixelShader();
+ m_pVP = new CGLSLVertexShader();
+}
+
+CGLSLShaderProgram::CGLSLShaderProgram(const std::string& vert,
+ const std::string& frag)
+{
+ m_pFP = new CGLSLPixelShader();
+ m_pFP->LoadSource(frag);
+ m_pVP = new CGLSLVertexShader();
+ m_pVP->LoadSource(vert);
+}
+
+CGLSLShaderProgram::~CGLSLShaderProgram()
+{
+ Free();
+}
+
+void CGLSLShaderProgram::Free()
+{
+ m_pVP->Free();
+ VerifyGLState();
+ m_pFP->Free();
+ VerifyGLState();
+ if (m_shaderProgram)
+ {
+ glDeleteProgram(m_shaderProgram);
+ }
+ m_shaderProgram = 0;
+ m_ok = false;
+ m_lastProgram = 0;
+}
+
+bool CGLSLShaderProgram::CompileAndLink()
+{
+ GLint params[4];
+
+ // free resources
+ Free();
+
+ // compiled vertex shader
+ if (!m_pVP->Compile())
+ {
+ CLog::Log(LOGERROR, "GL: Error compiling vertex shader: {}", m_pVP->GetName());
+ CLog::Log(LOGDEBUG, "GL: vertex shader source:\n{}", m_pVP->GetSourceWithLineNumbers());
+ return false;
+ }
+
+ // compile pixel shader
+ if (!m_pFP->Compile())
+ {
+ m_pVP->Free();
+ CLog::Log(LOGERROR, "GL: Error compiling fragment shader: {}", m_pFP->GetName());
+ CLog::Log(LOGDEBUG, "GL: fragment shader source:\n{}", m_pFP->GetSourceWithLineNumbers());
+ return false;
+ }
+
+ // create program object
+ if (!(m_shaderProgram = glCreateProgram()))
+ {
+ CLog::Log(LOGERROR, "GL: Error creating shader program handle");
+ goto error;
+ }
+
+ // attach the vertex shader
+ glAttachShader(m_shaderProgram, m_pVP->Handle());
+ VerifyGLState();
+
+ // if we have a pixel shader, attach it. If not, fixed pipeline
+ // will be used.
+ if (m_pFP->Handle())
+ {
+ glAttachShader(m_shaderProgram, m_pFP->Handle());
+ VerifyGLState();
+ }
+
+ // link the program
+ glLinkProgram(m_shaderProgram);
+ glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, params);
+ if (params[0]!=GL_TRUE)
+ {
+ GLchar log[LOG_SIZE];
+ CLog::Log(LOGERROR, "GL: Error linking shader");
+ glGetProgramInfoLog(m_shaderProgram, LOG_SIZE, NULL, log);
+ CLog::Log(LOGERROR, "{}", log);
+ goto error;
+ }
+ VerifyGLState();
+
+ m_validated = false;
+ m_ok = true;
+ OnCompiledAndLinked();
+ VerifyGLState();
+ return true;
+
+ error:
+ m_ok = false;
+ Free();
+ return false;
+}
+
+bool CGLSLShaderProgram::Enable()
+{
+ if (OK())
+ {
+ glUseProgram(m_shaderProgram);
+ if (OnEnabled())
+ {
+ if (!m_validated)
+ {
+ // validate the program
+ GLint params[4];
+ glValidateProgram(m_shaderProgram);
+ glGetProgramiv(m_shaderProgram, GL_VALIDATE_STATUS, params);
+ if (params[0]!=GL_TRUE)
+ {
+ GLchar log[LOG_SIZE];
+ CLog::Log(LOGERROR, "GL: Error validating shader");
+ glGetProgramInfoLog(m_shaderProgram, LOG_SIZE, NULL, log);
+ CLog::Log(LOGERROR, "{}", log);
+ }
+ m_validated = true;
+ }
+ VerifyGLState();
+ return true;
+ }
+ else
+ {
+ glUseProgram(0);
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+void CGLSLShaderProgram::Disable()
+{
+ if (OK())
+ {
+ glUseProgram(0);
+ OnDisabled();
+ }
+}
+