summaryrefslogtreecommitdiff
path: root/src/graphics/OGLShader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/graphics/OGLShader.cpp')
-rw-r--r--src/graphics/OGLShader.cpp206
1 files changed, 206 insertions, 0 deletions
diff --git a/src/graphics/OGLShader.cpp b/src/graphics/OGLShader.cpp
new file mode 100644
index 0000000..3abc40d
--- /dev/null
+++ b/src/graphics/OGLShader.cpp
@@ -0,0 +1,206 @@
+//
+// libavg - Media Playback Engine.
+// Copyright (C) 2003-2014 Ulrich von Zadow
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Current versions can be found at www.libavg.de
+//
+
+#include "OGLShader.h"
+#include "ShaderRegistry.h"
+
+#include "../base/Logger.h"
+#include "../base/Exception.h"
+#include "../base/OSHelper.h"
+
+#include "../graphics/VertexArray.h"
+
+#include <iostream>
+#include <sstream>
+
+using namespace std;
+
+namespace avg {
+
+OGLShader::OGLShader(const string& sName, const string& sVertProgram,
+ const string& sFragProgram, const string& sVertPrefix, const string& sFragPrefix)
+ : m_sName(sName),
+ m_sVertProgram(sVertProgram),
+ m_sFragProgram(sFragProgram)
+{
+ m_hProgram = glproc::CreateProgram();
+ if (sVertProgram == "") {
+ m_hVertexShader = 0;
+ } else {
+ glproc::BindAttribLocation(m_hProgram, VertexArray::TEX_INDEX, "a_TexCoord");
+ glproc::BindAttribLocation(m_hProgram, VertexArray::COLOR_INDEX, "a_Color");
+ glproc::BindAttribLocation(m_hProgram, VertexArray::POS_INDEX, "a_Pos");
+ m_hVertexShader = compileShader(GL_VERTEX_SHADER, sVertProgram, sVertPrefix);
+ glproc::AttachShader(m_hProgram, m_hVertexShader);
+ }
+ m_hFragmentShader = compileShader(GL_FRAGMENT_SHADER, sFragProgram, sFragPrefix);
+
+ glproc::AttachShader(m_hProgram, m_hFragmentShader);
+ glproc::LinkProgram(m_hProgram);
+ GLContext::checkError("OGLShader::OGLShader: glLinkProgram()");
+
+ GLint bLinked;
+ glproc::GetProgramiv(m_hProgram, GL_LINK_STATUS, &bLinked);
+ if (!bLinked) {
+ AVG_LOG_ERROR("Linking shader program '"+sName+"' failed. Aborting.");
+ dumpInfoLog(m_hVertexShader, Logger::severity::ERROR);
+ dumpInfoLog(m_hFragmentShader, Logger::severity::ERROR);
+ dumpInfoLog(m_hProgram, Logger::severity::ERROR, true);
+ exit(-1);
+ } else {
+ AVG_TRACE(Logger::category::SHADER, Logger::severity::INFO,
+ "Linking shader program '"+sName+"'.");
+ dumpInfoLog(m_hVertexShader, Logger::severity::INFO);
+ dumpInfoLog(m_hFragmentShader, Logger::severity::INFO);
+ dumpInfoLog(m_hProgram, Logger::severity::INFO, true);
+ }
+ m_pShaderRegistry = &*ShaderRegistry::get();
+ if (m_hVertexShader) {
+ m_pTransformParam = getParam<glm::mat4>("transform");
+ }
+}
+
+OGLShader::~OGLShader()
+{
+}
+
+bool isMountainLion()
+{
+#ifdef __APPLE__
+ return getOSXMajorVersion() >= 12;
+#else
+ return false;
+#endif
+}
+
+void OGLShader::activate()
+{
+ // If we're running on OS X mountain lion, we need to disable shader activation
+ // caching (See bug #355).
+ OGLShaderPtr pCurShader = m_pShaderRegistry->getCurShader();
+ if (isMountainLion() || !pCurShader || &*pCurShader != this) {
+ glproc::UseProgram(m_hProgram);
+ m_pShaderRegistry->setCurShader(m_sName);
+ GLContext::checkError("OGLShader::activate: glUseProgram()");
+ }
+}
+
+GLuint OGLShader::getProgram()
+{
+ return m_hProgram;
+}
+
+const std::string OGLShader::getName() const
+{
+ return m_sName;
+}
+
+void OGLShader::setTransform(const glm::mat4& transform)
+{
+ if (m_hVertexShader) {
+ m_pTransformParam->set(transform);
+ } else {
+#ifdef AVG_ENABLE_EGL
+ // No fixed-function vertex shader in gles
+ AVG_ASSERT(false);
+#else
+ glLoadMatrixf(glm::value_ptr(transform));
+#endif
+ }
+}
+
+GLuint OGLShader::compileShader(GLenum shaderType, const std::string& sProgram,
+ const std::string& sPrefix)
+{
+ const char * pProgramStrs[2];
+ pProgramStrs[0] = sPrefix.c_str();
+ pProgramStrs[1] = sProgram.c_str();
+ GLuint hShader = glproc::CreateShader(shaderType);
+ glproc::ShaderSource(hShader, 2, pProgramStrs, 0);
+ glproc::CompileShader(hShader);
+ GLContext::checkError("OGLShader::compileShader()");
+ return hShader;
+}
+
+bool OGLShader::findParam(const std::string& sName, unsigned& pos)
+{
+ GLShaderParamPtr pParam;
+ bool bFound = false;
+ pos = 0;
+ while (!bFound && pos<m_pParams.size() && m_pParams[pos]->getName() <= sName) {
+ if (m_pParams[pos]->getName() == sName) {
+ bFound = true;
+ } else {
+ ++pos;
+ }
+ }
+ return bFound;
+}
+
+void OGLShader::dumpInfoLog(GLuint hObj, long level, bool bIsProgram)
+{
+ int infoLogLength;
+ GLchar * pInfoLog;
+
+ if (!hObj) {
+ return;
+ }
+
+ if (bIsProgram) {
+ glproc::GetProgramiv(hObj, GL_INFO_LOG_LENGTH, &infoLogLength);
+ } else {
+ glproc::GetShaderiv(hObj, GL_INFO_LOG_LENGTH, &infoLogLength);
+ }
+ GLContext::checkError("OGLShader::dumpInfoLog: glGetShaderiv()");
+ if (infoLogLength > 1) {
+ pInfoLog = (GLchar*)malloc(infoLogLength);
+ int charsWritten;
+ if (bIsProgram) {
+ glproc::GetProgramInfoLog(hObj, infoLogLength, &charsWritten, pInfoLog);
+ } else {
+ glproc::GetShaderInfoLog(hObj, infoLogLength, &charsWritten, pInfoLog);
+ }
+ string sLog = removeATIInfoLogSpam(pInfoLog);
+ GLContext::checkError("OGLShader::dumpInfoLog: glGetShaderInfoLog()");
+ if (sLog.size() > 3) {
+ AVG_TRACE(Logger::category::SHADER, level, sLog);
+ }
+ free(pInfoLog);
+ }
+}
+
+string OGLShader::removeATIInfoLogSpam(const string& sOrigLog)
+{
+ istringstream stream(sOrigLog);
+ string sLog;
+ string sCurLine;
+ while(getline(stream, sCurLine)) {
+ bool bLineBroken = (sCurLine.find(
+ "shader was successfully compiled to run on hardware.") != string::npos)
+ || (sCurLine.find("shader(s) linked.") != string::npos);
+ if (!bLineBroken) {
+ sLog.append(sCurLine+"\n");
+ }
+ }
+ return sLog;
+}
+
+}