From fe88375ff376cbb0d940c96ac6ec1667be4acab0 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 20 Dec 2015 05:42:54 +0100 Subject: OPENGL: Support GLES2 contexts. --- backends/graphics/opengl/shader.cpp | 176 ++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 backends/graphics/opengl/shader.cpp (limited to 'backends/graphics/opengl/shader.cpp') diff --git a/backends/graphics/opengl/shader.cpp b/backends/graphics/opengl/shader.cpp new file mode 100644 index 0000000000..6e36307860 --- /dev/null +++ b/backends/graphics/opengl/shader.cpp @@ -0,0 +1,176 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "backends/graphics/opengl/shader.h" + +#if !USE_FORCED_GL && !USE_FORCED_GLES + +#include "common/textconsole.h" + +namespace OpenGL { + +const char *const g_defaultVertexShader = + "attribute vec4 position;\n" + "attribute vec2 texCoordIn;\n" + "attribute vec4 blendColorIn;\n" + "\n" + "uniform mat4 projection;\n" + "\n" + "varying vec2 texCoord;\n" + "varying vec4 blendColor;\n" + "\n" + "void main(void) {\n" + "\ttexCoord = texCoordIn;\n" + "\tblendColor = blendColorIn;\n" + "\tgl_Position = projection * position;\n" + "}\n"; + +const char *const g_defaultFragmentShader = + "varying lowp vec2 texCoord;\n" + "varying lowp vec4 blendColor;\n" + "\n" + "uniform sampler2D texture;\n" + "\n" + "void main(void) {\n" + "\tgl_FragColor = blendColor * texture2D(texture, texCoord);\n" + "}\n"; + +Shader::Shader(const Common::String &vertex, const Common::String &fragment) + : _vertex(vertex), _fragment(fragment), _program(0), _projectionLocation(-1), _textureLocation(-1) { +} + +void Shader::destroy() { + GL_CALL(glDeleteProgram(_program)); + _program = 0; +} + +bool Shader::recreate() { + // Make sure any old programs are destroyed properly. + destroy(); + + GLuint vertexShader = compileShader(_vertex.c_str(), GL_VERTEX_SHADER); + if (!vertexShader) { + return false; + } + + GLuint fragmentShader = compileShader(_fragment.c_str(), GL_FRAGMENT_SHADER); + if (!fragmentShader) { + GL_CALL(glDeleteShader(vertexShader)); + return false; + } + + GL_ASSIGN(_program, glCreateProgram()); + if (!_program) { + GL_CALL(glDeleteShader(vertexShader)); + GL_CALL(glDeleteShader(fragmentShader)); + return false; + } + + GL_CALL(glAttachShader(_program, vertexShader)); + GL_CALL(glAttachShader(_program, fragmentShader)); + + GL_CALL(glBindAttribLocation(_program, kPositionAttribLocation, "position")); + GL_CALL(glBindAttribLocation(_program, kTexCoordAttribLocation, "texCoordIn")); + GL_CALL(glBindAttribLocation(_program, kColorAttribLocation, "blendColorIn")); + + GL_CALL(glLinkProgram(_program)); + + GL_CALL(glDetachShader(_program, fragmentShader)); + GL_CALL(glDeleteShader(fragmentShader)); + + GL_CALL(glDetachShader(_program, vertexShader)); + GL_CALL(glDeleteShader(vertexShader)); + + GLint result; + GL_CALL(glGetProgramiv(_program, GL_LINK_STATUS, &result)); + if (result == GL_FALSE) { + GLint logSize; + GL_CALL(glGetProgramiv(_program, GL_INFO_LOG_LENGTH, &logSize)); + + GLchar *log = new GLchar[logSize]; + GL_CALL(glGetProgramInfoLog(_program, logSize, nullptr, log)); + warning("Could not link shader: \"%s\"", log); + delete[] log; + + destroy(); + return false; + } + + GL_ASSIGN(_projectionLocation, glGetUniformLocation(_program, "projection")); + if (_projectionLocation == -1) { + warning("Shader misses \"projection\" uniform."); + destroy(); + return false; + } + + GL_ASSIGN(_textureLocation, glGetUniformLocation(_program, "texture")); + if (_textureLocation == -1) { + warning("Shader misses \"texture\" uniform."); + destroy(); + return false; + } + + return true; +} + +void Shader::activate(const GLfloat *projectionMatrix) { + // Activate program. + GL_CALL(glUseProgram(_program)); + + // Set projection matrix. + GL_CALL(glUniformMatrix4fv(_projectionLocation, 1, GL_FALSE, projectionMatrix)); + + // We always use texture unit 0. + GL_CALL(glUniform1i(_textureLocation, 0)); +} + +GLuint Shader::compileShader(const char *source, GLenum shaderType) { + GLuint handle; + GL_ASSIGN(handle, glCreateShader(shaderType)); + if (!handle) { + return 0; + } + + GL_CALL(glShaderSource(handle, 1, &source, nullptr)); + GL_CALL(glCompileShader(handle)); + + GLint result; + GL_CALL(glGetShaderiv(handle, GL_COMPILE_STATUS, &result)); + if (result == GL_FALSE) { + GLint logSize; + GL_CALL(glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &logSize)); + + GLchar *log = new GLchar[logSize]; + GL_CALL(glGetShaderInfoLog(handle, logSize, nullptr, log)); + warning("Could not compile shader \"%s\": \"%s\"", source, log); + delete[] log; + + GL_CALL(glDeleteShader(handle)); + return 0; + } + + return handle; +} + +} // End of namespace OpenGL + +#endif // !USE_FORCED_GL && !USE_FORCED_GLES -- cgit v1.2.3 From fee1aa550203c3f46ff19afbe19a7baa4771a5cd Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 20 Dec 2015 09:30:11 +0100 Subject: OPENGL: Add support for shaders with GL contexts. --- backends/graphics/opengl/shader.cpp | 162 ++++++++++++++++++++++++++++++++++-- 1 file changed, 153 insertions(+), 9 deletions(-) (limited to 'backends/graphics/opengl/shader.cpp') diff --git a/backends/graphics/opengl/shader.cpp b/backends/graphics/opengl/shader.cpp index 6e36307860..c28036cb4e 100644 --- a/backends/graphics/opengl/shader.cpp +++ b/backends/graphics/opengl/shader.cpp @@ -22,7 +22,7 @@ #include "backends/graphics/opengl/shader.h" -#if !USE_FORCED_GL && !USE_FORCED_GLES +#if !USE_FORCED_GLES #include "common/textconsole.h" @@ -44,7 +44,20 @@ const char *const g_defaultVertexShader = "\tgl_Position = projection * position;\n" "}\n"; -const char *const g_defaultFragmentShader = +#if !USE_FORCED_GLES2 +const char *const g_defaultFragmentShaderGL = + "varying vec2 texCoord;\n" + "varying vec4 blendColor;\n" + "\n" + "uniform sampler2D texture;\n" + "\n" + "void main(void) {\n" + "\tgl_FragColor = blendColor * texture2D(texture, texCoord);\n" + "}\n"; +#endif + +#if !USE_FORCED_GL +const char *const g_defaultFragmentShaderGLES2 = "varying lowp vec2 texCoord;\n" "varying lowp vec4 blendColor;\n" "\n" @@ -53,17 +66,146 @@ const char *const g_defaultFragmentShader = "void main(void) {\n" "\tgl_FragColor = blendColor * texture2D(texture, texCoord);\n" "}\n"; +#endif + +#if !USE_FORCED_GLES2 + +ShaderARB::ShaderARB(const Common::String &vertex, const Common::String &fragment) + : Shader(vertex, fragment), _program(0), _projectionLocation(-1), _textureLocation(-1) { +} -Shader::Shader(const Common::String &vertex, const Common::String &fragment) - : _vertex(vertex), _fragment(fragment), _program(0), _projectionLocation(-1), _textureLocation(-1) { +void ShaderARB::destroy() { + // According to extension specification glDeleteObjectARB silently ignores + // 0. However, with nVidia drivers this can cause GL_INVALID_VALUE, thus + // we do not call it with 0 as parameter to avoid warnings. + if (_program) { + GL_CALL(glDeleteObjectARB(_program)); + } + _program = 0; } -void Shader::destroy() { +bool ShaderARB::recreate() { + // Make sure any old programs are destroyed properly. + destroy(); + + GLhandleARB vertexShader = compileShader(_vertex.c_str(), GL_VERTEX_SHADER_ARB); + if (!vertexShader) { + return false; + } + + GLhandleARB fragmentShader = compileShader(_fragment.c_str(), GL_FRAGMENT_SHADER_ARB); + if (!fragmentShader) { + GL_CALL(glDeleteObjectARB(vertexShader)); + return false; + } + + GL_ASSIGN(_program, glCreateProgramObjectARB()); + if (!_program) { + GL_CALL(glDeleteObjectARB(vertexShader)); + GL_CALL(glDeleteObjectARB(fragmentShader)); + return false; + } + + GL_CALL(glAttachObjectARB(_program, vertexShader)); + GL_CALL(glAttachObjectARB(_program, fragmentShader)); + + GL_CALL(glBindAttribLocationARB(_program, kPositionAttribLocation, "position")); + GL_CALL(glBindAttribLocationARB(_program, kTexCoordAttribLocation, "texCoordIn")); + GL_CALL(glBindAttribLocationARB(_program, kColorAttribLocation, "blendColorIn")); + + GL_CALL(glLinkProgramARB(_program)); + + GL_CALL(glDetachObjectARB(_program, fragmentShader)); + GL_CALL(glDeleteObjectARB(fragmentShader)); + + GL_CALL(glDetachObjectARB(_program, vertexShader)); + GL_CALL(glDeleteObjectARB(vertexShader)); + + GLint result; + GL_CALL(glGetObjectParameterivARB(_program, GL_OBJECT_LINK_STATUS_ARB, &result)); + if (result == GL_FALSE) { + GLint logSize; + GL_CALL(glGetObjectParameterivARB(_program, GL_OBJECT_INFO_LOG_LENGTH_ARB, &logSize)); + + GLchar *log = new GLchar[logSize]; + GL_CALL(glGetInfoLogARB(_program, logSize, nullptr, log)); + warning("Could not link shader: \"%s\"", log); + delete[] log; + + destroy(); + return false; + } + + GL_ASSIGN(_projectionLocation, glGetUniformLocationARB(_program, "projection")); + if (_projectionLocation == -1) { + warning("Shader misses \"projection\" uniform."); + destroy(); + return false; + } + + GL_ASSIGN(_textureLocation, glGetUniformLocationARB(_program, "texture")); + if (_textureLocation == -1) { + warning("Shader misses \"texture\" uniform."); + destroy(); + return false; + } + + return true; +} + +void ShaderARB::activate(const GLfloat *projectionMatrix) { + // Activate program. + GL_CALL(glUseProgramObjectARB(_program)); + + // Set projection matrix. + GL_CALL(glUniformMatrix4fvARB(_projectionLocation, 1, GL_FALSE, projectionMatrix)); + + // We always use texture unit 0. + GL_CALL(glUniform1iARB(_textureLocation, 0)); +} + +GLhandleARB ShaderARB::compileShader(const char *source, GLenum shaderType) { + GLuint handle; + GL_ASSIGN(handle, glCreateShaderObjectARB(shaderType)); + if (!handle) { + return 0; + } + + GL_CALL(glShaderSourceARB(handle, 1, &source, nullptr)); + GL_CALL(glCompileShaderARB(handle)); + + GLint result; + GL_CALL(glGetObjectParameterivARB(handle, GL_OBJECT_COMPILE_STATUS_ARB, &result)); + if (result == GL_FALSE) { + GLint logSize; + GL_CALL(glGetObjectParameterivARB(handle, GL_OBJECT_INFO_LOG_LENGTH_ARB, &logSize)); + + GLchar *log = new GLchar[logSize]; + GL_CALL(glGetInfoLogARB(handle, logSize, nullptr, log)); + warning("Could not compile shader \"%s\": \"%s\"", source, log); + delete[] log; + + GL_CALL(glDeleteObjectARB(handle)); + return 0; + } + + return handle; +} + +#endif // !USE_FORCED_GLES2 + +#if !USE_FORCED_GL + +ShaderGLES2::ShaderGLES2(const Common::String &vertex, const Common::String &fragment) + : Shader(vertex, fragment), _program(0), _projectionLocation(-1), _textureLocation(-1) { +} + +void ShaderGLES2::destroy() { GL_CALL(glDeleteProgram(_program)); _program = 0; } -bool Shader::recreate() { +bool ShaderGLES2::recreate() { // Make sure any old programs are destroyed properly. destroy(); @@ -132,7 +274,7 @@ bool Shader::recreate() { return true; } -void Shader::activate(const GLfloat *projectionMatrix) { +void ShaderGLES2::activate(const GLfloat *projectionMatrix) { // Activate program. GL_CALL(glUseProgram(_program)); @@ -143,7 +285,7 @@ void Shader::activate(const GLfloat *projectionMatrix) { GL_CALL(glUniform1i(_textureLocation, 0)); } -GLuint Shader::compileShader(const char *source, GLenum shaderType) { +GLuint ShaderGLES2::compileShader(const char *source, GLenum shaderType) { GLuint handle; GL_ASSIGN(handle, glCreateShader(shaderType)); if (!handle) { @@ -171,6 +313,8 @@ GLuint Shader::compileShader(const char *source, GLenum shaderType) { return handle; } +#endif // !!USE_FORCED_GL + } // End of namespace OpenGL -#endif // !USE_FORCED_GL && !USE_FORCED_GLES +#endif // !USE_FORCED_GLES -- cgit v1.2.3 From d029f167996f3328ac278829802d9c1a32c620e2 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 20 Dec 2015 09:50:55 +0100 Subject: OPENGL: Handle destruction gracefully when no context is setup. --- backends/graphics/opengl/shader.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'backends/graphics/opengl/shader.cpp') diff --git a/backends/graphics/opengl/shader.cpp b/backends/graphics/opengl/shader.cpp index c28036cb4e..d7fc20574b 100644 --- a/backends/graphics/opengl/shader.cpp +++ b/backends/graphics/opengl/shader.cpp @@ -74,6 +74,15 @@ ShaderARB::ShaderARB(const Common::String &vertex, const Common::String &fragmen : Shader(vertex, fragment), _program(0), _projectionLocation(-1), _textureLocation(-1) { } +ShaderARB::~ShaderARB() { + // According to extension specification glDeleteObjectARB silently ignores + // 0. However, with nVidia drivers this can cause GL_INVALID_VALUE, thus + // we do not call it with 0 as parameter to avoid warnings. + if (_program) { + GL_CALL_SAFE(glDeleteObjectARB, (_program)); + } +} + void ShaderARB::destroy() { // According to extension specification glDeleteObjectARB silently ignores // 0. However, with nVidia drivers this can cause GL_INVALID_VALUE, thus @@ -200,6 +209,10 @@ ShaderGLES2::ShaderGLES2(const Common::String &vertex, const Common::String &fra : Shader(vertex, fragment), _program(0), _projectionLocation(-1), _textureLocation(-1) { } +ShaderGLES2::~ShaderGLES2() { + GL_CALL_SAFE(glDeleteProgram, (_program)); +} + void ShaderGLES2::destroy() { GL_CALL(glDeleteProgram(_program)); _program = 0; -- cgit v1.2.3 From fc52f730506422ac99e44cd74f229e6a0c5c2121 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Mon, 21 Dec 2015 05:47:29 +0100 Subject: OPENGL: Slightly cleanup programmable pipeline handling. --- backends/graphics/opengl/shader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'backends/graphics/opengl/shader.cpp') diff --git a/backends/graphics/opengl/shader.cpp b/backends/graphics/opengl/shader.cpp index d7fc20574b..7fdebed493 100644 --- a/backends/graphics/opengl/shader.cpp +++ b/backends/graphics/opengl/shader.cpp @@ -167,10 +167,10 @@ void ShaderARB::activate(const GLfloat *projectionMatrix) { GL_CALL(glUseProgramObjectARB(_program)); // Set projection matrix. - GL_CALL(glUniformMatrix4fvARB(_projectionLocation, 1, GL_FALSE, projectionMatrix)); + GL_CALL(glUniformMatrix4fv(_projectionLocation, 1, GL_FALSE, projectionMatrix)); // We always use texture unit 0. - GL_CALL(glUniform1iARB(_textureLocation, 0)); + GL_CALL(glUniform1i(_textureLocation, 0)); } GLhandleARB ShaderARB::compileShader(const char *source, GLenum shaderType) { -- cgit v1.2.3 From 8a3eecb73a9eb5d885e3585835db6bee738c1de5 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Mon, 21 Dec 2015 06:35:13 +0100 Subject: OPENGL: Unify shader implementation for GL and GLES2. --- backends/graphics/opengl/shader.cpp | 155 +++--------------------------------- 1 file changed, 13 insertions(+), 142 deletions(-) (limited to 'backends/graphics/opengl/shader.cpp') diff --git a/backends/graphics/opengl/shader.cpp b/backends/graphics/opengl/shader.cpp index 7fdebed493..9e106a81b8 100644 --- a/backends/graphics/opengl/shader.cpp +++ b/backends/graphics/opengl/shader.cpp @@ -68,166 +68,39 @@ const char *const g_defaultFragmentShaderGLES2 = "}\n"; #endif -#if !USE_FORCED_GLES2 - -ShaderARB::ShaderARB(const Common::String &vertex, const Common::String &fragment) - : Shader(vertex, fragment), _program(0), _projectionLocation(-1), _textureLocation(-1) { +Shader::Shader(const Common::String &vertex, const Common::String &fragment) + : _vertex(vertex), _fragment(fragment), _program(0), _projectionLocation(-1), _textureLocation(-1) { } -ShaderARB::~ShaderARB() { +Shader::~Shader() { // According to extension specification glDeleteObjectARB silently ignores // 0. However, with nVidia drivers this can cause GL_INVALID_VALUE, thus // we do not call it with 0 as parameter to avoid warnings. if (_program) { - GL_CALL_SAFE(glDeleteObjectARB, (_program)); + GL_CALL_SAFE(glDeleteProgram, (_program)); } } -void ShaderARB::destroy() { +void Shader::destroy() { // According to extension specification glDeleteObjectARB silently ignores // 0. However, with nVidia drivers this can cause GL_INVALID_VALUE, thus // we do not call it with 0 as parameter to avoid warnings. if (_program) { - GL_CALL(glDeleteObjectARB(_program)); + GL_CALL(glDeleteProgram(_program)); + _program = 0; } - _program = 0; } -bool ShaderARB::recreate() { +bool Shader::recreate() { // Make sure any old programs are destroyed properly. destroy(); - GLhandleARB vertexShader = compileShader(_vertex.c_str(), GL_VERTEX_SHADER_ARB); + GLshader vertexShader = compileShader(_vertex.c_str(), GL_VERTEX_SHADER); if (!vertexShader) { return false; } - GLhandleARB fragmentShader = compileShader(_fragment.c_str(), GL_FRAGMENT_SHADER_ARB); - if (!fragmentShader) { - GL_CALL(glDeleteObjectARB(vertexShader)); - return false; - } - - GL_ASSIGN(_program, glCreateProgramObjectARB()); - if (!_program) { - GL_CALL(glDeleteObjectARB(vertexShader)); - GL_CALL(glDeleteObjectARB(fragmentShader)); - return false; - } - - GL_CALL(glAttachObjectARB(_program, vertexShader)); - GL_CALL(glAttachObjectARB(_program, fragmentShader)); - - GL_CALL(glBindAttribLocationARB(_program, kPositionAttribLocation, "position")); - GL_CALL(glBindAttribLocationARB(_program, kTexCoordAttribLocation, "texCoordIn")); - GL_CALL(glBindAttribLocationARB(_program, kColorAttribLocation, "blendColorIn")); - - GL_CALL(glLinkProgramARB(_program)); - - GL_CALL(glDetachObjectARB(_program, fragmentShader)); - GL_CALL(glDeleteObjectARB(fragmentShader)); - - GL_CALL(glDetachObjectARB(_program, vertexShader)); - GL_CALL(glDeleteObjectARB(vertexShader)); - - GLint result; - GL_CALL(glGetObjectParameterivARB(_program, GL_OBJECT_LINK_STATUS_ARB, &result)); - if (result == GL_FALSE) { - GLint logSize; - GL_CALL(glGetObjectParameterivARB(_program, GL_OBJECT_INFO_LOG_LENGTH_ARB, &logSize)); - - GLchar *log = new GLchar[logSize]; - GL_CALL(glGetInfoLogARB(_program, logSize, nullptr, log)); - warning("Could not link shader: \"%s\"", log); - delete[] log; - - destroy(); - return false; - } - - GL_ASSIGN(_projectionLocation, glGetUniformLocationARB(_program, "projection")); - if (_projectionLocation == -1) { - warning("Shader misses \"projection\" uniform."); - destroy(); - return false; - } - - GL_ASSIGN(_textureLocation, glGetUniformLocationARB(_program, "texture")); - if (_textureLocation == -1) { - warning("Shader misses \"texture\" uniform."); - destroy(); - return false; - } - - return true; -} - -void ShaderARB::activate(const GLfloat *projectionMatrix) { - // Activate program. - GL_CALL(glUseProgramObjectARB(_program)); - - // Set projection matrix. - GL_CALL(glUniformMatrix4fv(_projectionLocation, 1, GL_FALSE, projectionMatrix)); - - // We always use texture unit 0. - GL_CALL(glUniform1i(_textureLocation, 0)); -} - -GLhandleARB ShaderARB::compileShader(const char *source, GLenum shaderType) { - GLuint handle; - GL_ASSIGN(handle, glCreateShaderObjectARB(shaderType)); - if (!handle) { - return 0; - } - - GL_CALL(glShaderSourceARB(handle, 1, &source, nullptr)); - GL_CALL(glCompileShaderARB(handle)); - - GLint result; - GL_CALL(glGetObjectParameterivARB(handle, GL_OBJECT_COMPILE_STATUS_ARB, &result)); - if (result == GL_FALSE) { - GLint logSize; - GL_CALL(glGetObjectParameterivARB(handle, GL_OBJECT_INFO_LOG_LENGTH_ARB, &logSize)); - - GLchar *log = new GLchar[logSize]; - GL_CALL(glGetInfoLogARB(handle, logSize, nullptr, log)); - warning("Could not compile shader \"%s\": \"%s\"", source, log); - delete[] log; - - GL_CALL(glDeleteObjectARB(handle)); - return 0; - } - - return handle; -} - -#endif // !USE_FORCED_GLES2 - -#if !USE_FORCED_GL - -ShaderGLES2::ShaderGLES2(const Common::String &vertex, const Common::String &fragment) - : Shader(vertex, fragment), _program(0), _projectionLocation(-1), _textureLocation(-1) { -} - -ShaderGLES2::~ShaderGLES2() { - GL_CALL_SAFE(glDeleteProgram, (_program)); -} - -void ShaderGLES2::destroy() { - GL_CALL(glDeleteProgram(_program)); - _program = 0; -} - -bool ShaderGLES2::recreate() { - // Make sure any old programs are destroyed properly. - destroy(); - - GLuint vertexShader = compileShader(_vertex.c_str(), GL_VERTEX_SHADER); - if (!vertexShader) { - return false; - } - - GLuint fragmentShader = compileShader(_fragment.c_str(), GL_FRAGMENT_SHADER); + GLshader fragmentShader = compileShader(_fragment.c_str(), GL_FRAGMENT_SHADER); if (!fragmentShader) { GL_CALL(glDeleteShader(vertexShader)); return false; @@ -287,7 +160,7 @@ bool ShaderGLES2::recreate() { return true; } -void ShaderGLES2::activate(const GLfloat *projectionMatrix) { +void Shader::activate(const GLfloat *projectionMatrix) { // Activate program. GL_CALL(glUseProgram(_program)); @@ -298,8 +171,8 @@ void ShaderGLES2::activate(const GLfloat *projectionMatrix) { GL_CALL(glUniform1i(_textureLocation, 0)); } -GLuint ShaderGLES2::compileShader(const char *source, GLenum shaderType) { - GLuint handle; +GLshader Shader::compileShader(const char *source, GLenum shaderType) { + GLshader handle; GL_ASSIGN(handle, glCreateShader(shaderType)); if (!handle) { return 0; @@ -326,8 +199,6 @@ GLuint ShaderGLES2::compileShader(const char *source, GLenum shaderType) { return handle; } -#endif // !!USE_FORCED_GL - } // End of namespace OpenGL #endif // !USE_FORCED_GLES -- cgit v1.2.3 From e66e9e44d358b0cc90d128c31e695a8ace4177fa Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sat, 2 Jan 2016 14:09:41 +0100 Subject: OPENGL: Accelerate palette lookups with shaders. This currently is limited to GL contexts. --- backends/graphics/opengl/shader.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'backends/graphics/opengl/shader.cpp') diff --git a/backends/graphics/opengl/shader.cpp b/backends/graphics/opengl/shader.cpp index 9e106a81b8..c251ec1ed9 100644 --- a/backends/graphics/opengl/shader.cpp +++ b/backends/graphics/opengl/shader.cpp @@ -171,6 +171,16 @@ void Shader::activate(const GLfloat *projectionMatrix) { GL_CALL(glUniform1i(_textureLocation, 0)); } +GLint Shader::getUniformLocation(const char *name) const { + GLint result = -1; + GL_ASSIGN(result, glGetUniformLocation(_program, name)); + return result; +} + +void Shader::setUniformI(GLint location, GLint value) { + GL_CALL(glUniform1i(location, value)); +} + GLshader Shader::compileShader(const char *source, GLenum shaderType) { GLshader handle; GL_ASSIGN(handle, glCreateShader(shaderType)); -- cgit v1.2.3 From 2319fcd2289f604f2a9c00942a9cd2e88ea2acc8 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 3 Jan 2016 11:58:50 +0100 Subject: OPENGL: Handle GLES2 and GL shaders uniformly. GLES2 requires precision qualifiers to be set and allows use of precision qualifiers. For GLES2 we define a default precision now. Since precision qualifiers are not supported in the GLSL version we use for GL, we introduce compatibility #defines. --- backends/graphics/opengl/shader.cpp | 40 +++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-) (limited to 'backends/graphics/opengl/shader.cpp') diff --git a/backends/graphics/opengl/shader.cpp b/backends/graphics/opengl/shader.cpp index c251ec1ed9..e699262b8d 100644 --- a/backends/graphics/opengl/shader.cpp +++ b/backends/graphics/opengl/shader.cpp @@ -25,6 +25,7 @@ #if !USE_FORCED_GLES #include "common/textconsole.h" +#include "common/util.h" namespace OpenGL { @@ -44,8 +45,7 @@ const char *const g_defaultVertexShader = "\tgl_Position = projection * position;\n" "}\n"; -#if !USE_FORCED_GLES2 -const char *const g_defaultFragmentShaderGL = +const char *const g_defaultFragmentShader = "varying vec2 texCoord;\n" "varying vec4 blendColor;\n" "\n" @@ -54,19 +54,24 @@ const char *const g_defaultFragmentShaderGL = "void main(void) {\n" "\tgl_FragColor = blendColor * texture2D(texture, texCoord);\n" "}\n"; -#endif -#if !USE_FORCED_GL -const char *const g_defaultFragmentShaderGLES2 = - "varying lowp vec2 texCoord;\n" - "varying lowp vec4 blendColor;\n" - "\n" - "uniform sampler2D texture;\n" - "\n" - "void main(void) {\n" - "\tgl_FragColor = blendColor * texture2D(texture, texCoord);\n" - "}\n"; -#endif +namespace { + +// Taken from: https://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_03#OpenGL_ES_2_portability +const char *const g_precisionDefines = + "#ifdef GL_ES\n" + "\t#if defined(GL_FRAGMENT_PRECISION_HIGH) && GL_FRAGMENT_PRECISION_HIGH == 1\n" + "\t\tprecision highp float;\n" + "\t#else\n" + "\t\tprecision mediump float;\n" + "\t#endif\n" + "#else\n" + "\t#define highp\n" + "\t#define mediump\n" + "\t#define lowp\n" + "#endif\n"; + +} // End of anonymous namespace Shader::Shader(const Common::String &vertex, const Common::String &fragment) : _vertex(vertex), _fragment(fragment), _program(0), _projectionLocation(-1), _textureLocation(-1) { @@ -188,7 +193,12 @@ GLshader Shader::compileShader(const char *source, GLenum shaderType) { return 0; } - GL_CALL(glShaderSource(handle, 1, &source, nullptr)); + const char *const sources[2] = { + g_precisionDefines, + source + }; + + GL_CALL(glShaderSource(handle, ARRAYSIZE(sources), sources, nullptr)); GL_CALL(glCompileShader(handle)); GLint result; -- cgit v1.2.3 From 5498982a3754edccb498521587c553e0ecbe7328 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Mon, 4 Jan 2016 07:07:37 +0100 Subject: OPENGL: Introduce ShaderManager to handle builtin shaders. --- backends/graphics/opengl/shader.cpp | 53 ++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) (limited to 'backends/graphics/opengl/shader.cpp') diff --git a/backends/graphics/opengl/shader.cpp b/backends/graphics/opengl/shader.cpp index e699262b8d..2f2d5d82eb 100644 --- a/backends/graphics/opengl/shader.cpp +++ b/backends/graphics/opengl/shader.cpp @@ -27,8 +27,14 @@ #include "common/textconsole.h" #include "common/util.h" +namespace Common { +DECLARE_SINGLETON(OpenGL::ShaderManager); +} + namespace OpenGL { +namespace { + const char *const g_defaultVertexShader = "attribute vec4 position;\n" "attribute vec2 texCoordIn;\n" @@ -55,7 +61,20 @@ const char *const g_defaultFragmentShader = "\tgl_FragColor = blendColor * texture2D(texture, texCoord);\n" "}\n"; -namespace { +const char *const g_lookUpFragmentShader = + "varying vec2 texCoord;\n" + "varying vec4 blendColor;\n" + "\n" + "uniform sampler2D texture;\n" + "uniform sampler2D palette;\n" + "\n" + "const float adjustFactor = 255.0 / 256.0 + 1.0 / (2.0 * 256.0);" + "\n" + "void main(void) {\n" + "\tvec4 index = texture2D(texture, texCoord);\n" + "\tgl_FragColor = blendColor * texture2D(palette, vec2(index.a * adjustFactor, 0.0));\n" + "}\n"; + // Taken from: https://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_03#OpenGL_ES_2_portability const char *const g_precisionDefines = @@ -219,6 +238,38 @@ GLshader Shader::compileShader(const char *source, GLenum shaderType) { return handle; } +ShaderManager::ShaderManager() { + _builtIn[kDefault] = new Shader(g_defaultVertexShader, g_defaultFragmentShader); + _builtIn[kCLUT8LookUp] = new Shader(g_defaultVertexShader, g_lookUpFragmentShader); +} + +ShaderManager::~ShaderManager() { + for (int i = 0; i < ARRAYSIZE(_builtIn); ++i) { + delete _builtIn[i]; + } +} + +void ShaderManager::notifyDestroy() { + for (int i = 0; i < ARRAYSIZE(_builtIn); ++i) { + _builtIn[i]->destroy(); + } +} + +void ShaderManager::notifyCreate() { + for (int i = 0; i < ARRAYSIZE(_builtIn); ++i) { + _builtIn[i]->recreate(); + } +} + +Shader *ShaderManager::query(ShaderUsage shader) const { + if (shader == kMaxUsages) { + warning("OpenGL: ShaderManager::query used with kMaxUsages"); + return nullptr; + } + + return _builtIn[shader]; +} + } // End of namespace OpenGL #endif // !USE_FORCED_GLES -- cgit v1.2.3 From baca885cfce10acaa7a9892133aaa5b82c7183f7 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Wed, 2 Mar 2016 15:16:05 +0100 Subject: OPENGL: Let Shader store the uniform state. --- backends/graphics/opengl/shader.cpp | 90 ++++++++++++++++++++++++++++++------- 1 file changed, 73 insertions(+), 17 deletions(-) (limited to 'backends/graphics/opengl/shader.cpp') diff --git a/backends/graphics/opengl/shader.cpp b/backends/graphics/opengl/shader.cpp index 2f2d5d82eb..59749ba1f0 100644 --- a/backends/graphics/opengl/shader.cpp +++ b/backends/graphics/opengl/shader.cpp @@ -35,6 +35,8 @@ namespace OpenGL { namespace { +#pragma mark - Builtin Shader Sources - + const char *const g_defaultVertexShader = "attribute vec4 position;\n" "attribute vec2 texCoordIn;\n" @@ -92,8 +94,25 @@ const char *const g_precisionDefines = } // End of anonymous namespace +#pragma mark - Uniform Values - + +void ShaderUniformInteger::set(GLint location) const { + GL_CALL(glUniform1i(location, _value)); +} + +void ShaderUniformFloat::set(GLint location) const { + GL_CALL(glUniform1f(location, _value)); +} + +void ShaderUniformMatrix44::set(GLint location) const { + GL_CALL(glUniformMatrix4fv(location, 1, GL_FALSE, _matrix)); +} + +#pragma mark - Shader Implementation - + Shader::Shader(const Common::String &vertex, const Common::String &fragment) - : _vertex(vertex), _fragment(fragment), _program(0), _projectionLocation(-1), _textureLocation(-1) { + : _vertex(vertex), _fragment(fragment), _isActive(false), _program(0), _uniforms() { + recreate(); } Shader::~Shader() { @@ -167,15 +186,26 @@ bool Shader::recreate() { return false; } - GL_ASSIGN(_projectionLocation, glGetUniformLocation(_program, "projection")); - if (_projectionLocation == -1) { + // Set program object in case shader is active during recreation. + if (_isActive) { + GL_CALL(glUseProgram(_program)); + } + + for (UniformMap::iterator i = _uniforms.begin(), end = _uniforms.end(); i != end; ++i) { + i->_value.location = getUniformLocation(i->_key.c_str()); + i->_value.altered = true; + if (_isActive) { + i->_value.set(); + } + } + + if (getUniformLocation("projection") == -1) { warning("Shader misses \"projection\" uniform."); destroy(); return false; } - GL_ASSIGN(_textureLocation, glGetUniformLocation(_program, "texture")); - if (_textureLocation == -1) { + if (!setUniform1I("texture", 0)) { warning("Shader misses \"texture\" uniform."); destroy(); return false; @@ -184,15 +214,20 @@ bool Shader::recreate() { return true; } -void Shader::activate(const GLfloat *projectionMatrix) { +void Shader::activate() { // Activate program. GL_CALL(glUseProgram(_program)); - // Set projection matrix. - GL_CALL(glUniformMatrix4fv(_projectionLocation, 1, GL_FALSE, projectionMatrix)); + // Reset changed uniform values. + for (UniformMap::iterator i = _uniforms.begin(), end = _uniforms.end(); i != end; ++i) { + i->_value.set(); + } + + _isActive = true; +} - // We always use texture unit 0. - GL_CALL(glUniform1i(_textureLocation, 0)); +void Shader::deactivate() { + _isActive = false; } GLint Shader::getUniformLocation(const char *name) const { @@ -201,8 +236,23 @@ GLint Shader::getUniformLocation(const char *name) const { return result; } -void Shader::setUniformI(GLint location, GLint value) { - GL_CALL(glUniform1i(location, value)); +bool Shader::setUniform(const Common::String &name, ShaderUniformValue *value) { + UniformMap::iterator uniformIter = _uniforms.find(name); + Uniform *uniform; + + if (uniformIter == _uniforms.end()) { + uniform = &_uniforms[name]; + uniform->location = getUniformLocation(name.c_str()); + } else { + uniform = &uniformIter->_value; + } + + uniform->value = Common::SharedPtr(value); + uniform->altered = true; + if (_isActive) { + uniform->set(); + } + return uniform->location != -1; } GLshader Shader::compileShader(const char *source, GLenum shaderType) { @@ -238,9 +288,7 @@ GLshader Shader::compileShader(const char *source, GLenum shaderType) { return handle; } -ShaderManager::ShaderManager() { - _builtIn[kDefault] = new Shader(g_defaultVertexShader, g_defaultFragmentShader); - _builtIn[kCLUT8LookUp] = new Shader(g_defaultVertexShader, g_lookUpFragmentShader); +ShaderManager::ShaderManager() : _initializeShaders(true) { } ShaderManager::~ShaderManager() { @@ -256,8 +304,16 @@ void ShaderManager::notifyDestroy() { } void ShaderManager::notifyCreate() { - for (int i = 0; i < ARRAYSIZE(_builtIn); ++i) { - _builtIn[i]->recreate(); + if (_initializeShaders) { + _initializeShaders = false; + + _builtIn[kDefault] = new Shader(g_defaultVertexShader, g_defaultFragmentShader); + _builtIn[kCLUT8LookUp] = new Shader(g_defaultVertexShader, g_lookUpFragmentShader); + _builtIn[kCLUT8LookUp]->setUniform1I("palette", 1); + } else { + for (int i = 0; i < ARRAYSIZE(_builtIn); ++i) { + _builtIn[i]->recreate(); + } } } -- cgit v1.2.3 From 39100b613272523c2e36be213cc827857a08f824 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Fri, 4 Mar 2016 00:14:22 +0100 Subject: OPENGL: Do not hardcode any uniform/attribute handling in Shader. --- backends/graphics/opengl/shader.cpp | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) (limited to 'backends/graphics/opengl/shader.cpp') diff --git a/backends/graphics/opengl/shader.cpp b/backends/graphics/opengl/shader.cpp index 59749ba1f0..652da57dfa 100644 --- a/backends/graphics/opengl/shader.cpp +++ b/backends/graphics/opengl/shader.cpp @@ -159,10 +159,6 @@ bool Shader::recreate() { GL_CALL(glAttachShader(_program, vertexShader)); GL_CALL(glAttachShader(_program, fragmentShader)); - GL_CALL(glBindAttribLocation(_program, kPositionAttribLocation, "position")); - GL_CALL(glBindAttribLocation(_program, kTexCoordAttribLocation, "texCoordIn")); - GL_CALL(glBindAttribLocation(_program, kColorAttribLocation, "blendColorIn")); - GL_CALL(glLinkProgram(_program)); GL_CALL(glDetachShader(_program, fragmentShader)); @@ -199,18 +195,6 @@ bool Shader::recreate() { } } - if (getUniformLocation("projection") == -1) { - warning("Shader misses \"projection\" uniform."); - destroy(); - return false; - } - - if (!setUniform1I("texture", 0)) { - warning("Shader misses \"texture\" uniform."); - destroy(); - return false; - } - return true; } @@ -230,6 +214,12 @@ void Shader::deactivate() { _isActive = false; } +GLint Shader::getAttributeLocation(const char *name) const { + GLint result = -1; + GL_ASSIGN(result, glGetAttribLocation(_program, name)); + return result; +} + GLint Shader::getUniformLocation(const char *name) const { GLint result = -1; GL_ASSIGN(result, glGetUniformLocation(_program, name)); @@ -310,6 +300,10 @@ void ShaderManager::notifyCreate() { _builtIn[kDefault] = new Shader(g_defaultVertexShader, g_defaultFragmentShader); _builtIn[kCLUT8LookUp] = new Shader(g_defaultVertexShader, g_lookUpFragmentShader); _builtIn[kCLUT8LookUp]->setUniform1I("palette", 1); + + for (uint i = 0; i < kMaxUsages; ++i) { + _builtIn[i]->setUniform1I("texture", 0); + } } else { for (int i = 0; i < ARRAYSIZE(_builtIn); ++i) { _builtIn[i]->recreate(); -- cgit v1.2.3 From 17b1124a5aa294d39cf3a3c6fc6561f835affe2d Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Fri, 4 Mar 2016 16:08:28 +0100 Subject: OPENGL: Do not keep uniform state for nonexistent uniforms. --- backends/graphics/opengl/shader.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'backends/graphics/opengl/shader.cpp') diff --git a/backends/graphics/opengl/shader.cpp b/backends/graphics/opengl/shader.cpp index 652da57dfa..27981f25dc 100644 --- a/backends/graphics/opengl/shader.cpp +++ b/backends/graphics/opengl/shader.cpp @@ -231,8 +231,14 @@ bool Shader::setUniform(const Common::String &name, ShaderUniformValue *value) { Uniform *uniform; if (uniformIter == _uniforms.end()) { + const GLint location = getUniformLocation(name.c_str()); + if (location == -1) { + delete value; + return false; + } + uniform = &_uniforms[name]; - uniform->location = getUniformLocation(name.c_str()); + uniform->location = location; } else { uniform = &uniformIter->_value; } @@ -242,7 +248,8 @@ bool Shader::setUniform(const Common::String &name, ShaderUniformValue *value) { if (_isActive) { uniform->set(); } - return uniform->location != -1; + + return true; } GLshader Shader::compileShader(const char *source, GLenum shaderType) { -- cgit v1.2.3