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/context.cpp | 2 + backends/graphics/opengl/opengl-defs.h | 17 ++ backends/graphics/opengl/opengl-func.h | 25 +++ backends/graphics/opengl/opengl-graphics.cpp | 125 +++++++++++++-- backends/graphics/opengl/opengl-graphics.h | 31 +++- backends/graphics/opengl/opengl-sys.h | 12 +- backends/graphics/opengl/shader.cpp | 176 +++++++++++++++++++++ backends/graphics/opengl/shader.h | 110 +++++++++++++ backends/graphics/opengl/texture.cpp | 21 ++- backends/graphics/openglsdl/openglsdl-graphics.cpp | 20 ++- 10 files changed, 508 insertions(+), 31 deletions(-) create mode 100644 backends/graphics/opengl/shader.cpp create mode 100644 backends/graphics/opengl/shader.h (limited to 'backends/graphics') diff --git a/backends/graphics/opengl/context.cpp b/backends/graphics/opengl/context.cpp index 0077cc2746..0944e05f7c 100644 --- a/backends/graphics/opengl/context.cpp +++ b/backends/graphics/opengl/context.cpp @@ -44,6 +44,8 @@ void OpenGLGraphicsManager::setContextType(ContextType type) { type = kContextGL; #elif USE_FORCED_GLES type = kContextGLES; +#elif USE_FORCED_GLES2 + type = kContextGLES2; #endif g_context.type = type; diff --git a/backends/graphics/opengl/opengl-defs.h b/backends/graphics/opengl/opengl-defs.h index 4b82d7edd7..fe79caadd4 100644 --- a/backends/graphics/opengl/opengl-defs.h +++ b/backends/graphics/opengl/opengl-defs.h @@ -75,11 +75,16 @@ typedef float GLfloat; /* single precision float */ typedef float GLclampf; /* single precision float in [0,1] */ typedef double GLdouble; /* double precision float */ typedef double GLclampd; /* double precision float in [0,1] */ +typedef char GLchar; /* * Constants */ +/* Boolean constants */ +#define GL_FALSE 0 +#define GL_TRUE 1 + /* StringName */ #define GL_VENDOR 0x1F00 #define GL_RENDERER 0x1F01 @@ -216,4 +221,16 @@ typedef double GLclampd; /* double precision float in [0,1] */ #define GL_TRIANGLE_STRIP 0x0005 #define GL_TRIANGLE_FAN 0x0006 +/* Shaders */ +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 + +/* Programs */ +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_INFO_LOG_LENGTH 0x8B84 + +/* Textures */ +#define GL_TEXTURE0 0x84C0 + #endif diff --git a/backends/graphics/opengl/opengl-func.h b/backends/graphics/opengl/opengl-func.h index d13dece1ea..633385a4d0 100644 --- a/backends/graphics/opengl/opengl-func.h +++ b/backends/graphics/opengl/opengl-func.h @@ -91,3 +91,28 @@ GL_FUNC_DEF(void, glDrawArrays, (GLenum mode, GLint first, GLsizei count)); GL_FUNC_DEF(void, glTexSubImage2D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)); GL_FUNC_DEF(const GLubyte *, glGetString, (GLenum name)); GL_FUNC_DEF(GLenum, glGetError, ()); + +#if !USE_FORCED_GL && !USE_FORCED_GLES +GL_FUNC_DEF(void, glVertexAttrib4f, (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)); +GL_FUNC_DEF(void, glVertexAttribPointer, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer)); +GL_FUNC_DEF(void, glUniformMatrix4fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)); +GL_FUNC_DEF(void, glUniform1i, (GLint location, GLint v0)); +GL_FUNC_DEF(void, glDeleteProgram, (GLuint program)); +GL_FUNC_DEF(void, glDeleteShader, (GLuint shader)); +GL_FUNC_DEF(GLuint, glCreateProgram, ()); +GL_FUNC_DEF(void, glAttachShader, (GLuint program, GLuint shader)); +GL_FUNC_DEF(void, glBindAttribLocation, (GLuint program, GLuint index, const GLchar *name)); +GL_FUNC_DEF(void, glLinkProgram, (GLuint program)); +GL_FUNC_DEF(void, glDetachShader, (GLuint program, GLuint shader)); +GL_FUNC_DEF(void, glGetProgramiv, (GLuint program, GLenum pname, GLint *params)); +GL_FUNC_DEF(void, glGetProgramInfoLog, (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog)); +GL_FUNC_DEF(GLint, glGetUniformLocation, (GLuint program, const GLchar *name)); +GL_FUNC_DEF(void, glUseProgram, (GLuint program)); +GL_FUNC_DEF(GLuint, glCreateShader, (GLenum type)); +GL_FUNC_DEF(void, glShaderSource, (GLuint shader, GLsizei count, const GLchar *const *string, const GLint *length)); +GL_FUNC_DEF(void, glCompileShader, (GLuint shader)); +GL_FUNC_DEF(void, glGetShaderiv, (GLuint shader, GLenum pname, GLint *params)); +GL_FUNC_DEF(void, glGetShaderInfoLog, (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog)); +GL_FUNC_DEF(void, glEnableVertexAttribArray, (GLuint index)); +GL_FUNC_DEF(void, glActiveTexture, (GLenum texture)); +#endif diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp index 15e6f40271..1b20a31363 100644 --- a/backends/graphics/opengl/opengl-graphics.cpp +++ b/backends/graphics/opengl/opengl-graphics.cpp @@ -23,6 +23,7 @@ #include "backends/graphics/opengl/opengl-graphics.h" #include "backends/graphics/opengl/texture.h" +#include "backends/graphics/opengl/shader.h" #include "common/textconsole.h" #include "common/translation.h" @@ -53,6 +54,9 @@ OpenGLGraphicsManager::OpenGLGraphicsManager() _forceRedraw(false), _scissorOverride(3) #ifdef USE_OSD , _osdAlpha(0), _osdFadeStartTime(0), _osd(nullptr) +#endif +#if !USE_FORCED_GL && !USE_FORCED_GLES + , _shader(nullptr), _projectionMatrix() #endif { memset(_gamePalette, 0, sizeof(_gamePalette)); @@ -66,6 +70,9 @@ OpenGLGraphicsManager::~OpenGLGraphicsManager() { #ifdef USE_OSD delete _osd; #endif +#if !USE_FORCED_GL && !USE_FORCED_GLES + delete _shader; +#endif } bool OpenGLGraphicsManager::hasFeature(OSystem::Feature f) { @@ -418,13 +425,13 @@ void OpenGLGraphicsManager::updateScreen() { } // Set the OSD transparency. - GL_CALL(glColor4f(1.0f, 1.0f, 1.0f, _osdAlpha / 100.0f)); + setColor(1.0f, 1.0f, 1.0f, _osdAlpha / 100.0f); // Draw the OSD texture. _osd->draw(0, 0, _outputScreenWidth, _outputScreenHeight); // Reset color. - GL_CALL(glColor4f(1.0f, 1.0f, 1.0f, 1.0f)); + setColor(1.0f, 1.0f, 1.0f, 1.0f); } #endif @@ -765,11 +772,29 @@ void OpenGLGraphicsManager::setActualScreenSize(uint width, uint height) { -1.0f , 1.0f , 0.0f, 1.0f }; - GL_CALL(glMatrixMode(GL_PROJECTION)); - GL_CALL(glLoadMatrixf(orthoProjection)); +#if !USE_FORCED_GL && !USE_FORCED_GLES && !USE_FORCED_GLES2 + if (g_context.type != kContextGLES2) { +#endif +#if !USE_FORCED_GLES2 + GL_CALL(glMatrixMode(GL_PROJECTION)); + GL_CALL(glLoadMatrixf(orthoProjection)); - GL_CALL(glMatrixMode(GL_MODELVIEW)); - GL_CALL(glLoadIdentity()); + GL_CALL(glMatrixMode(GL_MODELVIEW)); + GL_CALL(glLoadIdentity()); +#endif +#if !USE_FORCED_GL && !USE_FORCED_GLES && !USE_FORCED_GLES2 + } else { +#endif +#if !USE_FORCED_GL && !USE_FORCED_GLES + assert(sizeof(_projectionMatrix) == sizeof(orthoProjection)); + memcpy(_projectionMatrix, orthoProjection, sizeof(_projectionMatrix)); + if (_shader) { + _shader->activate(_projectionMatrix); + } +#endif +#if !USE_FORCED_GL && !USE_FORCED_GLES && !USE_FORCED_GLES2 + } +#endif uint overlayWidth = width; uint overlayHeight = height; @@ -845,25 +870,51 @@ void OpenGLGraphicsManager::notifyContextCreate(const Graphics::PixelFormat &def // Disable 3D properties. GL_CALL(glDisable(GL_CULL_FACE)); GL_CALL(glDisable(GL_DEPTH_TEST)); - GL_CALL(glDisable(GL_LIGHTING)); - GL_CALL(glDisable(GL_FOG)); GL_CALL(glDisable(GL_DITHER)); - GL_CALL(glShadeModel(GL_FLAT)); - GL_CALL(glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST)); + +#if !USE_FORCED_GL && !USE_FORCED_GLES && !USE_FORCED_GLES2 + if (g_context.type != kContextGLES2) { +#endif +#if !USE_FORCED_GLES2 + GL_CALL(glDisable(GL_LIGHTING)); + GL_CALL(glDisable(GL_FOG)); + GL_CALL(glShadeModel(GL_FLAT)); + GL_CALL(glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST)); +#endif +#if !USE_FORCED_GL && !USE_FORCED_GLES && !USE_FORCED_GLES2 + } +#endif // Default to black as clear color. GL_CALL(glClearColor(0.0f, 0.0f, 0.0f, 0.0f)); - GL_CALL(glColor4f(1.0f, 1.0f, 1.0f, 1.0f)); + setColor(1.0f, 1.0f, 1.0f, 1.0f); // Setup alpha blend (for overlay and cursor). GL_CALL(glEnable(GL_BLEND)); GL_CALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - // Enable rendering with vertex and coord arrays. - GL_CALL(glEnableClientState(GL_VERTEX_ARRAY)); - GL_CALL(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); +#if !USE_FORCED_GL && !USE_FORCED_GLES && !USE_FORCED_GLES2 + if (g_context.type != kContextGLES2) { +#endif +#if !USE_FORCED_GLES2 + // Enable rendering with vertex and coord arrays. + GL_CALL(glEnableClientState(GL_VERTEX_ARRAY)); + GL_CALL(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); + + GL_CALL(glEnable(GL_TEXTURE_2D)); +#endif +#if !USE_FORCED_GL && !USE_FORCED_GLES && !USE_FORCED_GLES2 + } else { +#endif +#if !USE_FORCED_GL && !USE_FORCED_GLES + GL_CALL(glEnableVertexAttribArray(kPositionAttribLocation)); + GL_CALL(glEnableVertexAttribArray(kTexCoordAttribLocation)); - GL_CALL(glEnable(GL_TEXTURE_2D)); + GL_CALL(glActiveTexture(GL_TEXTURE0)); +#endif +#if !USE_FORCED_GL && !USE_FORCED_GLES && !USE_FORCED_GLES2 + } +#endif // Setup scissor state accordingly. if (_overlayVisible) { @@ -883,6 +934,22 @@ void OpenGLGraphicsManager::notifyContextCreate(const Graphics::PixelFormat &def // Query information needed by textures. Texture::queryTextureInformation(); +#if !USE_FORCED_GL && !USE_FORCED_GLES && !USE_FORCED_GLES2 + if (g_context.type == kContextGLES2) { +#endif +#if !USE_FORCED_GL && !USE_FORCED_GLES + if (!_shader) { + _shader = new Shader(g_defaultVertexShader, g_defaultFragmentShader); + } + + // TODO: What do we do on failure? + _shader->recreate(); + _shader->activate(_projectionMatrix); +#endif +#if !USE_FORCED_GL && !USE_FORCED_GLES && !USE_FORCED_GLES2 + } +#endif + // Refresh the output screen dimensions if some are set up. if (_outputScreenWidth != 0 && _outputScreenHeight != 0) { setActualScreenSize(_outputScreenWidth, _outputScreenHeight); @@ -931,6 +998,12 @@ void OpenGLGraphicsManager::notifyContextDestroy() { _osd->releaseInternalTexture(); } #endif + +#if !USE_FORCED_GL && !USE_FORCED_GLES + if (_shader) { + _shader->destroy(); + } +#endif } void OpenGLGraphicsManager::adjustMousePosition(int16 &x, int16 &y) { @@ -1002,6 +1075,24 @@ Texture *OpenGLGraphicsManager::createTexture(const Graphics::PixelFormat &forma } } +void OpenGLGraphicsManager::setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { +#if !USE_FORCED_GL && !USE_FORCED_GLES && !USE_FORCED_GLES2 + if (g_context.type != kContextGLES2) { +#endif +#if !USE_FORCED_GLES2 + GL_CALL(glColor4f(r, g, b, a)); +#endif +#if !USE_FORCED_GL && !USE_FORCED_GLES && !USE_FORCED_GLES2 + } else { +#endif +#if !USE_FORCED_GL && !USE_FORCED_GLES + GL_CALL(glVertexAttrib4f(kColorAttribLocation, r, g, b, a)); +#endif +#if !USE_FORCED_GL && !USE_FORCED_GLES && !USE_FORCED_GLES2 + } +#endif +} + bool OpenGLGraphicsManager::getGLPixelFormat(const Graphics::PixelFormat &pixelFormat, GLenum &glIntFormat, GLenum &glFormat, GLenum &glType) const { #ifdef SCUMM_LITTLE_ENDIAN if (pixelFormat == Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24)) { // ABGR8888 @@ -1027,7 +1118,7 @@ bool OpenGLGraphicsManager::getGLPixelFormat(const Graphics::PixelFormat &pixelF glFormat = GL_RGBA; glType = GL_UNSIGNED_SHORT_4_4_4_4; return true; -#if !USE_FORCED_GLES +#if !USE_FORCED_GLES && !USE_FORCED_GLES2 // The formats below are not supported by every GLES implementation. // Thus, we do not mark them as supported when a GLES context is setup. } else if (isGLESContext()) { @@ -1081,7 +1172,7 @@ bool OpenGLGraphicsManager::getGLPixelFormat(const Graphics::PixelFormat &pixelF glFormat = GL_BGRA; glType = GL_UNSIGNED_SHORT_4_4_4_4; return true; -#endif // !USE_FORCED_GLES +#endif // !USE_FORCED_GLES && !USE_FORCED_GLES2 } else { return false; } diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h index 5a2b1bb373..37ab1f8591 100644 --- a/backends/graphics/opengl/opengl-graphics.h +++ b/backends/graphics/opengl/opengl-graphics.h @@ -41,6 +41,9 @@ namespace OpenGL { #define USE_OSD 1 class Texture; +#if !USE_FORCED_GL && !USE_FORCED_GLES +class Shader; +#endif enum { GFX_LINEAR = 0, @@ -117,9 +120,9 @@ public: protected: /** - * Whether an GLES context is active. + * Whether an GLES or GLES2 context is active. */ - bool isGLESContext() const { return g_context.type == kContextGLES; } + bool isGLESContext() const { return g_context.type == kContextGLES || g_context.type == kContextGLES2; } /** * Set up the actual screen size available for the OpenGL code to do any @@ -300,6 +303,14 @@ private: */ void initializeGLContext(); + /** + * Set color which shall be multiplied with each pixel. + * + * This serves as a wrapper around glColor4f for fixed-function and our + * shader pipeline. + */ + void setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a); + protected: /** * Query the address of an OpenGL function by name. @@ -518,6 +529,22 @@ private: */ uint _scissorOverride; +#if !USE_FORCED_GL && !USE_FORCED_GLES + // + // Shaders + // + + /** + * Active shader. + */ + Shader *_shader; + + /** + * Projection matrix used. + */ + GLfloat _projectionMatrix[4*4]; +#endif + #ifdef USE_OSD // // OSD diff --git a/backends/graphics/opengl/opengl-sys.h b/backends/graphics/opengl/opengl-sys.h index 250357f92a..ad36226a57 100644 --- a/backends/graphics/opengl/opengl-sys.h +++ b/backends/graphics/opengl/opengl-sys.h @@ -35,8 +35,10 @@ // the given selection choices: // 0 - Force OpenGL context // 1 - Force OpenGL ES context -#define USE_FORCED_GL (defined(USE_GLES_MODE) && USE_GLES_MODE == 0) -#define USE_FORCED_GLES (defined(USE_GLES_MODE) && USE_GLES_MODE == 1) +// 2 - Force OpenGL ES 2.0 context +#define USE_FORCED_GL (defined(USE_GLES_MODE) && USE_GLES_MODE == 0) +#define USE_FORCED_GLES (defined(USE_GLES_MODE) && USE_GLES_MODE == 1) +#define USE_FORCED_GLES2 (defined(USE_GLES_MODE) && USE_GLES_MODE == 2) // On Tizen we include the toolchain's OpenGL file. This is something we // actually want to avoid. However, since Tizen uses eglGetProcAddress which @@ -69,7 +71,8 @@ namespace OpenGL { enum ContextType { kContextGL, - kContextGLES + kContextGLES, + kContextGLES2 }; /** @@ -103,6 +106,7 @@ extern Context g_context; } // End of namespace OpenGL -#define GL_CALL(x) GL_WRAP_DEBUG(g_context.x, x) +#define GL_CALL(x) GL_WRAP_DEBUG(g_context.x, x) +#define GL_ASSIGN(var, x) GL_WRAP_DEBUG(var = g_context.x, x) #endif 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 diff --git a/backends/graphics/opengl/shader.h b/backends/graphics/opengl/shader.h new file mode 100644 index 0000000000..e8535e0225 --- /dev/null +++ b/backends/graphics/opengl/shader.h @@ -0,0 +1,110 @@ +/* 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. + * + */ + +#ifndef BACKENDS_GRAPHICS_OPENGL_SHADER_H +#define BACKENDS_GRAPHICS_OPENGL_SHADER_H + +#include "backends/graphics/opengl/opengl-sys.h" + +#if !USE_FORCED_GL && !USE_FORCED_GLES + +#include "common/str.h" + +namespace OpenGL { + +enum { + kPositionAttribLocation = 0, + kTexCoordAttribLocation = 1, + kColorAttribLocation = 2 +}; + +extern const char *const g_defaultVertexShader; +extern const char *const g_defaultFragmentShader; + +class Shader { +public: + Shader(const Common::String &vertex, const Common::String &fragment); + ~Shader() { destroy(); } + + /** + * Destroy the shader program. + * + * This keeps the vertex and fragment shader sources around and thus + * allows for recreating the shader on context recreation. + */ + void destroy(); + + /** + * Recreate shader program. + * + * @return true on success, false on failure. + */ + bool recreate(); + + /** + * Make shader active. + * + * @param projectionMatrix Projection matrix to use. + */ + void activate(const GLfloat *projectionMatrix); +private: + /** + * Vertex shader sources. + */ + const Common::String _vertex; + + /** + * Fragment shader sources. + */ + const Common::String _fragment; + + /** + * Shader program handle. + */ + GLuint _program; + + /** + * Location of the matrix uniform in the shader program. + */ + GLint _projectionLocation; + + /** + * Location of the texture sampler location in the shader program. + */ + GLint _textureLocation; + + /** + * Compile a vertex or fragment shader. + * + * @param source Sources to the shader. + * @param shaderType Type of shader to compile (GL_FRAGMENT_SHADER or + * GL_VERTEX_SHADER) + * @return The shader object or 0 on failure. + */ + static GLuint compileShader(const char *source, GLenum shaderType); +}; + +} // End of namespace OpenGL + +#endif // !USE_FORCED_GL && !USE_FORCED_GLES + +#endif diff --git a/backends/graphics/opengl/texture.cpp b/backends/graphics/opengl/texture.cpp index fadfd99aaa..c8c38edbbd 100644 --- a/backends/graphics/opengl/texture.cpp +++ b/backends/graphics/opengl/texture.cpp @@ -21,6 +21,7 @@ */ #include "backends/graphics/opengl/texture.h" +#include "backends/graphics/opengl/shader.h" #include "common/rect.h" #include "common/textconsole.h" @@ -185,7 +186,6 @@ void Texture::draw(GLfloat x, GLfloat y, GLfloat w, GLfloat h) { 0, texHeight, texWidth, texHeight }; - GL_CALL(glTexCoordPointer(2, GL_FLOAT, 0, texcoords)); // Calculate the screen rect where the texture will be drawn. const GLfloat vertices[4*2] = { @@ -194,7 +194,24 @@ void Texture::draw(GLfloat x, GLfloat y, GLfloat w, GLfloat h) { x, y + h, x + w, y + h }; - GL_CALL(glVertexPointer(2, GL_FLOAT, 0, vertices)); + +#if !USE_FORCED_GL && !USE_FORCED_GLES && !USE_FORCED_GLES2 + if (g_context.type != kContextGLES2) { +#endif +#if !USE_FORCED_GLES2 + GL_CALL(glTexCoordPointer(2, GL_FLOAT, 0, texcoords)); + GL_CALL(glVertexPointer(2, GL_FLOAT, 0, vertices)); +#endif +#if !USE_FORCED_GL && !USE_FORCED_GLES && !USE_FORCED_GLES2 + } else { +#endif +#if !USE_FORCED_GL && !USE_FORCED_GLES + GL_CALL(glVertexAttribPointer(kTexCoordAttribLocation, 2, GL_FLOAT, GL_FALSE, 0, texcoords)); + GL_CALL(glVertexAttribPointer(kPositionAttribLocation, 2, GL_FLOAT, GL_FALSE, 0, vertices)); +#endif +#if !USE_FORCED_GL && !USE_FORCED_GLES && !USE_FORCED_GLES2 + } +#endif // Draw the texture to the screen buffer. GL_CALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); diff --git a/backends/graphics/openglsdl/openglsdl-graphics.cpp b/backends/graphics/openglsdl/openglsdl-graphics.cpp index 94f5f7aba2..f2af7ccadd 100644 --- a/backends/graphics/openglsdl/openglsdl-graphics.cpp +++ b/backends/graphics/openglsdl/openglsdl-graphics.cpp @@ -57,6 +57,9 @@ OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(uint desktopWidth, uint deskt #define DEFAULT_GLES_MAJOR 1 #define DEFAULT_GLES_MINOR 1 +#define DEFAULT_GLES2_MAJOR 2 +#define DEFAULT_GLES2_MINOR 0 + #if USE_FORCED_GL glContextType = OpenGL::kContextGL; _glContextProfileMask = SDL_GL_CONTEXT_PROFILE_COMPATIBILITY; @@ -67,6 +70,11 @@ OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(uint desktopWidth, uint deskt _glContextProfileMask = SDL_GL_CONTEXT_PROFILE_ES; _glContextMajor = DEFAULT_GLES_MAJOR; _glContextMinor = DEFAULT_GLES_MINOR; +#elif USE_FORCED_GLES2 + glContextType = OpenGL::kContextGLES2; + _glContextProfileMask = SDL_GL_CONTEXT_PROFILE_ES; + _glContextMajor = DEFAULT_GLES2_MAJOR; + _glContextMinor = DEFAULT_GLES2_MINOR; #else bool noDefaults = false; @@ -102,12 +110,10 @@ OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(uint desktopWidth, uint deskt } if (_glContextProfileMask == SDL_GL_CONTEXT_PROFILE_ES) { - glContextType = OpenGL::kContextGLES; - - // We do not support GLES2 contexts right now. Force a GLES1 context. if (_glContextMajor >= 2) { - _glContextMajor = DEFAULT_GLES_MAJOR; - _glContextMinor = DEFAULT_GLES_MINOR; + glContextType = OpenGL::kContextGLES2; + } else { + glContextType = OpenGL::kContextGLES; } } else if (_glContextProfileMask == SDL_GL_CONTEXT_PROFILE_CORE) { glContextType = OpenGL::kContextGL; @@ -124,6 +130,8 @@ OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(uint desktopWidth, uint deskt #undef DEFAULT_GL_MINOR #undef DEFAULT_GLES_MAJOR #undef DEFAULT_GLES_MINOR +#undef DEFAULT_GLES2_MAJOR +#undef DEFAULT_GLES2_MINOR #endif setContextType(glContextType); @@ -296,7 +304,7 @@ Common::List OpenGLSdlGraphicsManager::getSupportedFormat // RGBA4444 formats.push_back(Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0)); -#if !USE_FORCED_GLES +#if !USE_FORCED_GLES && !USE_FORCED_GLES2 #if !USE_FORCED_GL if (!isGLESContext()) { #endif -- cgit v1.2.3