[Scummvm-git-logs] scummvm master -> 98c306376fd4b6c1884b71ba2665bd064246221f

lephilousophe noreply at scummvm.org
Sun Jun 26 16:32:14 UTC 2022


This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
4ab044a254 OPENGL: Merge both OpenGL contexts
98c306376f OPENGL: Merge both OpenGL shaders objects


Commit: 4ab044a254de09748c841b0da7f5393efc17f140
    https://github.com/scummvm/scummvm/commit/4ab044a254de09748c841b0da7f5393efc17f140
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2022-06-26T18:32:10+02:00

Commit Message:
OPENGL: Merge both OpenGL contexts

Changed paths:
  R backends/graphics/opengl/context.cpp
  R backends/graphics/opengl/opengl-sys.h
    backends/graphics/android/android-graphics.cpp
    backends/graphics/android/android-graphics.h
    backends/graphics/opengl/debug.cpp
    backends/graphics/opengl/debug.h
    backends/graphics/opengl/framebuffer.cpp
    backends/graphics/opengl/framebuffer.h
    backends/graphics/opengl/opengl-graphics.cpp
    backends/graphics/opengl/opengl-graphics.h
    backends/graphics/opengl/pipelines/clut8.cpp
    backends/graphics/opengl/pipelines/fixed.cpp
    backends/graphics/opengl/pipelines/pipeline.cpp
    backends/graphics/opengl/pipelines/pipeline.h
    backends/graphics/opengl/pipelines/shader.cpp
    backends/graphics/opengl/shader.cpp
    backends/graphics/opengl/shader.h
    backends/graphics/opengl/texture.cpp
    backends/graphics/opengl/texture.h
    backends/graphics/openglsdl/openglsdl-graphics.cpp
    backends/graphics/openglsdl/openglsdl-graphics.h
    backends/graphics3d/android/android-graphics3d.cpp
    backends/graphics3d/openglsdl/openglsdl-graphics3d.cpp
    backends/graphics3d/openglsdl/openglsdl-graphics3d.h
    backends/module.mk
    backends/platform/android/android.cpp
    backends/platform/android/android.h
    backends/platform/ios7/ios7_common.h
    backends/platform/ios7/ios7_osys_main.cpp
    backends/platform/ios7/ios7_osys_main.h
    backends/platform/sdl/sdl.cpp
    backends/platform/sdl/sdl.h
    common/system.h
    engines/grim/gfx_opengl_shaders.cpp
    engines/stark/gfx/opengltexture.cpp
    graphics/opengl/context.cpp
    graphics/opengl/context.h
    graphics/opengl/shader.cpp
    graphics/renderer.cpp


diff --git a/backends/graphics/android/android-graphics.cpp b/backends/graphics/android/android-graphics.cpp
index f2e22de5543..2541d8c3210 100644
--- a/backends/graphics/android/android-graphics.cpp
+++ b/backends/graphics/android/android-graphics.cpp
@@ -93,19 +93,22 @@ void AndroidGraphicsManager::initSurface() {
 	assert(!JNI::haveSurface());
 	JNI::initSurface();
 
-	// Notify the OpenGL code about our context.
-	setContextType(OpenGL::kContextGLES2);
-
 	if (JNI::egl_bits_per_pixel == 16) {
 		// We default to RGB565 and RGBA5551 which is closest to what we setup in Java side
-		notifyContextCreate(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0));
+		notifyContextCreate(OpenGL::kContextGLES2,
+				Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0),
+				Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0));
 	} else {
 		// If not 16, this must be 24 or 32 bpp so make use of them
+		notifyContextCreate(OpenGL::kContextGLES2,
 #ifdef SCUMM_BIG_ENDIAN
-		notifyContextCreate(Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0), Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
+				Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0),
+				Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)
 #else
-		notifyContextCreate(Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 8, 16, 0), Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
+				Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 8, 16, 0),
+				Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24)
 #endif
+		);
 	}
 
 	if (_touchcontrols) {
@@ -203,8 +206,8 @@ void AndroidGraphicsManager::refreshScreen() {
 
 void AndroidGraphicsManager::touchControlDraw(int16 x, int16 y, int16 w, int16 h, const Common::Rect &clip) {
 	_backBuffer.enableBlend(OpenGL::Framebuffer::kBlendModeTraditionalTransparency);
-	OpenGL::g_context.getActivePipeline()->drawTexture(_touchcontrols->getGLTexture(),
-		                                           x, y, w, h, clip);
+	OpenGL::Pipeline::getActivePipeline()->drawTexture(_touchcontrols->getGLTexture(),
+	                                                   x, y, w, h, clip);
 }
 
 void AndroidGraphicsManager::touchControlNotifyChanged() {
@@ -212,12 +215,6 @@ void AndroidGraphicsManager::touchControlNotifyChanged() {
 	_forceRedraw = true;
 }
 
-void *AndroidGraphicsManager::getProcAddress(const char *name) const {
-	ENTER("%s", name);
-
-	return androidGLgetProcAddress(name);
-}
-
 bool AndroidGraphicsManager::notifyMousePosition(Common::Point &mouse) {
 	mouse.x = CLIP<int16>(mouse.x, _activeArea.drawRect.left, _activeArea.drawRect.right);
 	mouse.y = CLIP<int16>(mouse.y, _activeArea.drawRect.top, _activeArea.drawRect.bottom);
diff --git a/backends/graphics/android/android-graphics.h b/backends/graphics/android/android-graphics.h
index 74a3c6311e4..b054c9b55a8 100644
--- a/backends/graphics/android/android-graphics.h
+++ b/backends/graphics/android/android-graphics.h
@@ -98,8 +98,6 @@ protected:
 
 	void refreshScreen() override;
 
-	void *getProcAddress(const char *name) const override;
-
 private:
 	OpenGL::Surface *_touchcontrols;
 	int _old_touch_mode;
diff --git a/backends/graphics/opengl/context.cpp b/backends/graphics/opengl/context.cpp
deleted file mode 100644
index 30907248415..00000000000
--- a/backends/graphics/opengl/context.cpp
+++ /dev/null
@@ -1,240 +0,0 @@
-/* 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 3 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, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#define GLAD_GL_IMPLEMENTATION
-
-#include "backends/graphics/opengl/opengl-sys.h"
-#include "backends/graphics/opengl/opengl-graphics.h"
-#include "backends/graphics/opengl/shader.h"
-#include "backends/graphics/opengl/pipelines/pipeline.h"
-#include "backends/graphics/opengl/framebuffer.h"
-
-#include "common/tokenizer.h"
-#include "common/debug.h"
-
-namespace OpenGL {
-
-void Context::reset() {
-	maxTextureSize = 0;
-
-	majorVersion = 0;
-	minorVersion = 0;
-
-	NPOTSupported = false;
-	shadersSupported = false;
-	multitextureSupported = false;
-	framebufferObjectSupported = false;
-	packedPixelsSupported = false;
-	textureEdgeClampSupported = false;
-
-	isInitialized = false;
-
-	activePipeline = nullptr;
-}
-
-Pipeline *Context::setPipeline(Pipeline *pipeline) {
-	Pipeline *oldPipeline = activePipeline;
-	if (oldPipeline) {
-		oldPipeline->deactivate();
-	}
-
-	activePipeline = pipeline;
-	if (activePipeline) {
-		activePipeline->activate();
-	}
-
-	return oldPipeline;
-}
-
-Context g_context;
-
-void OpenGLGraphicsManager::setContextType(ContextType type) {
-#if USE_FORCED_GL
-	type = kContextGL;
-#elif USE_FORCED_GLES
-	type = kContextGLES;
-#elif USE_FORCED_GLES2
-	type = kContextGLES2;
-#endif
-
-	g_context.type = type;
-}
-
-#ifdef USE_GLAD
-static GLADapiproc loadFunc(void *userptr, const char *name) {
-	OpenGLGraphicsManager *openglGraphicsManager = (OpenGLGraphicsManager *)userptr;
-	return (GLADapiproc)openglGraphicsManager->getProcAddress(name);
-}
-#endif
-
-void OpenGLGraphicsManager::initializeGLContext() {
-	// Initialize default state.
-	g_context.reset();
-
-#ifdef USE_GLAD
-	switch (g_context.type) {
-	case kContextGL:
-		gladLoadGLUserPtr(loadFunc, this);
-		break;
-
-	case kContextGLES:
-		gladLoadGLES1UserPtr(loadFunc, this);
-		break;
-
-	case kContextGLES2:
-		gladLoadGLES2UserPtr(loadFunc, this);
-		break;
-
-	default:
-		break;
-	}
-#endif
-
-	g_context.isInitialized = true;
-
-	// Obtain maximum texture size.
-	GL_CALL(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &g_context.maxTextureSize));
-	debug(5, "OpenGL maximum texture size: %d", g_context.maxTextureSize);
-
-	const char *verString = (const char *)glGetString(GL_VERSION);
-	debug(5, "OpenGL version: %s", verString);
-
-	if (g_context.type == kContextGL) {
-		// OpenGL version number is either of the form major.minor or major.minor.release,
-		// where the numbers all have one or more digits
-		if (sscanf(verString, "%d.%d", &g_context.majorVersion, &g_context.minorVersion) != 2) {
-			g_context.majorVersion = g_context.minorVersion = 0;
-			warning("Could not parse GL version '%s'", verString);
-		}
-	} else if (g_context.type == kContextGLES) {
-		// The form of the string is "OpenGL ES-<profile> <major>.<minor>",
-		// where <profile> is either "CM" (Common) or "CL" (Common-Lite),
-		// and <major> and <minor> are integers.
-		char profile[3];
-		if (sscanf(verString, "OpenGL ES-%2s %d.%d", profile,
-					&g_context.majorVersion, &g_context.minorVersion) != 3) {
-			g_context.majorVersion = g_context.minorVersion = 0;
-			warning("Could not parse GL ES version '%s'", verString);
-		}
-	} else if (g_context.type == kContextGLES2) {
-		// The version is of the form
-		// OpenGL<space>ES<space><version number><space><vendor-specific information>
-		// version number format is not defined
-		// There is only OpenGL ES 2.0 anyway
-		if (sscanf(verString, "OpenGL ES %d.%d", &g_context.majorVersion, &g_context.minorVersion) != 2) {
-			g_context.minorVersion = 0;
-			if (sscanf(verString, "OpenGL ES %d ", &g_context.majorVersion) != 1) {
-				g_context.majorVersion = 0;
-				warning("Could not parse GL ES 2 version '%s'", verString);
-			}
-		}
-	}
-
-	const char *extString = (const char *)glGetString(GL_EXTENSIONS);
-	debug(5, "OpenGL extensions: %s", extString);
-
-	bool ARBShaderObjects = false;
-	bool ARBShadingLanguage100 = false;
-	bool ARBVertexShader = false;
-	bool ARBFragmentShader = false;
-
-	Common::StringTokenizer tokenizer(extString, " ");
-	while (!tokenizer.empty()) {
-		Common::String token = tokenizer.nextToken();
-
-		if (token == "GL_ARB_texture_non_power_of_two" || token == "GL_OES_texture_npot") {
-			g_context.NPOTSupported = true;
-		} else if (token == "GL_ARB_shader_objects") {
-			ARBShaderObjects = true;
-		} else if (token == "GL_ARB_shading_language_100") {
-			ARBShadingLanguage100 = true;
-		} else if (token == "GL_ARB_vertex_shader") {
-			ARBVertexShader = true;
-		} else if (token == "GL_ARB_fragment_shader") {
-			ARBFragmentShader = true;
-		} else if (token == "GL_ARB_multitexture") {
-			g_context.multitextureSupported = true;
-		} else if (token == "GL_ARB_framebuffer_object") {
-			g_context.framebufferObjectSupported = true;
-		} else if (token == "GL_EXT_packed_pixels" || token == "GL_APPLE_packed_pixels") {
-			g_context.packedPixelsSupported = true;
-		} else if (token == "GL_SGIS_texture_edge_clamp") {
-			g_context.textureEdgeClampSupported = true;
-		}
-	}
-
-	if (g_context.type == kContextGLES2) {
-		// GLES2 always has (limited) NPOT support.
-		g_context.NPOTSupported = true;
-
-		// GLES2 always has shader support.
-		g_context.shadersSupported = true;
-
-		// GLES2 always has multi texture support.
-		g_context.multitextureSupported = true;
-
-		// GLES2 always has FBO support.
-		g_context.framebufferObjectSupported = true;
-	} else {
-		g_context.shadersSupported = ARBShaderObjects & ARBShadingLanguage100 & ARBVertexShader & ARBFragmentShader;
-	}
-
-	// OpenGL 1.2 and later always has packed pixels and texture edge clamp support
-	if (g_context.type != kContextGL || g_context.isGLVersionOrHigher(1, 2)) {
-		g_context.packedPixelsSupported = true;
-		g_context.textureEdgeClampSupported = true;
-	}
-
-	// Log context type.
-	switch (g_context.type) {
-	case kContextGL:
-		debug(5, "OpenGL: GL context initialized");
-		break;
-
-	case kContextGLES:
-		debug(5, "OpenGL: GLES context initialized");
-		break;
-
-	case kContextGLES2:
-		debug(5, "OpenGL: GLES2 context initialized");
-		break;
-
-	default:
-		warning("OpenGL: Unknown context initialized");
-		break;
-	}
-
-	// Log features supported by GL context.
-#if !USE_FORCED_GLES
-	if (g_context.shadersSupported)
-		debug(5, "GLSL version: %s", glGetString(GL_SHADING_LANGUAGE_VERSION));
-#endif
-	debug(5, "OpenGL vendor: %s", glGetString(GL_VENDOR));
-	debug(5, "OpenGL renderer: %s", glGetString(GL_RENDERER));
-	debug(5, "OpenGL: NPOT texture support: %d", g_context.NPOTSupported);
-	debug(5, "OpenGL: Shader support: %d", g_context.shadersSupported);
-	debug(5, "OpenGL: Multitexture support: %d", g_context.multitextureSupported);
-	debug(5, "OpenGL: FBO support: %d", g_context.framebufferObjectSupported);
-	debug(5, "OpenGL: Packed pixels support: %d", g_context.packedPixelsSupported);
-	debug(5, "OpenGL: Texture edge clamping support: %d", g_context.textureEdgeClampSupported);
-}
-
-} // End of namespace OpenGL
diff --git a/backends/graphics/opengl/debug.cpp b/backends/graphics/opengl/debug.cpp
index 3dd45ef6201..91f11862596 100644
--- a/backends/graphics/opengl/debug.cpp
+++ b/backends/graphics/opengl/debug.cpp
@@ -20,11 +20,12 @@
  */
 
 #include "backends/graphics/opengl/debug.h"
-#include "backends/graphics/opengl/opengl-sys.h"
 
 #include "common/str.h"
 #include "common/textconsole.h"
 
+#include "graphics/opengl/system_headers.h"
+
 #ifdef OPENGL_DEBUG
 
 namespace OpenGL {
diff --git a/backends/graphics/opengl/debug.h b/backends/graphics/opengl/debug.h
index faea50441ef..e2d3cc2d2a4 100644
--- a/backends/graphics/opengl/debug.h
+++ b/backends/graphics/opengl/debug.h
@@ -22,6 +22,8 @@
 #ifndef BACKENDS_GRAPHICS_OPENGL_DEBUG_H
 #define BACKENDS_GRAPHICS_OPENGL_DEBUG_H
 
+#include "graphics/opengl/context.h"
+
 #define OPENGL_DEBUG
 
 #ifdef OPENGL_DEBUG
@@ -35,4 +37,13 @@ void checkGLError(const char *expr, const char *file, int line);
 #define GL_WRAP_DEBUG(call, name) do { (call); } while (false)
 #endif
 
+#define GL_CALL(x)                 GL_WRAP_DEBUG(x, x)
+#define GL_CALL_SAFE(func, params) \
+	do { \
+		if (OpenGLContext.type != kContextNone) { \
+			GL_CALL(func params); \
+		} \
+	} while (0)
+#define GL_ASSIGN(var, x)          GL_WRAP_DEBUG(var = x, x)
+
 #endif
diff --git a/backends/graphics/opengl/framebuffer.cpp b/backends/graphics/opengl/framebuffer.cpp
index 6692efb3913..a8e4f758ddb 100644
--- a/backends/graphics/opengl/framebuffer.cpp
+++ b/backends/graphics/opengl/framebuffer.cpp
@@ -19,6 +19,7 @@
  *
  */
 
+#include "backends/graphics/opengl/debug.h"
 #include "backends/graphics/opengl/framebuffer.h"
 #include "backends/graphics/opengl/texture.h"
 #include "backends/graphics/opengl/pipelines/pipeline.h"
@@ -96,7 +97,7 @@ void Framebuffer::applyViewport() {
 }
 
 void Framebuffer::applyProjectionMatrix() {
-	g_context.getActivePipeline()->setProjectionMatrix(_projectionMatrix);
+	Pipeline::getActivePipeline()->setProjectionMatrix(_projectionMatrix);
 }
 
 void Framebuffer::applyClearColor() {
@@ -139,7 +140,7 @@ void Framebuffer::applyScissorBox() {
 
 void Backbuffer::activateInternal() {
 #if !USE_FORCED_GLES
-	if (g_context.framebufferObjectSupported) {
+	if (OpenGLContext.framebufferObjectSupported) {
 		GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
 	}
 #endif
diff --git a/backends/graphics/opengl/framebuffer.h b/backends/graphics/opengl/framebuffer.h
index 896af84cb3c..f29fdd2b36d 100644
--- a/backends/graphics/opengl/framebuffer.h
+++ b/backends/graphics/opengl/framebuffer.h
@@ -22,7 +22,7 @@
 #ifndef BACKENDS_GRAPHICS_OPENGL_FRAMEBUFFER_H
 #define BACKENDS_GRAPHICS_OPENGL_FRAMEBUFFER_H
 
-#include "backends/graphics/opengl/opengl-sys.h"
+#include "graphics/opengl/system_headers.h"
 
 namespace OpenGL {
 
diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index 1e8aae83655..3d41e94d978 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -21,6 +21,7 @@
 
 
 #include "backends/graphics/opengl/opengl-graphics.h"
+#include "backends/graphics/opengl/debug.h"
 #include "backends/graphics/opengl/texture.h"
 #include "backends/graphics/opengl/pipelines/pipeline.h"
 #include "backends/graphics/opengl/pipelines/fixed.h"
@@ -79,7 +80,7 @@ OpenGLGraphicsManager::OpenGLGraphicsManager()
 #endif
 	{
 	memset(_gamePalette, 0, sizeof(_gamePalette));
-	g_context.reset();
+	OpenGLContext.reset();
 }
 
 OpenGLGraphicsManager::~OpenGLGraphicsManager() {
@@ -391,8 +392,8 @@ OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() {
 		   // a context existing before, which means we don't know the maximum
 		   // supported texture size before this. Thus, we check whether the
 		   // requested game resolution is supported over here.
-		   || (   _currentState.gameWidth  > (uint)g_context.maxTextureSize
-		       || _currentState.gameHeight > (uint)g_context.maxTextureSize)) {
+		   || (   _currentState.gameWidth  > (uint)OpenGLContext.maxTextureSize
+		       || _currentState.gameHeight > (uint)OpenGLContext.maxTextureSize)) {
 			if (_transactionMode == kTransactionActive) {
 				// Try to setup the old state in case its valid and is
 				// actually different from the new one.
@@ -587,21 +588,21 @@ void OpenGLGraphicsManager::updateScreen() {
 	_backBuffer.enableBlend(Framebuffer::kBlendModeDisabled);
 
 	// First step: Draw the (virtual) game screen.
-	g_context.getActivePipeline()->drawTexture(_gameScreen->getGLTexture(), _gameDrawRect.left, _gameDrawRect.top, _gameDrawRect.width(), _gameDrawRect.height());
+	Pipeline::getActivePipeline()->drawTexture(_gameScreen->getGLTexture(), _gameDrawRect.left, _gameDrawRect.top, _gameDrawRect.width(), _gameDrawRect.height());
 
 	// Second step: Draw the overlay if visible.
 	if (_overlayVisible) {
 		int dstX = (_windowWidth - _overlayDrawRect.width()) / 2;
 		int dstY = (_windowHeight - _overlayDrawRect.height()) / 2;
 		_backBuffer.enableBlend(Framebuffer::kBlendModeTraditionalTransparency);
-		g_context.getActivePipeline()->drawTexture(_overlay->getGLTexture(), dstX, dstY, _overlayDrawRect.width(), _overlayDrawRect.height());
+		Pipeline::getActivePipeline()->drawTexture(_overlay->getGLTexture(), dstX, dstY, _overlayDrawRect.width(), _overlayDrawRect.height());
 	}
 
 	// Third step: Draw the cursor if visible.
 	if (_cursorVisible && _cursor) {
 		_backBuffer.enableBlend(Framebuffer::kBlendModePremultipliedTransparency);
 
-		g_context.getActivePipeline()->drawTexture(_cursor->getGLTexture(),
+		Pipeline::getActivePipeline()->drawTexture(_cursor->getGLTexture(),
 		                         _cursorX - _cursorHotspotXScaled + _shakeOffsetScaled.x,
 		                         _cursorY - _cursorHotspotYScaled + _shakeOffsetScaled.y,
 		                         _cursorWidthScaled, _cursorHeightScaled);
@@ -631,17 +632,17 @@ void OpenGLGraphicsManager::updateScreen() {
 		}
 
 		// Set the OSD transparency.
-		g_context.getActivePipeline()->setColor(1.0f, 1.0f, 1.0f, _osdMessageAlpha / 100.0f);
+		Pipeline::getActivePipeline()->setColor(1.0f, 1.0f, 1.0f, _osdMessageAlpha / 100.0f);
 
 		int dstX = (_windowWidth - _osdMessageSurface->getWidth()) / 2;
 		int dstY = (_windowHeight - _osdMessageSurface->getHeight()) / 2;
 
 		// Draw the OSD texture.
-		g_context.getActivePipeline()->drawTexture(_osdMessageSurface->getGLTexture(),
+		Pipeline::getActivePipeline()->drawTexture(_osdMessageSurface->getGLTexture(),
 		                                           dstX, dstY, _osdMessageSurface->getWidth(), _osdMessageSurface->getHeight());
 
 		// Reset color.
-		g_context.getActivePipeline()->setColor(1.0f, 1.0f, 1.0f, 1.0f);
+		Pipeline::getActivePipeline()->setColor(1.0f, 1.0f, 1.0f, 1.0f);
 
 		if (_osdMessageAlpha <= 0) {
 			delete _osdMessageSurface;
@@ -658,7 +659,7 @@ void OpenGLGraphicsManager::updateScreen() {
 		int dstY = kOSDIconTopMargin;
 
 		// Draw the OSD icon texture.
-		g_context.getActivePipeline()->drawTexture(_osdIconSurface->getGLTexture(),
+		Pipeline::getActivePipeline()->drawTexture(_osdIconSurface->getGLTexture(),
 		                                           dstX, dstY, _osdIconSurface->getWidth(), _osdIconSurface->getHeight());
 	}
 #endif
@@ -1019,15 +1020,15 @@ void OpenGLGraphicsManager::handleResizeImpl(const int width, const int height)
 	// possible and then scale it to the physical display size. This sounds
 	// bad but actually all recent chips should support full HD resolution
 	// anyway. Thus, it should not be a real issue for modern hardware.
-	if (   overlayWidth  > (uint)g_context.maxTextureSize
-	    || overlayHeight > (uint)g_context.maxTextureSize) {
+	if (   overlayWidth  > (uint)OpenGLContext.maxTextureSize
+	    || overlayHeight > (uint)OpenGLContext.maxTextureSize) {
 		const frac_t outputAspect = intToFrac(_windowWidth) / _windowHeight;
 
 		if (outputAspect > (frac_t)FRAC_ONE) {
-			overlayWidth  = g_context.maxTextureSize;
+			overlayWidth  = OpenGLContext.maxTextureSize;
 			overlayHeight = intToFrac(overlayWidth) / outputAspect;
 		} else {
-			overlayHeight = g_context.maxTextureSize;
+			overlayHeight = OpenGLContext.maxTextureSize;
 			overlayWidth  = fracToInt(overlayHeight * outputAspect);
 		}
 	}
@@ -1065,16 +1066,17 @@ void OpenGLGraphicsManager::handleResizeImpl(const int width, const int height)
 	++_screenChangeID;
 }
 
-void OpenGLGraphicsManager::notifyContextCreate(const Graphics::PixelFormat &defaultFormat, const Graphics::PixelFormat &defaultFormatAlpha) {
-	// Initialize context for use.
-	initializeGLContext();
-
+void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
+	const Graphics::PixelFormat &defaultFormat,
+	const Graphics::PixelFormat &defaultFormatAlpha) {
 	// Initialize pipeline.
 	delete _pipeline;
 	_pipeline = nullptr;
 
+	OpenGLContext.initialize(type);
+
 #if !USE_FORCED_GLES
-	if (g_context.shadersSupported) {
+	if (OpenGLContext.shadersSupported) {
 		ShaderMan.notifyCreate();
 		_pipeline = new ShaderPipeline(ShaderMan.query(ShaderManager::kDefault));
 	}
@@ -1086,21 +1088,21 @@ void OpenGLGraphicsManager::notifyContextCreate(const Graphics::PixelFormat &def
 	}
 #endif
 
-	g_context.setPipeline(_pipeline);
+	Pipeline::setPipeline(_pipeline);
 
 	// Disable 3D properties.
 	GL_CALL(glDisable(GL_CULL_FACE));
 	GL_CALL(glDisable(GL_DEPTH_TEST));
 	GL_CALL(glDisable(GL_DITHER));
 
-	g_context.getActivePipeline()->setColor(1.0f, 1.0f, 1.0f, 1.0f);
+	Pipeline::getActivePipeline()->setColor(1.0f, 1.0f, 1.0f, 1.0f);
 
 	// Setup backbuffer state.
 
 	// Default to black as clear color.
 	_backBuffer.setClearColor(0.0f, 0.0f, 0.0f, 0.0f);
 
-	g_context.getActivePipeline()->setFramebuffer(&_backBuffer);
+	Pipeline::getActivePipeline()->setFramebuffer(&_backBuffer);
 
 	// We use a "pack" alignment (when reading from textures) to 4 here,
 	// since the only place where we really use it is the BMP screenshot
@@ -1165,18 +1167,18 @@ void OpenGLGraphicsManager::notifyContextDestroy() {
 #endif
 
 #if !USE_FORCED_GLES
-	if (g_context.shadersSupported) {
+	if (OpenGLContext.shadersSupported) {
 		ShaderMan.notifyDestroy();
 	}
 #endif
 
 	// Destroy rendering pipeline.
-	g_context.setPipeline(nullptr);
+	Pipeline::setPipeline(nullptr);
 	delete _pipeline;
 	_pipeline = nullptr;
 
 	// Rest our context description since the context is gone soon.
-	g_context.reset();
+	OpenGLContext.reset();
 }
 
 Surface *OpenGLGraphicsManager::createSurface(const Graphics::PixelFormat &format, bool wantAlpha, bool wantScaler) {
@@ -1213,7 +1215,7 @@ Surface *OpenGLGraphicsManager::createSurface(const Graphics::PixelFormat &forma
 		}
 	} else if (getGLPixelFormat(format, glIntFormat, glFormat, glType)) {
 		return new Texture(glIntFormat, glFormat, glType, format);
-	} else if (g_context.packedPixelsSupported && format == Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)) {
+	} else if (OpenGLContext.packedPixelsSupported && format == Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)) {
 		// OpenGL ES does not support a texture format usable for RGB555.
 		// Since SCUMM uses this pixel format for some games (and there is no
 		// hope for this to change anytime soon) we use pixel format
@@ -1244,7 +1246,7 @@ bool OpenGLGraphicsManager::getGLPixelFormat(const Graphics::PixelFormat &pixelF
 		glFormat = GL_RGBA;
 		glType = GL_UNSIGNED_BYTE;
 		return true;
-	} else if (!g_context.packedPixelsSupported) {
+	} else if (!OpenGLContext.packedPixelsSupported) {
 		return false;
 	} else if (pixelFormat == Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)) { // RGB565
 		glIntFormat = GL_RGB;
diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h
index 5ff7ebbbaaa..f3d30f04555 100644
--- a/backends/graphics/opengl/opengl-graphics.h
+++ b/backends/graphics/opengl/opengl-graphics.h
@@ -22,7 +22,6 @@
 #ifndef BACKENDS_GRAPHICS_OPENGL_OPENGL_GRAPHICS_H
 #define BACKENDS_GRAPHICS_OPENGL_OPENGL_GRAPHICS_H
 
-#include "backends/graphics/opengl/opengl-sys.h"
 #include "backends/graphics/opengl/framebuffer.h"
 #include "backends/graphics/windowed.h"
 
@@ -130,28 +129,22 @@ protected:
 	/**
 	 * Whether an GLES or GLES2 context is active.
 	 */
-	bool isGLESContext() const { return g_context.type == kContextGLES || g_context.type == kContextGLES2; }
-
-	/**
-	 * Sets the OpenGL (ES) type the graphics manager shall work with.
-	 *
-	 * This needs to be called at least once (and before ever calling
-	 * notifyContextCreate).
-	 *
-	 * @param type Type of the OpenGL (ES) contexts to be created.
-	 */
-	void setContextType(ContextType type);
+	bool isGLESContext() const { return OpenGLContext.type == kContextGLES || OpenGLContext.type == kContextGLES2; }
 
 	/**
 	 * Notify the manager of a OpenGL context change. This should be the first
 	 * thing to call after you created an OpenGL (ES) context!
 	 *
+	 * @param type               Type of the OpenGL (ES) contexts created.
 	 * @param defaultFormat      The new default format for the game screen
 	 *                           (this is used for the CLUT8 game screens).
 	 * @param defaultFormatAlpha The new default format with an alpha channel
 	 *                           (this is used for the overlay and cursor).
 	 */
-	void notifyContextCreate(const Graphics::PixelFormat &defaultFormat, const Graphics::PixelFormat &defaultFormatAlpha);
+	void notifyContextCreate(
+			ContextType type,
+			const Graphics::PixelFormat &defaultFormat,
+			const Graphics::PixelFormat &defaultFormatAlpha);
 
 	/**
 	 * Notify the manager that the OpenGL context is about to be destroyed.
@@ -300,20 +293,6 @@ private:
 	 */
 	Pipeline *_pipeline;
 
-public:
-	/**
-	 * Query the address of an OpenGL function by name.
-	 *
-	 * This can only be used after a context has been created.
-	 * Please note that this function can return valid addresses even if the
-	 * OpenGL context does not support the function.
-	 *
-	 * @param name The name of the OpenGL function.
-	 * @return An function pointer for the requested OpenGL function or
-	 *         nullptr in case of failure.
-	 */
-	virtual void *getProcAddress(const char *name) const = 0;
-
 protected:
 	/**
 	 * Try to determine the internal parameters for a given pixel format.
diff --git a/backends/graphics/opengl/opengl-sys.h b/backends/graphics/opengl/opengl-sys.h
deleted file mode 100644
index b27dcbde6ae..00000000000
--- a/backends/graphics/opengl/opengl-sys.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/* 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 3 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, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef BACKENDS_GRAPHICS_OPENGL_OPENGL_SYS_H
-#define BACKENDS_GRAPHICS_OPENGL_OPENGL_SYS_H
-
-#include "common/scummsys.h"
-#include "graphics/opengl/system_headers.h"
-
-#include "backends/graphics/opengl/debug.h"
-
-// This is an addition from us to alias ARB shader object extensions to
-// OpenGL (ES) 2.0 style functions. It only works when GLhandleARB and GLuint
-// are type compatible.
-typedef GLuint GLprogram;
-typedef GLuint GLshader;
-
-namespace OpenGL {
-
-enum ContextType {
-	kContextGL,
-	kContextGLES,
-	kContextGLES2
-};
-
-class Pipeline;
-class Framebuffer;
-
-/**
- * Description structure of the OpenGL (ES) context.
- */
-struct Context {
-	/** The type of the active context. */
-	ContextType type;
-
-	/** Whether the context is initialized or not. */
-	bool isInitialized;
-
-	/**
-	 * Reset context.
-	 *
-	 * This marks all extensions as unavailable and clears all function
-	 * pointers.
-	 */
-	void reset();
-
-	/** Helper function for checking the GL version supported by the context. */
-	inline bool isGLVersionOrHigher(int major, int minor) {
-		return ((majorVersion > major) || ((majorVersion == major) && (minorVersion >= minor)));
-	}
-
-	/** The GL version supported by the context. */
-	int majorVersion, minorVersion;
-
-	/** The maximum texture size supported by the context. */
-	GLint maxTextureSize;
-
-	/** Whether GL_ARB_texture_non_power_of_two is available or not. */
-	bool NPOTSupported;
-
-	/** Whether shader support is available or not. */
-	bool shadersSupported;
-
-	/** Whether multi texture support is available or not. */
-	bool multitextureSupported;
-
-	/** Whether FBO support is available or not. */
-	bool framebufferObjectSupported;
-
-	/** Whether packed pixels support is available or not. */
-	bool packedPixelsSupported;
-
-	/** Whether texture coordinate edge clamping is available or not. */
-	bool textureEdgeClampSupported;
-
-	//
-	// Wrapper functionality to handle fixed-function pipelines and
-	// programmable pipelines in the same fashion.
-	//
-
-private:
-	/** Currently active rendering pipeline. */
-	Pipeline *activePipeline;
-
-public:
-	/**
-	 * Set new pipeline.
-	 *
-	 * Client is responsible for any memory management related to pipelines.
-	 *
-	 * @param pipeline Pipeline to activate.
-	 * @return Formerly active pipeline.
-	 */
-	Pipeline *setPipeline(Pipeline *pipeline);
-
-	/**
-	 * Query the currently active rendering pipeline.
-	 */
-	Pipeline *getActivePipeline() const { return activePipeline; }
-};
-
-/**
- * The (active) OpenGL context.
- */
-extern Context g_context;
-
-} // End of namespace OpenGL
-
-#define GL_CALL(x)                 GL_WRAP_DEBUG(x, x)
-#define GL_CALL_SAFE(func, params) \
-	do { \
-		if (g_context.isInitialized) { \
-			GL_CALL(func params); \
-		} \
-	} while (0)
-#define GL_ASSIGN(var, x)          GL_WRAP_DEBUG(var = x, x)
-
-#endif
diff --git a/backends/graphics/opengl/pipelines/clut8.cpp b/backends/graphics/opengl/pipelines/clut8.cpp
index 5f2db578b3f..dc4732e4f27 100644
--- a/backends/graphics/opengl/pipelines/clut8.cpp
+++ b/backends/graphics/opengl/pipelines/clut8.cpp
@@ -20,6 +20,7 @@
  */
 
 #include "backends/graphics/opengl/pipelines/clut8.h"
+#include "backends/graphics/opengl/debug.h"
 #include "backends/graphics/opengl/shader.h"
 #include "backends/graphics/opengl/framebuffer.h"
 
diff --git a/backends/graphics/opengl/pipelines/fixed.cpp b/backends/graphics/opengl/pipelines/fixed.cpp
index bac928374d2..edf4ce6ddc7 100644
--- a/backends/graphics/opengl/pipelines/fixed.cpp
+++ b/backends/graphics/opengl/pipelines/fixed.cpp
@@ -20,6 +20,7 @@
  */
 
 #include "backends/graphics/opengl/pipelines/fixed.h"
+#include "backends/graphics/opengl/debug.h"
 
 namespace OpenGL {
 
@@ -34,7 +35,7 @@ void FixedPipeline::activateInternal() {
 	GL_CALL(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
 
 #if !USE_FORCED_GLES
-	if (g_context.multitextureSupported) {
+	if (OpenGLContext.multitextureSupported) {
 		GL_CALL(glActiveTexture(GL_TEXTURE0));
 	}
 #endif
diff --git a/backends/graphics/opengl/pipelines/pipeline.cpp b/backends/graphics/opengl/pipelines/pipeline.cpp
index d20e25c6102..815d93924f6 100644
--- a/backends/graphics/opengl/pipelines/pipeline.cpp
+++ b/backends/graphics/opengl/pipelines/pipeline.cpp
@@ -24,6 +24,8 @@
 
 namespace OpenGL {
 
+Pipeline *Pipeline::activePipeline = nullptr;
+
 Pipeline::Pipeline()
 	: _activeFramebuffer(nullptr), _isActive(false) {
 }
@@ -62,4 +64,18 @@ Framebuffer *Pipeline::setFramebuffer(Framebuffer *framebuffer) {
 	return oldFramebuffer;
 }
 
+Pipeline *Pipeline::setPipeline(Pipeline *pipeline) {
+	Pipeline *oldPipeline = activePipeline;
+	if (oldPipeline) {
+		oldPipeline->deactivate();
+	}
+
+	activePipeline = pipeline;
+	if (activePipeline) {
+		activePipeline->activate();
+	}
+
+	return oldPipeline;
+}
+
 } // End of namespace OpenGL
diff --git a/backends/graphics/opengl/pipelines/pipeline.h b/backends/graphics/opengl/pipelines/pipeline.h
index 53782476f59..ee16d63f96a 100644
--- a/backends/graphics/opengl/pipelines/pipeline.h
+++ b/backends/graphics/opengl/pipelines/pipeline.h
@@ -22,7 +22,8 @@
 #ifndef BACKENDS_GRAPHICS_OPENGL_PIPELINES_PIPELINE_H
 #define BACKENDS_GRAPHICS_OPENGL_PIPELINES_PIPELINE_H
 
-#include "backends/graphics/opengl/opengl-sys.h"
+#include "graphics/opengl/system_headers.h"
+
 #include "backends/graphics/opengl/texture.h"
 
 namespace OpenGL {
@@ -148,6 +149,25 @@ protected:
 
 private:
 	bool _isActive;
+
+	/** Currently active rendering pipeline. */
+	static Pipeline *activePipeline;
+
+public:
+	/**
+	 * Set new pipeline.
+	 *
+	 * Client is responsible for any memory management related to pipelines.
+	 *
+	 * @param pipeline Pipeline to activate.
+	 * @return Formerly active pipeline.
+	 */
+	static Pipeline *setPipeline(Pipeline *pipeline);
+
+	/**
+	 * Query the currently active rendering pipeline.
+	 */
+	static Pipeline *getActivePipeline() { return activePipeline; }
 };
 
 } // End of namespace OpenGL
diff --git a/backends/graphics/opengl/pipelines/shader.cpp b/backends/graphics/opengl/pipelines/shader.cpp
index d9e6c64ceb8..8905701c608 100644
--- a/backends/graphics/opengl/pipelines/shader.cpp
+++ b/backends/graphics/opengl/pipelines/shader.cpp
@@ -20,6 +20,7 @@
  */
 
 #include "backends/graphics/opengl/pipelines/shader.h"
+#include "backends/graphics/opengl/debug.h"
 #include "backends/graphics/opengl/shader.h"
 #include "backends/graphics/opengl/framebuffer.h"
 
@@ -50,7 +51,7 @@ void ShaderPipeline::activateInternal() {
 	GL_CALL(glEnableVertexAttribArray(_texCoordAttribLocation));
 	GL_CALL(glEnableVertexAttribArray(_colorAttribLocation));
 
-	if (g_context.multitextureSupported) {
+	if (OpenGLContext.multitextureSupported) {
 		GL_CALL(glActiveTexture(GL_TEXTURE0));
 	}
 
diff --git a/backends/graphics/opengl/shader.cpp b/backends/graphics/opengl/shader.cpp
index 2f36a9ce820..4fb7f1f5b36 100644
--- a/backends/graphics/opengl/shader.cpp
+++ b/backends/graphics/opengl/shader.cpp
@@ -20,9 +20,9 @@
  */
 
 #include "backends/graphics/opengl/shader.h"
+#include "backends/graphics/opengl/debug.h"
 
 #if !USE_FORCED_GLES
-
 #include "common/textconsole.h"
 #include "common/util.h"
 
@@ -252,7 +252,7 @@ bool Shader::setUniform(const Common::String &name, ShaderUniformValue *value) {
 }
 
 GLshader Shader::compileShader(const char *source, GLenum shaderType) {
-	const GLchar *versionSource = g_context.type == kContextGLES2 ? "#version 100\n" : "#version 110\n";
+	const GLchar *versionSource = OpenGLContext.type == kContextGLES2 ? "#version 100\n" : "#version 110\n";
 	const GLchar *compatSource = shaderType == GL_VERTEX_SHADER ? "" : g_precisionDefines;
 
 	GLshader handle;
diff --git a/backends/graphics/opengl/shader.h b/backends/graphics/opengl/shader.h
index d534692d360..5395dfbba59 100644
--- a/backends/graphics/opengl/shader.h
+++ b/backends/graphics/opengl/shader.h
@@ -22,7 +22,7 @@
 #ifndef BACKENDS_GRAPHICS_OPENGL_SHADER_H
 #define BACKENDS_GRAPHICS_OPENGL_SHADER_H
 
-#include "backends/graphics/opengl/opengl-sys.h"
+#include "graphics/opengl/system_headers.h"
 
 #if !USE_FORCED_GLES
 
@@ -30,6 +30,12 @@
 #include "common/hash-str.h"
 #include "common/ptr.h"
 
+// This is an addition from us to alias ARB shader object extensions to
+// OpenGL (ES) 2.0 style functions. It only works when GLhandleARB and GLuint
+// are type compatible.
+typedef GLuint GLprogram;
+typedef GLuint GLshader;
+
 namespace OpenGL {
 
 /**
diff --git a/backends/graphics/opengl/texture.cpp b/backends/graphics/opengl/texture.cpp
index 0371ed45360..32a9ad0d94e 100644
--- a/backends/graphics/opengl/texture.cpp
+++ b/backends/graphics/opengl/texture.cpp
@@ -20,6 +20,7 @@
  */
 
 #include "backends/graphics/opengl/texture.h"
+#include "backends/graphics/opengl/debug.h"
 #include "backends/graphics/opengl/shader.h"
 #include "backends/graphics/opengl/pipelines/pipeline.h"
 #include "backends/graphics/opengl/pipelines/clut8.h"
@@ -80,7 +81,7 @@ void GLTexture::create() {
 	GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
 	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _glFilter));
 	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _glFilter));
-	if (g_context.textureEdgeClampSupported) {
+	if (OpenGLContext.textureEdgeClampSupported) {
 		GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
 		GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
 	} else {
@@ -106,7 +107,7 @@ void GLTexture::setSize(uint width, uint height) {
 	const uint oldWidth  = _width;
 	const uint oldHeight = _height;
 
-	if (!g_context.NPOTSupported) {
+	if (!OpenGLContext.NPOTSupported) {
 		_width  = Common::nextHigher2(width);
 		_height = Common::nextHigher2(height);
 	} else {
@@ -734,13 +735,13 @@ void TextureCLUT8GPU::updateGLTexture() {
 
 void TextureCLUT8GPU::lookUpColors() {
 	// Setup pipeline to do color look up.
-	Pipeline *oldPipeline = g_context.setPipeline(_clut8Pipeline);
+	Pipeline *oldPipeline = Pipeline::setPipeline(_clut8Pipeline);
 
 	// Do color look up.
-	g_context.getActivePipeline()->drawTexture(_clut8Texture, _clut8Vertices);
+	Pipeline::getActivePipeline()->drawTexture(_clut8Texture, _clut8Vertices);
 
 	// Restore old state.
-	g_context.setPipeline(oldPipeline);
+	Pipeline::setPipeline(oldPipeline);
 }
 #endif // !USE_FORCED_GLES
 
diff --git a/backends/graphics/opengl/texture.h b/backends/graphics/opengl/texture.h
index 22ef603b8cd..95a1aa47447 100644
--- a/backends/graphics/opengl/texture.h
+++ b/backends/graphics/opengl/texture.h
@@ -22,7 +22,8 @@
 #ifndef BACKENDS_GRAPHICS_OPENGL_TEXTURE_H
 #define BACKENDS_GRAPHICS_OPENGL_TEXTURE_H
 
-#include "backends/graphics/opengl/opengl-sys.h"
+#include "graphics/opengl/system_headers.h"
+#include "graphics/opengl/context.h"
 
 #include "graphics/pixelformat.h"
 #include "graphics/surface.h"
@@ -405,9 +406,9 @@ public:
 	virtual const GLTexture &getGLTexture() const;
 
 	static bool isSupportedByContext() {
-		return g_context.shadersSupported
-		    && g_context.multitextureSupported
-		    && g_context.framebufferObjectSupported;
+		return OpenGLContext.shadersSupported
+		    && OpenGLContext.multitextureSupported
+		    && OpenGLContext.framebufferObjectSupported;
 	}
 private:
 	void lookUpColors();
diff --git a/backends/graphics/openglsdl/openglsdl-graphics.cpp b/backends/graphics/openglsdl/openglsdl-graphics.cpp
index 3dc643d388d..3379df37028 100644
--- a/backends/graphics/openglsdl/openglsdl-graphics.cpp
+++ b/backends/graphics/openglsdl/openglsdl-graphics.cpp
@@ -49,8 +49,6 @@ OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(SdlEventSource *eventSource,
 
 	// Set up proper SDL OpenGL context creation.
 #if SDL_VERSION_ATLEAST(2, 0, 0)
-	OpenGL::ContextType glContextType;
-
 	// Context version 1.4 is choosen arbitrarily based on what most shader
 	// extensions were written against.
 	enum {
@@ -65,17 +63,17 @@ OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(SdlEventSource *eventSource,
 	};
 
 #if USE_FORCED_GL
-	glContextType = OpenGL::kContextGL;
+	_glContextType = OpenGL::kContextGL;
 	_glContextProfileMask = 0;
 	_glContextMajor = DEFAULT_GL_MAJOR;
 	_glContextMinor = DEFAULT_GL_MINOR;
 #elif USE_FORCED_GLES
-	glContextType = OpenGL::kContextGLES;
+	_glContextType = OpenGL::kContextGLES;
 	_glContextProfileMask = SDL_GL_CONTEXT_PROFILE_ES;
 	_glContextMajor = DEFAULT_GLES_MAJOR;
 	_glContextMinor = DEFAULT_GLES_MINOR;
 #elif USE_FORCED_GLES2
-	glContextType = OpenGL::kContextGLES2;
+	_glContextType = OpenGL::kContextGLES2;
 	_glContextProfileMask = SDL_GL_CONTEXT_PROFILE_ES;
 	_glContextMajor = DEFAULT_GLES2_MAJOR;
 	_glContextMinor = DEFAULT_GLES2_MINOR;
@@ -115,12 +113,12 @@ OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(SdlEventSource *eventSource,
 
 	if (_glContextProfileMask == SDL_GL_CONTEXT_PROFILE_ES) {
 		if (_glContextMajor >= 2) {
-			glContextType = OpenGL::kContextGLES2;
+			_glContextType = OpenGL::kContextGLES2;
 		} else {
-			glContextType = OpenGL::kContextGLES;
+			_glContextType = OpenGL::kContextGLES;
 		}
 	} else if (_glContextProfileMask == SDL_GL_CONTEXT_PROFILE_CORE) {
-		glContextType = OpenGL::kContextGL;
+		_glContextType = OpenGL::kContextGL;
 
 		// Core profile does not allow legacy functionality, which we use.
 		// Thus we request a standard OpenGL context.
@@ -128,13 +126,11 @@ OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(SdlEventSource *eventSource,
 		_glContextMajor = DEFAULT_GL_MAJOR;
 		_glContextMinor = DEFAULT_GL_MINOR;
 	} else {
-		glContextType = OpenGL::kContextGL;
+		_glContextType = OpenGL::kContextGL;
 	}
 #endif
-
-	setContextType(glContextType);
 #else
-	setContextType(OpenGL::kContextGL);
+	_glContextType = OpenGL::kContextGL;
 #endif
 
 	// Retrieve a list of working fullscreen modes
@@ -426,10 +422,6 @@ void OpenGLSdlGraphicsManager::refreshScreen() {
 #endif
 }
 
-void *OpenGLSdlGraphicsManager::getProcAddress(const char *name) const {
-	return SDL_GL_GetProcAddress(name);
-}
-
 void OpenGLSdlGraphicsManager::handleResizeImpl(const int width, const int height) {
 	OpenGLGraphicsManager::handleResizeImpl(width, height);
 	SdlGraphicsManager::handleResizeImpl(width, height);
@@ -550,7 +542,7 @@ bool OpenGLSdlGraphicsManager::setupMode(uint width, uint height) {
 	}
 #endif
 
-	notifyContextCreate(rgba8888, rgba8888);
+	notifyContextCreate(_glContextType, rgba8888, rgba8888);
 	int actualWidth, actualHeight;
 	getWindowSizeFromSdl(&actualWidth, &actualHeight);
 
@@ -617,7 +609,7 @@ bool OpenGLSdlGraphicsManager::setupMode(uint width, uint height) {
 	_lastVideoModeLoad = SDL_GetTicks();
 
 	if (_hwScreen) {
-		notifyContextCreate(rgba8888, rgba8888);
+		notifyContextCreate(_glContextType, rgba8888, rgba8888);
 		handleResize(_hwScreen->w, _hwScreen->h);
 	}
 
diff --git a/backends/graphics/openglsdl/openglsdl-graphics.h b/backends/graphics/openglsdl/openglsdl-graphics.h
index d12ad471909..32305e40190 100644
--- a/backends/graphics/openglsdl/openglsdl-graphics.h
+++ b/backends/graphics/openglsdl/openglsdl-graphics.h
@@ -55,8 +55,6 @@ protected:
 
 	void refreshScreen() override;
 
-	void *getProcAddress(const char *name) const override;
-
 	void handleResizeImpl(const int width, const int height) override;
 
 	bool saveScreenshot(const Common::String &filename) const override;
@@ -66,10 +64,12 @@ private:
 
 #if SDL_VERSION_ATLEAST(2, 0, 0)
 	int _glContextProfileMask, _glContextMajor, _glContextMinor;
+
 	SDL_GLContext _glContext;
 #else
 	uint32 _lastVideoModeLoad;
 #endif
+	OpenGL::ContextType _glContextType;
 
 	uint _lastRequestedWidth;
 	uint _lastRequestedHeight;
diff --git a/backends/graphics3d/android/android-graphics3d.cpp b/backends/graphics3d/android/android-graphics3d.cpp
index 9203401ea51..8f56b0d1e3c 100644
--- a/backends/graphics3d/android/android-graphics3d.cpp
+++ b/backends/graphics3d/android/android-graphics3d.cpp
@@ -171,7 +171,7 @@ void AndroidGraphics3dManager::initSurface() {
 	_screenChangeID = JNI::surface_changeid;
 
 	// Initialize OpenGLES context.
-	OpenGLContext.initialize(OpenGL::kOGLContextGLES2);
+	OpenGLContext.initialize(OpenGL::kContextGLES2);
 	logExtensions();
 	GLESTexture::initGL();
 
@@ -244,7 +244,7 @@ void AndroidGraphics3dManager::deinitSurface() {
 		_touchcontrols_texture->release();
 	}
 
-	OpenGL::ContextGL::destroy();
+	OpenGLContext.reset();
 
 	JNI::deinitSurface();
 }
diff --git a/backends/graphics3d/openglsdl/openglsdl-graphics3d.cpp b/backends/graphics3d/openglsdl/openglsdl-graphics3d.cpp
index 81c172c9a46..89e5f30cbb6 100644
--- a/backends/graphics3d/openglsdl/openglsdl-graphics3d.cpp
+++ b/backends/graphics3d/openglsdl/openglsdl-graphics3d.cpp
@@ -83,7 +83,7 @@ OpenGLSdlGraphics3dManager::OpenGLSdlGraphics3dManager(SdlEventSource *eventSour
 	};
 
 #if USE_FORCED_GLES2
-	_glContextType = OpenGL::kOGLContextGLES2;
+	_glContextType = OpenGL::kContextGLES2;
 	_glContextProfileMask = SDL_GL_CONTEXT_PROFILE_ES;
 	_glContextMajor = DEFAULT_GLES2_MAJOR;
 	_glContextMinor = DEFAULT_GLES2_MINOR;
@@ -123,9 +123,9 @@ OpenGLSdlGraphics3dManager::OpenGLSdlGraphics3dManager(SdlEventSource *eventSour
 
 	if (_glContextProfileMask == SDL_GL_CONTEXT_PROFILE_ES) {
 		// TODO: Support GLES1 for games
-		_glContextType = OpenGL::kOGLContextGLES2;
+		_glContextType = OpenGL::kContextGLES2;
 	} else if (_glContextProfileMask == SDL_GL_CONTEXT_PROFILE_CORE) {
-		_glContextType = OpenGL::kOGLContextGL;
+		_glContextType = OpenGL::kContextGL;
 
 		// Core profile does not allow legacy functionality, which we use.
 		// Thus we request a standard OpenGL context.
@@ -133,11 +133,11 @@ OpenGLSdlGraphics3dManager::OpenGLSdlGraphics3dManager(SdlEventSource *eventSour
 		_glContextMajor = DEFAULT_GL_MAJOR;
 		_glContextMinor = DEFAULT_GL_MINOR;
 	} else {
-		_glContextType = OpenGL::kOGLContextGL;
+		_glContextType = OpenGL::kContextGL;
 	}
 #endif
 #else
-	_glContextType = OpenGL::kOGLContextGL;
+	_glContextType = OpenGL::kContextGL;
 #endif
 }
 
@@ -718,7 +718,7 @@ void OpenGLSdlGraphics3dManager::closeOverlay() {
 	delete _frameBuffer;
 	_frameBuffer = nullptr;
 
-	OpenGL::ContextGL::destroy();
+	OpenGLContext.reset();
 }
 
 int16 OpenGLSdlGraphics3dManager::getOverlayHeight() const {
diff --git a/backends/graphics3d/openglsdl/openglsdl-graphics3d.h b/backends/graphics3d/openglsdl/openglsdl-graphics3d.h
index 7b0ea2dc6b1..59af7fe0f69 100644
--- a/backends/graphics3d/openglsdl/openglsdl-graphics3d.h
+++ b/backends/graphics3d/openglsdl/openglsdl-graphics3d.h
@@ -121,7 +121,7 @@ protected:
 	void deinitializeRenderer();
 #endif
 
-	OpenGL::ContextOGLType _glContextType;
+	OpenGL::ContextType _glContextType;
 
 	bool _supportsFrameBuffer;
 
diff --git a/backends/module.mk b/backends/module.mk
index 2f27ad9e164..e53150eff34 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -123,7 +123,6 @@ endif
 # OpenGL specific source files.
 ifdef USE_OPENGL
 MODULE_OBJS += \
-	graphics/opengl/context.o \
 	graphics/opengl/debug.o \
 	graphics/opengl/framebuffer.o \
 	graphics/opengl/opengl-graphics.o \
diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp
index a8532969706..e947441ebd7 100644
--- a/backends/platform/android/android.cpp
+++ b/backends/platform/android/android.cpp
@@ -121,11 +121,6 @@ void checkGlError(const char *expr, const char *file, int line) {
 }
 #endif
 
-void *androidGLgetProcAddress(const char *name) {
-	// This exists since Android 2.3 (API Level 9)
-	return (void *)eglGetProcAddress(name);
-}
-
 OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) :
 	_audio_sample_rate(audio_sample_rate),
 	_audio_buffer_size(audio_buffer_size),
@@ -793,4 +788,11 @@ int OSystem_Android::getGraphicsMode() const {
 	return 0;
 }
 
+#if defined(USE_OPENGL) && defined(USE_GLAD)
+void *OSystem_Android::getOpenGLProcAddress(const char *name) const {
+	// This exists since Android 2.3 (API Level 9)
+	return (void *)eglGetProcAddress(name);
+}
+#endif
+
 #endif
diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h
index 4b83e05ebd0..432caa3e61d 100644
--- a/backends/platform/android/android.h
+++ b/backends/platform/android/android.h
@@ -201,7 +201,10 @@ public:
 	bool setGraphicsMode(int mode, uint flags) override;
 	int getGraphicsMode() const override;
 
-	OpenGL::ContextOGLType getOpenGLType() const override { return OpenGL::kOGLContextGLES2; }
+	OpenGL::ContextType getOpenGLType() const override { return OpenGL::kContextGLES2; }
+#if defined(USE_OPENGL) && defined(USE_GLAD)
+	void *getOpenGLProcAddress(const char *name) const override;
+#endif
 
 #ifdef ANDROID_DEBUG_GL_CALLS
 	bool isRunningInMainThread() { return pthread_self() == _main_thread; }
diff --git a/backends/platform/ios7/ios7_common.h b/backends/platform/ios7/ios7_common.h
index 481f029789b..c58cbe82c0f 100644
--- a/backends/platform/ios7/ios7_common.h
+++ b/backends/platform/ios7/ios7_common.h
@@ -112,7 +112,6 @@ bool iOS7_isBigDevice();
 
 void iOS7_buildSharedOSystemInstance();
 void iOS7_main(int argc, char **argv);
-void *iOS7_getProcAddress(const char *name);
 const char *iOS7_getDocumentsDir();
 bool iOS7_touchpadModeEnabled();
 
diff --git a/backends/platform/ios7/ios7_osys_main.cpp b/backends/platform/ios7/ios7_osys_main.cpp
index f6083b7f3af..417882b127e 100644
--- a/backends/platform/ios7/ios7_osys_main.cpp
+++ b/backends/platform/ios7/ios7_osys_main.cpp
@@ -124,6 +124,12 @@ bool OSystem_iOS7::touchpadModeEnabled() const {
 	return _touchpadModeEnabled;
 }
 
+#if defined(USE_OPENGL) && defined(USE_GLAD)
+void *OSystem_iOS7::getOpenGLProcAddress(const char *name) const {
+	return dlsym(RTLD_SELF, name);
+}
+#endif
+
 int OSystem_iOS7::timerHandler(int t) {
 	DefaultTimerManager *tm = (DefaultTimerManager *)g_system->getTimerManager();
 	tm->handler();
@@ -413,7 +419,3 @@ void iOS7_main(int argc, char **argv) {
 		fclose(newfp);
 	}
 }
-
-void *iOS7_getProcAddress(const char *name) {
-	return dlsym(RTLD_SELF, name);
-}
diff --git a/backends/platform/ios7/ios7_osys_main.h b/backends/platform/ios7/ios7_osys_main.h
index 1b90de28fa9..61c35715e87 100644
--- a/backends/platform/ios7/ios7_osys_main.h
+++ b/backends/platform/ios7/ios7_osys_main.h
@@ -143,6 +143,9 @@ public:
 	Graphics::PixelFormat getScreenFormat() const override { return _framebuffer.format; }
 	Common::List<Graphics::PixelFormat> getSupportedFormats() const override;
 #endif
+#if defined(USE_OPENGL) && defined(USE_GLAD)
+	void *getOpenGLProcAddress(const char *name) const override;
+#endif
 
 	PaletteManager *getPaletteManager() override { return this; }
 
diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp
index a751360422b..3f1fd57d305 100644
--- a/backends/platform/sdl/sdl.cpp
+++ b/backends/platform/sdl/sdl.cpp
@@ -315,12 +315,12 @@ void OSystem_SDL::initBackend() {
 
 #if defined(USE_OPENGL_GAME) || defined(USE_OPENGL_SHADERS)
 void OSystem_SDL::detectOpenGLFeaturesSupport() {
-	_oglType = OpenGL::kOGLContextNone;
+	_oglType = OpenGL::kContextNone;
 	_supportsFrameBuffer = false;
 	_supportsShaders = false;
 #if USE_FORCED_GLES2
 	// Framebuffers and shaders are always available with GLES2
-	_oglType = OpenGL::kOGLContextGLES2;
+	_oglType = OpenGL::kContextGLES2;
 	_supportsFrameBuffer = true;
 	_supportsShaders = true;
 #else
@@ -342,13 +342,13 @@ void OSystem_SDL::detectOpenGLFeaturesSupport() {
 			return;
 		}
 		if (glContextMajor == 2) {
-			_oglType = OpenGL::kOGLContextGLES2;
+			_oglType = OpenGL::kContextGLES2;
 		} else {
 			SDL_DestroyWindow(window);
 			return;
 		}
 	} else {
-		_oglType = OpenGL::kOGLContextGL;
+		_oglType = OpenGL::kContextGL;
 	}
 	SDL_GLContext glContext = SDL_GL_CreateContext(window);
 	if (!glContext) {
@@ -358,7 +358,7 @@ void OSystem_SDL::detectOpenGLFeaturesSupport() {
 
 	OpenGLContext.initialize(_oglType);
 	_supportsFrameBuffer = OpenGLContext.framebufferObjectSupported;
-	_supportsShaders = OpenGLContext.shadersSupported;
+	_supportsShaders = OpenGLContext.enginesShadersSupported;
 	OpenGLContext.reset();
 	SDL_GL_DeleteContext(glContext);
 	SDL_DestroyWindow(window);
@@ -367,7 +367,7 @@ void OSystem_SDL::detectOpenGLFeaturesSupport() {
 	SDL_SetVideoMode(32, 32, 0, SDL_OPENGL);
 	SDL_putenv(const_cast<char *>("SDL_VIDEO_WINDOW_POS=center"));
 	// SDL 1.2 only supports OpenGL
-	_oglType = OpenGL::kOGLContextGL;
+	_oglType = OpenGL::kContextGL;
 	OpenGLContext.initialize(_oglType);
 	_supportsFrameBuffer = OpenGLContext.framebufferObjectSupported;
 	_supportsShaders = OpenGLContext.shadersSupported;
@@ -522,6 +522,12 @@ Common::Array<uint> OSystem_SDL::getSupportedAntiAliasingLevels() const {
 }
 #endif
 
+#if defined(USE_OPENGL) && defined(USE_GLAD)
+void *OSystem_SDL::getOpenGLProcAddress(const char *name) const {
+	return SDL_GL_GetProcAddress(name);
+}
+#endif
+
 void OSystem_SDL::quit() {
 	destroy();
 	exit(0);
diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h
index f7dd0b8a2e0..87c73522c5a 100644
--- a/backends/platform/sdl/sdl.h
+++ b/backends/platform/sdl/sdl.h
@@ -95,7 +95,10 @@ public:
 
 #if defined(USE_OPENGL_GAME) || defined(USE_OPENGL_SHADERS)
 	Common::Array<uint> getSupportedAntiAliasingLevels() const override;
-	OpenGL::ContextOGLType getOpenGLType() const override { return _oglType; }
+	OpenGL::ContextType getOpenGLType() const override { return _oglType; }
+#endif
+#if defined(USE_OPENGL) && defined(USE_GLAD)
+	void *getOpenGLProcAddress(const char *name) const override;
 #endif
 
 protected:
@@ -137,7 +140,7 @@ protected:
 	void detectOpenGLFeaturesSupport();
 	void detectAntiAliasingSupport();
 
-	OpenGL::ContextOGLType _oglType;
+	OpenGL::ContextType _oglType;
 	bool _supportsFrameBuffer;
 	bool _supportsShaders;
 	Common::Array<uint> _antiAliasLevels;
diff --git a/common/system.h b/common/system.h
index 34db3d089cb..6418ae118b8 100644
--- a/common/system.h
+++ b/common/system.h
@@ -745,10 +745,25 @@ public:
 	 *
 	 * @return the OpenGL type of context which is supported.
 	 */
-	virtual OpenGL::ContextOGLType getOpenGLType() const {
-		return OpenGL::kOGLContextNone;
+	virtual OpenGL::ContextType getOpenGLType() const {
+		return OpenGL::kContextNone;
 	}
 
+#if defined(USE_OPENGL) && defined(USE_GLAD)
+	/**
+	 * Query the address of an OpenGL function by name.
+	 *
+	 * This can only be used after a context has been created.
+	 * Please note that this function can return valid addresses even if the
+	 * OpenGL context does not support the function.
+	 *
+	 * @param name The name of the OpenGL function.
+	 * @return An function pointer for the requested OpenGL function or
+	 *         nullptr in case of failure.
+	 */
+	virtual void *getOpenGLProcAddress(const char *name) const { return nullptr; }
+#endif
+
 	/**
 	 * Retrieve a list of all hardware shaders supported by this backend.
 	 *
diff --git a/engines/grim/gfx_opengl_shaders.cpp b/engines/grim/gfx_opengl_shaders.cpp
index ae223b46489..5c0a931c048 100644
--- a/engines/grim/gfx_opengl_shaders.cpp
+++ b/engines/grim/gfx_opengl_shaders.cpp
@@ -2215,7 +2215,7 @@ Bitmap *GfxOpenGLS::getScreenshot(int w, int h, bool useStored) {
 	Bitmap *bmp;
 
 	if (useStored) {
-		if (OpenGLContext.type == OpenGL::kOGLContextGLES2) {
+		if (OpenGLContext.type == OpenGL::kContextGLES2) {
 			GLuint frameBuffer;
 			glGenFramebuffers(1, &frameBuffer);
 			glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
diff --git a/engines/stark/gfx/opengltexture.cpp b/engines/stark/gfx/opengltexture.cpp
index adef004dd69..7ab81eb9578 100644
--- a/engines/stark/gfx/opengltexture.cpp
+++ b/engines/stark/gfx/opengltexture.cpp
@@ -106,7 +106,7 @@ void OpenGlTexture::setLevelCount(uint32 count) {
 		// GLES2 does not allow setting the max provided mipmap level.
 		// It expects all the levels to be provided, which is not the case in TLJ.
 		// FIXME: Enable mipmapping on GLES2
-		if (OpenGLContext.type != OpenGL::kOGLContextGLES2) {
+		if (OpenGLContext.type != OpenGL::kContextGLES2) {
 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, count - 1);
 
 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
@@ -122,7 +122,7 @@ void OpenGlTexture::setLevelCount(uint32 count) {
 void OpenGlTexture::addLevel(uint32 level, const Graphics::Surface *surface, const byte *palette) {
 	assert(level < _levelCount);
 
-	if (level == 0 || OpenGLContext.type != OpenGL::kOGLContextGLES2) {
+	if (level == 0 || OpenGLContext.type != OpenGL::kContextGLES2) {
 		updateLevel(level, surface, palette);
 	}
 }
diff --git a/graphics/opengl/context.cpp b/graphics/opengl/context.cpp
index 3d30e9a58c2..17b174900ea 100644
--- a/graphics/opengl/context.cpp
+++ b/graphics/opengl/context.cpp
@@ -19,75 +19,62 @@
  *
  */
 
+#define GLAD_GL_IMPLEMENTATION
+
 #include "graphics/opengl/context.h"
 
 #include "common/debug.h"
 #include "common/str.h"
+#include "common/system.h"
 #include "common/textconsole.h"
 #include "common/tokenizer.h"
 
 #include "graphics/opengl/system_headers.h"
 
-#if defined(USE_OPENGL_GAME) || defined(USE_OPENGL_SHADERS)
+#if defined(USE_OPENGL)
 
 #ifdef USE_GLAD
-
-#ifdef SDL_BACKEND
-#include "backends/platform/sdl/sdl-sys.h"
-
-static GLADapiproc loadFunc(void *userptr, const char *name) {
-	return (GLADapiproc)SDL_GL_GetProcAddress(name);
-}
-
-#elif defined(__ANDROID__)
-// To keep includes light, don't include EGL here and don't include Android headers
-void *androidGLgetProcAddress(const char *name);
-
-static GLADapiproc loadFunc(void *userptr, const char *name) {
-	return (GLADapiproc)androidGLgetProcAddress(name);
-}
-
-#elif defined(IPHONE_IOS7)
-#include "backends/platform/ios7/ios7_common.h"
-
-static GLADapiproc loadFunc(void *userptr, const char *name) {
-	return (GLADapiproc)iOS7_getProcAddress(name);
+static GLADapiproc loadFunc(const char *name) {
+	return (GLADapiproc)g_system->getOpenGLProcAddress(name);
 }
-
-#else
-#error Not implemented
-#endif
-
 #endif
 
 namespace Common {
-DECLARE_SINGLETON(OpenGL::ContextGL);
+DECLARE_SINGLETON(OpenGL::Context);
 }
 
 namespace OpenGL {
 
-ContextGL::ContextGL() {
+Context::Context() {
 	reset();
 }
 
-void ContextGL::reset() {
-	type = kOGLContextNone;
+void Context::reset() {
+	type = kContextNone;
 	maxTextureSize = 0;
 
+	majorVersion = 0;
+	minorVersion = 0;
+	glslVersion = 0;
+
 	NPOTSupported = false;
 	shadersSupported = false;
+	enginesShadersSupported = false;
+	multitextureSupported = false;
 	framebufferObjectSupported = false;
+	framebufferObjectMultisampleSupported = false;
+	multisampleMaxSamples = -1;
+	packedPixelsSupported = false;
 	packedDepthStencilSupported = false;
 	unpackSubImageSupported = false;
-	framebufferObjectMultisampleSupported = false;
 	OESDepth24 = false;
-	multisampleMaxSamples = -1;
+	textureEdgeClampSupported = false;
 }
 
-void ContextGL::initialize(ContextOGLType contextType) {
+void Context::initialize(ContextType contextType) {
 	// Initialize default state.
 	reset();
-	if (contextType == kOGLContextNone) {
+	if (contextType == kContextNone) {
 		return;
 	}
 
@@ -95,12 +82,16 @@ void ContextGL::initialize(ContextOGLType contextType) {
 
 #ifdef USE_GLAD
 	switch (type) {
-	case kOGLContextGL:
-		gladLoadGLUserPtr(loadFunc, this);
+	case kContextGL:
+		gladLoadGL(loadFunc);
 		break;
 
-	case kOGLContextGLES2:
-		gladLoadGLES2UserPtr(loadFunc, this);
+	case kContextGLES:
+		gladLoadGLES1(loadFunc);
+		break;
+
+	case kContextGLES2:
+		gladLoadGLES2(loadFunc);
 		break;
 
 	default:
@@ -108,6 +99,42 @@ void ContextGL::initialize(ContextOGLType contextType) {
 	}
 #endif
 
+	const char *verString = (const char *)glGetString(GL_VERSION);
+	debug(5, "OpenGL version: %s", verString);
+
+	if (type == kContextGL) {
+		// OpenGL version number is either of the form major.minor or major.minor.release,
+		// where the numbers all have one or more digits
+		if (sscanf(verString, "%d.%d", &majorVersion, &minorVersion) != 2) {
+			majorVersion = minorVersion = 0;
+			warning("Could not parse GL version '%s'", verString);
+		}
+	} else if (type == kContextGLES) {
+		// The form of the string is "OpenGL ES-<profile> <major>.<minor>",
+		// where <profile> is either "CM" (Common) or "CL" (Common-Lite),
+		// and <major> and <minor> are integers.
+		char profile[3];
+		if (sscanf(verString, "OpenGL ES-%2s %d.%d", profile,
+					&majorVersion, &minorVersion) != 3) {
+			majorVersion = minorVersion = 0;
+			warning("Could not parse GL ES version '%s'", verString);
+		}
+	} else if (type == kContextGLES2) {
+		// The version is of the form
+		// OpenGL<space>ES<space><version number><space><vendor-specific information>
+		// version number format is not defined
+		// There is only OpenGL ES 2.0 anyway
+		if (sscanf(verString, "OpenGL ES %d.%d", &majorVersion, &minorVersion) != 2) {
+			minorVersion = 0;
+			if (sscanf(verString, "OpenGL ES %d ", &majorVersion) != 1) {
+				majorVersion = 0;
+				warning("Could not parse GL ES 2 version '%s'", verString);
+			}
+		}
+	}
+
+	glslVersion = getGLSLVersion();
+
 	// Obtain maximum texture size.
 	glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&maxTextureSize);
 	debug(5, "OpenGL maximum texture size: %d", maxTextureSize);
@@ -135,8 +162,12 @@ void ContextGL::initialize(ContextOGLType contextType) {
 			ARBVertexShader = true;
 		} else if (token == "GL_ARB_fragment_shader") {
 			ARBFragmentShader = true;
+		} else if (token == "GL_ARB_multitexture") {
+			multitextureSupported = true;
 		} else if (token == "GL_ARB_framebuffer_object") {
 			framebufferObjectSupported = true;
+		} else if (token == "GL_EXT_packed_pixels" || token == "GL_APPLE_packed_pixels") {
+			packedPixelsSupported = true;
 		} else if (token == "GL_EXT_packed_depth_stencil" || token == "GL_OES_packed_depth_stencil") {
 			packedDepthStencilSupported = true;
 		} else if (token == "GL_EXT_unpack_subimage") {
@@ -147,19 +178,22 @@ void ContextGL::initialize(ContextOGLType contextType) {
 			EXTFramebufferBlit = true;
 		} else if (token == "GL_OES_depth24") {
 			OESDepth24 = true;
+		} else if (token == "GL_SGIS_texture_edge_clamp") {
+			textureEdgeClampSupported = true;
 		}
-
 	}
 
-	int glslVersion = getGLSLVersion();
-	debug(5, "OpenGL GLSL version: %d", glslVersion);
-
-	if (type == kOGLContextGLES2) {
+	if (type == kContextGLES2) {
 		// GLES2 always has (limited) NPOT support.
 		NPOTSupported = true;
 
 		// GLES2 always has shader support.
 		shadersSupported = true;
+		// GLES2 should always have GLSL ES 1.00 support but let's make sure
+		enginesShadersSupported = (glslVersion >= 100);
+
+		// GLES2 always has multi texture support.
+		multitextureSupported = true;
 
 		// GLES2 always has FBO support.
 		framebufferObjectSupported = true;
@@ -167,8 +201,42 @@ void ContextGL::initialize(ContextOGLType contextType) {
 		// ScummVM does not support multisample FBOs with GLES2 for now
 		framebufferObjectMultisampleSupported = false;
 		multisampleMaxSamples = -1;
-	} else {
-		shadersSupported = ARBShaderObjects && ARBShadingLanguage100 && ARBVertexShader && ARBFragmentShader && glslVersion >= 120;
+
+		packedPixelsSupported = true;
+		textureEdgeClampSupported = true;
+		debug(5, "OpenGL: GLES2 context initialized");
+	} else if (type == kContextGLES) {
+		// GLES doesn't support shaders natively
+		// We don't do any aliasing in our code and expect standard OpenGL functions but GLAD does it
+		// So if we use GLAD we can check for ARB extensions and expect a GLSL of 1.00
+#ifdef USE_GLAD
+		shadersSupported = ARBShaderObjects && ARBShadingLanguage100 && ARBVertexShader && ARBFragmentShader;
+		glslVersion = 100;
+#endif
+		// We don't expect GLES to support shaders recent enough for engines
+
+		// ScummVM does not support multisample FBOs with GLES for now
+		framebufferObjectMultisampleSupported = false;
+		multisampleMaxSamples = -1;
+
+		packedPixelsSupported = true;
+		textureEdgeClampSupported = true;
+		debug(5, "OpenGL: GLES context initialized");
+	} else if (type == kContextGL) {
+		shadersSupported = glslVersion >= 100;
+
+		// We don't do any aliasing in our code and expect standard OpenGL functions but GLAD does it
+		// So if we use GLAD we can check for ARB extensions and expect a GLSL of 1.00
+#ifdef USE_GLAD
+		if (!shadersSupported) {
+			shadersSupported = ARBShaderObjects && ARBShadingLanguage100 && ARBVertexShader && ARBFragmentShader;
+			if (shadersSupported) {
+				glslVersion = 100;
+			}
+		}
+#endif
+		// In GL mode engines need GLSL 1.20
+		enginesShadersSupported = glslVersion >= 120;
 
 		// Desktop GL always has unpack sub-image support
 		unpackSubImageSupported = true;
@@ -178,31 +246,50 @@ void ContextGL::initialize(ContextOGLType contextType) {
 		if (framebufferObjectMultisampleSupported) {
 			glGetIntegerv(GL_MAX_SAMPLES, (GLint *)&multisampleMaxSamples);
 		}
-	}
 
-	// Log context type.
-	switch (type) {
-		case kOGLContextNone:
-			/* Shouldn't happen */
-			break;
-		case kOGLContextGL:
-			debug(5, "OpenGL: GL context initialized");
-			break;
-
-		case kOGLContextGLES2:
-			debug(5, "OpenGL: GLES2 context initialized");
-			break;
+		// OpenGL 1.2 and later always has packed pixels and texture edge clamp support
+		if (isGLVersionOrHigher(1, 2)) {
+			packedPixelsSupported = true;
+			textureEdgeClampSupported = true;
+		}
+		debug(5, "OpenGL: GL context initialized");
+	} else {
+		warning("OpenGL: Unknown context initialized");
 	}
 
 	// Log features supported by GL context.
+	debug(5, "OpenGL vendor: %s", glGetString(GL_VENDOR));
+	debug(5, "OpenGL renderer: %s", glGetString(GL_RENDERER));
+	debug(5, "OpenGL: version %d.%d", majorVersion, minorVersion);
+	debug(5, "OpenGL: GLSL version: %d", glslVersion);
+	debug(5, "OpenGL: Max texture size: %d", maxTextureSize);
 	debug(5, "OpenGL: NPOT texture support: %d", NPOTSupported);
 	debug(5, "OpenGL: Shader support: %d", shadersSupported);
+	debug(5, "OpenGL: Multitexture support: %d", multitextureSupported);
 	debug(5, "OpenGL: FBO support: %d", framebufferObjectSupported);
+	debug(5, "OpenGL: Multisample FBO support: %d", framebufferObjectMultisampleSupported);
+	debug(5, "OpenGL: Multisample max number: %d", multisampleMaxSamples);
+	debug(5, "OpenGL: Packed pixels support: %d", packedPixelsSupported);
 	debug(5, "OpenGL: Packed depth stencil support: %d", packedDepthStencilSupported);
 	debug(5, "OpenGL: Unpack subimage support: %d", unpackSubImageSupported);
+	debug(5, "OpenGL: OpenGL ES depth 24 support: %d", OESDepth24);
+	debug(5, "OpenGL: Texture edge clamping support: %d", textureEdgeClampSupported);
 }
 
-int ContextGL::getGLSLVersion() const {
+int Context::getGLSLVersion() const {
+#if USE_FORCED_GLES
+	return 0;
+#else
+	// No shader support in GLES
+	if (type == kContextGLES) {
+		return 0;
+	}
+
+	// No shader support in OpenGL 1.x
+	if (type == kContextGL && !isGLVersionOrHigher(2, 0)) {
+		return 0;
+	}
+
 	const char *glslVersionString = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
 	if (!glslVersionString) {
 		warning("Could not get GLSL version");
@@ -210,7 +297,7 @@ int ContextGL::getGLSLVersion() const {
 	}
 
 	const char *glslVersionFormat;
-	if (type == kOGLContextGL) {
+	if (type == kContextGL) {
 		glslVersionFormat = "%d.%d";
 	} else {
 		glslVersionFormat = "OpenGL ES GLSL ES %d.%d";
@@ -223,6 +310,7 @@ int ContextGL::getGLSLVersion() const {
 	}
 
 	return glslMajorVersion * 100 + glslMinorVersion;
+#endif
 }
 
 } // End of namespace OpenGL
diff --git a/graphics/opengl/context.h b/graphics/opengl/context.h
index bfe0642b6bb..d00a0ab1ab8 100644
--- a/graphics/opengl/context.h
+++ b/graphics/opengl/context.h
@@ -26,20 +26,19 @@
 
 namespace OpenGL {
 
-enum ContextOGLType {
-	kOGLContextNone,
-	kOGLContextGL,
-	kOGLContextGLES2
+enum ContextType {
+	kContextNone,
+	kContextGL,
+	kContextGLES,
+	kContextGLES2
 };
 
 /**
  * Description structure of the OpenGL (ES) context.
- *
- * This class is based on LordHoto's OpenGL backend for ScummVM
  */
-class ContextGL : public Common::Singleton<ContextGL> {
+class Context : public Common::Singleton<Context> {
 public:
-	ContextGL();
+	Context();
 
 	/**
 	 * Initialize the context description from currently active context.
@@ -47,7 +46,7 @@ public:
 	 * The extensions and features are marked as available according
 	 * to the current context capabilities.
 	 */
-	void initialize(ContextOGLType contextType);
+	void initialize(ContextType contextType);
 
 	/**
 	 * Reset context.
@@ -57,7 +56,18 @@ public:
 	void reset();
 
 	/** The type of the active context. */
-	ContextOGLType type;
+	ContextType type;
+
+	/** Helper function for checking the GL version supported by the context. */
+	inline bool isGLVersionOrHigher(int major, int minor) const {
+		return ((majorVersion > major) || ((majorVersion == major) && (minorVersion >= minor)));
+	}
+
+	/** The GL version supported by the context. */
+	int majorVersion, minorVersion;
+
+	/** The GLSL version supported by the context */
+	int glslVersion;
 
 	/** The maximum texture size supported by the context. */
 	int maxTextureSize;
@@ -68,6 +78,12 @@ public:
 	/** Whether shader support is available or not. */
 	bool shadersSupported;
 
+	/** Whether shader support is good enough for engines or not. */
+	bool enginesShadersSupported;
+
+	/** Whether multi texture support is available or not. */
+	bool multitextureSupported;
+
 	/** Whether FBO support is available or not. */
 	bool framebufferObjectSupported;
 
@@ -80,6 +96,9 @@ public:
 	 */
 	int multisampleMaxSamples;
 
+	/** Whether packed pixels support is available or not. */
+	bool packedPixelsSupported;
+
 	/** Whether packing the depth and stencil buffers is possible or not. */
 	bool packedDepthStencilSupported;
 
@@ -89,12 +108,20 @@ public:
 	/** Whether depth component 24 is supported or not */
 	bool OESDepth24;
 
+	/** Whether texture coordinate edge clamping is available or not. */
+	bool textureEdgeClampSupported;
+
+private:
+	/**
+	 * Returns the native GLSL version supported by the driver.
+	 * This does NOT take shaders ARB extensions into account.
+	 */
 	int getGLSLVersion() const;
 };
 
 } // End of namespace OpenGL
 
 /** Shortcut for accessing the active OpenGL context. */
-#define OpenGLContext OpenGL::ContextGL::instance()
+#define OpenGLContext OpenGL::Context::instance()
 
 #endif
diff --git a/graphics/opengl/shader.cpp b/graphics/opengl/shader.cpp
index 1a407e41b34..9cebcb115a2 100644
--- a/graphics/opengl/shader.cpp
+++ b/graphics/opengl/shader.cpp
@@ -133,7 +133,7 @@ static GLuint createDirectShader(const char *shaderSource, GLenum shaderType, co
 }
 
 static GLuint createCompatShader(const char *shaderSource, GLenum shaderType, const Common::String &name) {
-	const GLchar *versionSource = OpenGLContext.type == kOGLContextGLES2 ? "#version 100\n" : "#version 120\n";
+	const GLchar *versionSource = OpenGLContext.type == kContextGLES2 ? "#version 100\n" : "#version 120\n";
 	const GLchar *compatSource =
 			shaderType == GL_VERTEX_SHADER ? compatVertex : compatFragment;
 	const GLchar *shaderSources[] = {
diff --git a/graphics/renderer.cpp b/graphics/renderer.cpp
index f1defb637ff..26377d51674 100644
--- a/graphics/renderer.cpp
+++ b/graphics/renderer.cpp
@@ -93,7 +93,7 @@ uint32 Renderer::getAvailableTypes() {
 		/* Backend either support OpenGL or OpenGL ES(2) */
 #if defined(USE_OPENGL_GAME)
 		/* OpenGL classic is compiled in, check if hardware supports it */
-		if (g_system->getOpenGLType() == OpenGL::kOGLContextGL) {
+		if (g_system->getOpenGLType() == OpenGL::kContextGL) {
 			available |= kRendererTypeOpenGL;
 		}
 #endif


Commit: 98c306376fd4b6c1884b71ba2665bd064246221f
    https://github.com/scummvm/scummvm/commit/98c306376fd4b6c1884b71ba2665bd064246221f
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2022-06-26T18:32:10+02:00

Commit Message:
OPENGL: Merge both OpenGL shaders objects

Changed paths:
    backends/graphics/opengl/opengl-graphics.cpp
    backends/graphics/opengl/opengl-graphics.h
    backends/graphics/opengl/pipelines/shader.cpp
    backends/graphics/opengl/pipelines/shader.h
    backends/graphics/opengl/shader.cpp
    backends/graphics/opengl/shader.h
    backends/graphics/opengl/texture.cpp
    backends/graphics/opengl/texture.h
    backends/graphics3d/android/texture.cpp
    backends/graphics3d/android/texture.h
    backends/graphics3d/opengl/surfacerenderer.cpp
    backends/graphics3d/opengl/surfacerenderer.h
    engines/grim/gfx_opengl_shaders.cpp
    engines/grim/gfx_opengl_shaders.h
    engines/myst3/gfx_opengl_shaders.cpp
    engines/myst3/gfx_opengl_shaders.h
    engines/playground3d/gfx_opengl_shaders.cpp
    engines/playground3d/gfx_opengl_shaders.h
    engines/stark/gfx/opengls.cpp
    engines/stark/gfx/opengls.h
    engines/stark/gfx/openglsactor.cpp
    engines/stark/gfx/openglsactor.h
    engines/stark/gfx/openglsfade.h
    engines/stark/gfx/openglsprop.cpp
    engines/stark/gfx/openglsprop.h
    engines/stark/gfx/openglssurface.h
    engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.cpp
    engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.h
    engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.cpp
    engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.h
    engines/wintermute/base/gfx/opengl/meshx_opengl_shader.cpp
    engines/wintermute/base/gfx/opengl/meshx_opengl_shader.h
    engines/wintermute/base/gfx/opengl/shadow_volume_opengl_shader.cpp
    engines/wintermute/base/gfx/opengl/shadow_volume_opengl_shader.h
    graphics/opengl/shader.cpp
    graphics/opengl/shader.h


diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index 3d41e94d978..7552f605ad0 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -1070,6 +1070,7 @@ void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
 	const Graphics::PixelFormat &defaultFormat,
 	const Graphics::PixelFormat &defaultFormatAlpha) {
 	// Initialize pipeline.
+	Pipeline::setPipeline(nullptr);
 	delete _pipeline;
 	_pipeline = nullptr;
 
@@ -1088,21 +1089,19 @@ void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
 	}
 #endif
 
-	Pipeline::setPipeline(_pipeline);
-
 	// Disable 3D properties.
 	GL_CALL(glDisable(GL_CULL_FACE));
 	GL_CALL(glDisable(GL_DEPTH_TEST));
 	GL_CALL(glDisable(GL_DITHER));
 
-	Pipeline::getActivePipeline()->setColor(1.0f, 1.0f, 1.0f, 1.0f);
+	_pipeline->setColor(1.0f, 1.0f, 1.0f, 1.0f);
 
 	// Setup backbuffer state.
 
 	// Default to black as clear color.
 	_backBuffer.setClearColor(0.0f, 0.0f, 0.0f, 0.0f);
 
-	Pipeline::getActivePipeline()->setFramebuffer(&_backBuffer);
+	_pipeline->setFramebuffer(&_backBuffer);
 
 	// We use a "pack" alignment (when reading from textures) to 4 here,
 	// since the only place where we really use it is the BMP screenshot
@@ -1141,6 +1140,10 @@ void OpenGLGraphicsManager::notifyContextCreate(ContextType type,
 		_osdIconSurface->recreate();
 	}
 #endif
+
+	// Everything is ready: activate the pipeline
+	Pipeline::setPipeline(_pipeline);
+
 }
 
 void OpenGLGraphicsManager::notifyContextDestroy() {
diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h
index f3d30f04555..5c894ee00ab 100644
--- a/backends/graphics/opengl/opengl-graphics.h
+++ b/backends/graphics/opengl/opengl-graphics.h
@@ -44,9 +44,6 @@ namespace OpenGL {
 
 class Surface;
 class Pipeline;
-#if !USE_FORCED_GLES
-class Shader;
-#endif
 
 enum {
 	GFX_OPENGL = 0
diff --git a/backends/graphics/opengl/pipelines/shader.cpp b/backends/graphics/opengl/pipelines/shader.cpp
index 8905701c608..e2385bffcaf 100644
--- a/backends/graphics/opengl/pipelines/shader.cpp
+++ b/backends/graphics/opengl/pipelines/shader.cpp
@@ -26,46 +26,43 @@
 
 namespace OpenGL {
 
+// A 4 elements with 2 components vector of floats
+static const int kCoordinatesSize = 4 * 2 * sizeof(float);
+
 #if !USE_FORCED_GLES
 ShaderPipeline::ShaderPipeline(Shader *shader)
 	: _activeShader(shader), _colorAttributes() {
-	_vertexAttribLocation = shader->getAttributeLocation("position");
-	_texCoordAttribLocation = shader->getAttributeLocation("texCoordIn");
-	_colorAttribLocation = shader->getAttributeLocation("blendColorIn");
-
-	assert(_vertexAttribLocation   != -1);
-	assert(_texCoordAttribLocation != -1);
-	assert(_colorAttribLocation    != -1);
-
-	// One of the attributes needs to be passed through location 0, otherwise
-	// we get no output for GL contexts due to GL compatibility reasons. Let's
-	// check whether this ever happens. If this ever gets hit, we need to
-	// enable location 0 and pass some dummy values through it to fix output.
-	assert(   _vertexAttribLocation == 0
-	       || _texCoordAttribLocation == 0
-	       || _colorAttribLocation == 0);
+	// Use the same VBO for vertices and texcoords as we modify them at the same time
+	_coordsVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, kCoordinatesSize, nullptr, GL_STATIC_DRAW);
+	_activeShader->enableVertexAttribute("position", _coordsVBO, 2, GL_FLOAT, GL_FALSE, 0, 0);
+	_texcoordsVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, kCoordinatesSize, nullptr, GL_STATIC_DRAW);
+	_activeShader->enableVertexAttribute("texCoordIn", _texcoordsVBO, 2, GL_FLOAT, GL_FALSE, 0, 0);
+	_colorVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(_colorAttributes), nullptr, GL_DYNAMIC_DRAW);
+	_activeShader->enableVertexAttribute("blendColorIn", _colorVBO, 4, GL_FLOAT, GL_FALSE, 0, 0);
 }
 
-void ShaderPipeline::activateInternal() {
-	GL_CALL(glEnableVertexAttribArray(_vertexAttribLocation));
-	GL_CALL(glEnableVertexAttribArray(_texCoordAttribLocation));
-	GL_CALL(glEnableVertexAttribArray(_colorAttribLocation));
+ShaderPipeline::~ShaderPipeline() {
+	delete _activeShader;
+
+	OpenGL::Shader::freeBuffer(_coordsVBO);
+	OpenGL::Shader::freeBuffer(_texcoordsVBO);
+	OpenGL::Shader::freeBuffer(_colorVBO);
+}
 
+void ShaderPipeline::activateInternal() {
 	if (OpenGLContext.multitextureSupported) {
 		GL_CALL(glActiveTexture(GL_TEXTURE0));
 	}
 
-	_activeShader->activate();
+	_activeShader->use();
 
-	GL_CALL(glVertexAttribPointer(_colorAttribLocation, 4, GL_FLOAT, GL_FALSE, 0, _colorAttributes));
+	GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, _colorVBO));
+	GL_CALL(glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(_colorAttributes), _colorAttributes));
+	GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
 }
 
 void ShaderPipeline::deactivateInternal() {
-	GL_CALL(glDisableVertexAttribArray(_vertexAttribLocation));
-	GL_CALL(glDisableVertexAttribArray(_texCoordAttribLocation));
-	GL_CALL(glDisableVertexAttribArray(_colorAttribLocation));
-
-	_activeShader->deactivate();
+	_activeShader->unbind();
 }
 
 void ShaderPipeline::setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
@@ -81,13 +78,19 @@ void ShaderPipeline::setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
 void ShaderPipeline::drawTexture(const GLTexture &texture, const GLfloat *coordinates, const GLfloat *texcoords) {
 	texture.bind();
 
-	GL_CALL(glVertexAttribPointer(_texCoordAttribLocation, 2, GL_FLOAT, GL_FALSE, 0, texcoords));
-	GL_CALL(glVertexAttribPointer(_vertexAttribLocation, 2, GL_FLOAT, GL_FALSE, 0, coordinates));
+	GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, _coordsVBO));
+	GL_CALL(glBufferData(GL_ARRAY_BUFFER, kCoordinatesSize, coordinates, GL_STATIC_DRAW));
+	GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, _texcoordsVBO));
+	GL_CALL(glBufferData(GL_ARRAY_BUFFER, kCoordinatesSize, texcoords, GL_STATIC_DRAW));
+	GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
+
 	GL_CALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
 }
 
 void ShaderPipeline::setProjectionMatrix(const GLfloat *projectionMatrix) {
-	_activeShader->setUniform("projection", new ShaderUniformMatrix44(projectionMatrix));
+	Math::Matrix4 m4;
+	m4.setData(projectionMatrix);
+	_activeShader->setUniform("projection", m4);
 }
 #endif // !USE_FORCED_GLES
 
diff --git a/backends/graphics/opengl/pipelines/shader.h b/backends/graphics/opengl/pipelines/shader.h
index cbba6272f4c..dc8d365c494 100644
--- a/backends/graphics/opengl/pipelines/shader.h
+++ b/backends/graphics/opengl/pipelines/shader.h
@@ -32,6 +32,7 @@ class Shader;
 class ShaderPipeline : public Pipeline {
 public:
 	ShaderPipeline(Shader *shader);
+	~ShaderPipeline();
 
 	virtual void setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a);
 
@@ -43,9 +44,9 @@ protected:
 	virtual void activateInternal();
 	virtual void deactivateInternal();
 
-	GLint _vertexAttribLocation;
-	GLint _texCoordAttribLocation;
-	GLint _colorAttribLocation;
+	GLuint _coordsVBO;
+	GLuint _texcoordsVBO;
+	GLuint _colorVBO;
 
 	GLfloat _colorAttributes[4*4];
 
diff --git a/backends/graphics/opengl/shader.cpp b/backends/graphics/opengl/shader.cpp
index 4fb7f1f5b36..2d789f8ed1e 100644
--- a/backends/graphics/opengl/shader.cpp
+++ b/backends/graphics/opengl/shader.cpp
@@ -23,8 +23,6 @@
 #include "backends/graphics/opengl/debug.h"
 
 #if !USE_FORCED_GLES
-#include "common/textconsole.h"
-#include "common/util.h"
 
 namespace Common {
 DECLARE_SINGLETON(OpenGL::ShaderManager);
@@ -36,6 +34,10 @@ namespace {
 
 #pragma mark - Builtin Shader Sources -
 
+const char *const g_defaultShaderAttributes[] = {
+	"position", "texCoordIn", "blendColorIn", nullptr
+};
+
 const char *const g_defaultVertexShader =
 	"attribute vec4 position;\n"
 	"attribute vec2 texCoordIn;\n"
@@ -76,219 +78,9 @@ const char *const g_lookUpFragmentShader =
 	"\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 =
-	"#ifdef GL_ES\n"
-	"\t#ifdef GL_FRAGMENT_PRECISION_HIGH\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
 
-#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), _isActive(false), _program(0), _uniforms() {
-	recreate();
-}
-
-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(glDeleteProgram, (_program));
-	}
-}
-
-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(glDeleteProgram(_program));
-		_program = 0;
-	}
-}
-
-bool Shader::recreate() {
-	// Make sure any old programs are destroyed properly.
-	destroy();
-
-	GLshader vertexShader = compileShader(_vertex.c_str(), GL_VERTEX_SHADER);
-	if (!vertexShader) {
-		return false;
-	}
-
-	GLshader 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(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;
-	}
-
-	// 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();
-		}
-	}
-
-	return true;
-}
-
-void Shader::activate() {
-	// Activate program.
-	GL_CALL(glUseProgram(_program));
-
-	// Reset changed uniform values.
-	for (UniformMap::iterator i = _uniforms.begin(), end = _uniforms.end(); i != end; ++i) {
-		i->_value.set();
-	}
-
-	_isActive = true;
-}
-
-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));
-	return result;
-}
-
-bool Shader::setUniform(const Common::String &name, ShaderUniformValue *value) {
-	UniformMap::iterator uniformIter = _uniforms.find(name);
-	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 = location;
-	} else {
-		uniform = &uniformIter->_value;
-	}
-
-	uniform->value = Common::SharedPtr<ShaderUniformValue>(value);
-	uniform->altered = true;
-	if (_isActive) {
-		uniform->set();
-	}
-
-	return true;
-}
-
-GLshader Shader::compileShader(const char *source, GLenum shaderType) {
-	const GLchar *versionSource = OpenGLContext.type == kContextGLES2 ? "#version 100\n" : "#version 110\n";
-	const GLchar *compatSource = shaderType == GL_VERTEX_SHADER ? "" : g_precisionDefines;
-
-	GLshader handle;
-	GL_ASSIGN(handle, glCreateShader(shaderType));
-	if (!handle) {
-		return 0;
-	}
-
-	const char *const shaderSources[] = {
-		versionSource,
-		compatSource,
-		source
-	};
-
-	GL_CALL(glShaderSource(handle, ARRAYSIZE(shaderSources), shaderSources, 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%s\": \"%s\"", versionSource, compatSource, source, log);
-		delete[] log;
-
-		GL_CALL(glDeleteShader(handle));
-		return 0;
-	}
-
-	return handle;
-}
-
-ShaderManager::ShaderManager() : _initializeShaders(true) {
+ShaderManager::ShaderManager() {
 	for (int i = 0; i < ARRAYSIZE(_builtIn); ++i) {
 		_builtIn[i] = nullptr;
 	}
@@ -302,25 +94,21 @@ ShaderManager::~ShaderManager() {
 
 void ShaderManager::notifyDestroy() {
 	for (int i = 0; i < ARRAYSIZE(_builtIn); ++i) {
-		_builtIn[i]->destroy();
+		delete _builtIn[i];
+		_builtIn[i] = nullptr;
 	}
 }
 
 void ShaderManager::notifyCreate() {
-	if (_initializeShaders) {
-		_initializeShaders = false;
+	// Ensure everything is destroyed
+	notifyDestroy();
 
-		_builtIn[kDefault] = new Shader(g_defaultVertexShader, g_defaultFragmentShader);
-		_builtIn[kCLUT8LookUp] = new Shader(g_defaultVertexShader, g_lookUpFragmentShader);
-		_builtIn[kCLUT8LookUp]->setUniform1I("palette", 1);
+	_builtIn[kDefault] = Shader::fromStrings("default", g_defaultVertexShader, g_defaultFragmentShader, g_defaultShaderAttributes, 110);
+	_builtIn[kCLUT8LookUp] = Shader::fromStrings("clut8lookup", g_defaultVertexShader, g_lookUpFragmentShader, g_defaultShaderAttributes, 110);
+	_builtIn[kCLUT8LookUp]->setUniform("palette", 1);
 
-		for (uint i = 0; i < kMaxUsages; ++i) {
-			_builtIn[i]->setUniform1I("shaderTexture", 0);
-		}
-	} else {
-		for (int i = 0; i < ARRAYSIZE(_builtIn); ++i) {
-			_builtIn[i]->recreate();
-		}
+	for (uint i = 0; i < kMaxUsages; ++i) {
+		_builtIn[i]->setUniform("shaderTexture", 0);
 	}
 }
 
@@ -330,7 +118,7 @@ Shader *ShaderManager::query(ShaderUsage shader) const {
 		return nullptr;
 	}
 
-	return _builtIn[shader];
+	return _builtIn[shader]->clone();
 }
 
 } // End of namespace OpenGL
diff --git a/backends/graphics/opengl/shader.h b/backends/graphics/opengl/shader.h
index 5395dfbba59..63ecf0badd3 100644
--- a/backends/graphics/opengl/shader.h
+++ b/backends/graphics/opengl/shader.h
@@ -27,224 +27,11 @@
 #if !USE_FORCED_GLES
 
 #include "common/singleton.h"
-#include "common/hash-str.h"
-#include "common/ptr.h"
 
-// This is an addition from us to alias ARB shader object extensions to
-// OpenGL (ES) 2.0 style functions. It only works when GLhandleARB and GLuint
-// are type compatible.
-typedef GLuint GLprogram;
-typedef GLuint GLshader;
+#include "graphics/opengl/shader.h"
 
 namespace OpenGL {
 
-/**
- * A generic uniform value interface for a shader program.
- */
-class ShaderUniformValue {
-public:
-	virtual ~ShaderUniformValue() {}
-
-	/**
-	 * Setup the the value to the given location.
-	 *
-	 * @param location Location of the uniform.
-	 */
-	virtual void set(GLint location) const = 0;
-};
-
-/**
- * Integer value for a shader uniform.
- */
-class ShaderUniformInteger : public ShaderUniformValue {
-public:
-	ShaderUniformInteger(GLint value) : _value(value) {}
-
-	void set(GLint location) const override;
-
-private:
-	const GLint _value;
-};
-
-/**
- * Float value for a shader uniform.
- */
-class ShaderUniformFloat : public ShaderUniformValue {
-public:
-	ShaderUniformFloat(GLfloat value) : _value(value) {}
-
-	void set(GLint location) const override;
-
-private:
-	const GLfloat _value;
-};
-
-/**
- * 4x4 Matrix value for a shader uniform.
- */
-class ShaderUniformMatrix44 : public ShaderUniformValue {
-public:
-	ShaderUniformMatrix44(const GLfloat *mat44) {
-		memcpy(_matrix, mat44, sizeof(_matrix));
-	}
-
-	void set(GLint location) const override;
-
-private:
-	GLfloat _matrix[4*4];
-};
-
-class Shader {
-public:
-	Shader(const Common::String &vertex, const Common::String &fragment);
-	~Shader();
-
-	/**
-	 * Destroy the shader program.
-	 *
-	 * This keeps the vertex and fragment shader sources around and thus
-	 * allows for recreating the shader on context recreation. It also keeps
-	 * the uniform state around.
-	 */
-	void destroy();
-
-	/**
-	 * Recreate shader program.
-	 *
-	 * @return true on success, false on failure.
-	 */
-	bool recreate();
-
-	/**
-	 * Make shader active.
-	 */
-	void activate();
-
-	/**
-	 * Make shader inactive.
-	 */
-	void deactivate();
-
-	/**
-	 * Return location for attribute with given name.
-	 *
-	 * @param name Name of the attribute to look up in the shader.
-	 * @return The loctaion of -1 if attribute was not found.
-	 */
-	GLint getAttributeLocation(const char *name) const;
-	GLint getAttributeLocation(const Common::String &name) const {
-		return getAttributeLocation(name.c_str());
-	}
-
-	/**
-	 * Return location for uniform with given name.
-	 *
-	 * @param name Name of the uniform to look up in the shader.
-	 * @return The location or -1 if uniform was not found.
-	 */
-	GLint getUniformLocation(const char *name) const;
-	GLint getUniformLocation(const Common::String &name) const {
-		return getUniformLocation(name.c_str());
-	}
-
-	/**
-	 * Bind value to uniform.
-	 *
-	 * @param name  The name of the uniform to be set.
-	 * @param value The value to be set.
-	 * @return 'false' on error (i.e. uniform unknown or otherwise),
-	 *         'true' otherwise.
-	 */
-	bool setUniform(const Common::String &name, ShaderUniformValue *value);
-
-	/**
-	 * Bind integer value to uniform.
-	 *
-	 * @param name  The name of the uniform to be set.
-	 * @param value The value to be set.
-	 * @return 'false' on error (i.e. uniform unknown or otherwise),
-	 *         'true' otherwise.
-	 */
-	bool setUniform1I(const Common::String &name, GLint value) {
-		return setUniform(name, new ShaderUniformInteger(value));
-	}
-protected:
-	/**
-	 * Vertex shader sources.
-	 */
-	const Common::String _vertex;
-
-	/**
-	 * Fragment shader sources.
-	 */
-	const Common::String _fragment;
-
-	/**
-	 * Whether the shader is active or not.
-	 */
-	bool _isActive;
-
-	/**
-	 * Shader program handle.
-	 */
-	GLprogram _program;
-
-	/**
-	 * A uniform descriptor.
-	 *
-	 * This stores the state of a shader uniform. The state is made up of the
-	 * uniform location, whether the state was altered since last set, and the
-	 * value of the uniform.
-	 */
-	struct Uniform {
-		Uniform() : location(-1), altered(false), value() {}
-		Uniform(GLint loc, ShaderUniformValue *val)
-		    : location(loc), altered(true), value(val) {}
-
-		/**
-		 * Write uniform value into currently active shader.
-		 */
-		void set() {
-			if (altered && value) {
-				value->set(location);
-				altered = false;
-			}
-		}
-
-		/**
-		 * The location of the uniform or -1 in case it does not exist.
-		 */
-		GLint location;
-
-		/**
-		 * Whether the uniform state was aletered since last 'set'.
-		 */
-		bool altered;
-
-		/**
-		 * The value of the uniform.
-		 */
-		Common::SharedPtr<ShaderUniformValue> value;
-	};
-
-	typedef Common::HashMap<Common::String, Uniform> UniformMap;
-
-	/**
-	 * Map from uniform name to associated uniform description.
-	 */
-	UniformMap _uniforms;
-
-	/**
-	 * Compile a vertex or fragment shader.
-	 *
-	 * @param source     Sources to the shader.
-	 * @param shaderType Type of shader to compile (GL_FRAGMENT_SHADER_ARB or
-	 *                   GL_VERTEX_SHADER_ARB)
-	 * @return The shader object or 0 on failure.
-	 */
-	static GLshader compileShader(const char *source, GLenum shaderType);
-};
-
 class ShaderManager : public Common::Singleton<ShaderManager> {
 public:
 	enum ShaderUsage {
@@ -270,6 +57,7 @@ public:
 
 	/**
 	 * Query a built-in shader.
+	 * Shader returned must be destroyed by caller.
 	 */
 	Shader *query(ShaderUsage shader) const;
 
@@ -278,8 +66,6 @@ private:
 	ShaderManager();
 	~ShaderManager();
 
-	bool _initializeShaders;
-
 	Shader *_builtIn[kMaxUsages];
 };
 
diff --git a/backends/graphics/opengl/texture.cpp b/backends/graphics/opengl/texture.cpp
index 32a9ad0d94e..01244be5401 100644
--- a/backends/graphics/opengl/texture.cpp
+++ b/backends/graphics/opengl/texture.cpp
@@ -614,6 +614,8 @@ void TextureCLUT8GPU::destroy() {
 	_clut8Texture.destroy();
 	_paletteTexture.destroy();
 	_target->destroy();
+	delete _clut8Pipeline;
+	_clut8Pipeline = nullptr;
 }
 
 void TextureCLUT8GPU::recreate() {
@@ -627,6 +629,14 @@ void TextureCLUT8GPU::recreate() {
 		flagDirty();
 		_paletteDirty = true;
 	}
+
+	if (_clut8Pipeline == nullptr) {
+		_clut8Pipeline = new CLUT8LookUpPipeline();
+		// Setup pipeline.
+		_clut8Pipeline->setFramebuffer(_target);
+		_clut8Pipeline->setPaletteTexture(&_paletteTexture);
+		_clut8Pipeline->setColor(1.0f, 1.0f, 1.0f, 1.0f);
+	}
 }
 
 void TextureCLUT8GPU::enableLinearFiltering(bool enable) {
diff --git a/backends/graphics/opengl/texture.h b/backends/graphics/opengl/texture.h
index 95a1aa47447..1d3fb7769ff 100644
--- a/backends/graphics/opengl/texture.h
+++ b/backends/graphics/opengl/texture.h
@@ -34,8 +34,6 @@ class Scaler;
 
 namespace OpenGL {
 
-class Shader;
-
 /**
  * A simple GL texture object abstraction.
  *
diff --git a/backends/graphics3d/android/texture.cpp b/backends/graphics3d/android/texture.cpp
index 14b098da7c5..36782d8e0b3 100644
--- a/backends/graphics3d/android/texture.cpp
+++ b/backends/graphics3d/android/texture.cpp
@@ -51,7 +51,7 @@
 
 // Supported GL extensions
 bool GLESBaseTexture::_npot_supported = false;
-OpenGL::ShaderGL *GLESBaseTexture::_box_shader = nullptr;
+OpenGL::Shader *GLESBaseTexture::_box_shader = nullptr;
 GLuint GLESBaseTexture::_verticesVBO = 0;
 
 template<class T>
@@ -111,8 +111,8 @@ void GLESBaseTexture::initGL() {
 	_npot_supported = OpenGLContext.NPOTSupported;
 
 	const char *attributes[] = { "position", "texcoord", NULL };
-	_box_shader = OpenGL::ShaderGL::fromStrings("control", controlVertex, controlFragment, attributes);
-	_verticesVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, sizeof(vertices), vertices);
+	_box_shader = OpenGL::Shader::fromStrings("control", controlVertex, controlFragment, attributes);
+	_verticesVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(vertices), vertices);
 	_box_shader->enableVertexAttribute("position", _verticesVBO, 2, GL_FLOAT, GL_TRUE,
 	                                   2 * sizeof(float), 0);
 	_box_shader->enableVertexAttribute("texcoord", _verticesVBO, 2, GL_FLOAT, GL_TRUE,
diff --git a/backends/graphics3d/android/texture.h b/backends/graphics3d/android/texture.h
index e2b4a57cb5c..318115028d2 100644
--- a/backends/graphics3d/android/texture.h
+++ b/backends/graphics3d/android/texture.h
@@ -32,7 +32,7 @@
 #include "common/array.h"
 
 namespace OpenGL {
-class ShaderGL;
+class Shader;
 }
 
 class GLESBaseTexture {
@@ -194,7 +194,7 @@ protected:
 	bool _is_game_texture;
 
 	static bool _npot_supported;
-	static OpenGL::ShaderGL *_box_shader;
+	static OpenGL::Shader *_box_shader;
 	static GLuint _verticesVBO;
 
 };
diff --git a/backends/graphics3d/opengl/surfacerenderer.cpp b/backends/graphics3d/opengl/surfacerenderer.cpp
index 4fa46c50324..0afa4ad634b 100644
--- a/backends/graphics3d/opengl/surfacerenderer.cpp
+++ b/backends/graphics3d/opengl/surfacerenderer.cpp
@@ -223,8 +223,8 @@ ShaderSurfaceRenderer::ShaderSurfaceRenderer() {
 
 	// Setup the box shader used to render the overlay
 	const char *attributes[] = { "position", "texcoord", nullptr };
-	_boxShader = ShaderGL::fromStrings("box", boxVertex, boxFragment, attributes);
-	_boxVerticesVBO = ShaderGL::createBuffer(GL_ARRAY_BUFFER, sizeof(vertices), vertices);
+	_boxShader = Shader::fromStrings("box", boxVertex, boxFragment, attributes);
+	_boxVerticesVBO = Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(vertices), vertices);
 	_boxShader->enableVertexAttribute("position", _boxVerticesVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
 	_boxShader->enableVertexAttribute("texcoord", _boxVerticesVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
 }
@@ -270,7 +270,7 @@ void ShaderSurfaceRenderer::restorePreviousState() {
 }
 
 ShaderSurfaceRenderer::~ShaderSurfaceRenderer() {
-	ShaderGL::freeBuffer(_boxVerticesVBO);
+	Shader::freeBuffer(_boxVerticesVBO);
 
 	delete _boxShader;
 }
diff --git a/backends/graphics3d/opengl/surfacerenderer.h b/backends/graphics3d/opengl/surfacerenderer.h
index 889d4d9742d..6dba63ffde3 100644
--- a/backends/graphics3d/opengl/surfacerenderer.h
+++ b/backends/graphics3d/opengl/surfacerenderer.h
@@ -28,7 +28,7 @@
 
 namespace OpenGL {
 
-class ShaderGL;
+class Shader;
 class TextureGL;
 
 /**
@@ -103,7 +103,7 @@ public:
 	void restorePreviousState() override;
 
 private:
-	ShaderGL *_boxShader;
+	Shader *_boxShader;
 	GLuint _boxVerticesVBO;
 	GLboolean _prevStateDepthTest;
 	GLboolean _prevStateDepthWriteMask;
diff --git a/engines/grim/gfx_opengl_shaders.cpp b/engines/grim/gfx_opengl_shaders.cpp
index 5c0a931c048..803547feb27 100644
--- a/engines/grim/gfx_opengl_shaders.cpp
+++ b/engines/grim/gfx_opengl_shaders.cpp
@@ -103,7 +103,7 @@ struct GrimVertex {
 };
 
 struct TextUserData {
-	OpenGL::ShaderGL * shader;
+	OpenGL::Shader * shader;
 	uint32 characters;
 	Color  color;
 	GLuint texture;
@@ -115,8 +115,8 @@ struct FontUserData {
 };
 
 struct EMIModelUserData {
-	OpenGL::ShaderGL *_shader;
-	OpenGL::ShaderGL *_shaderLights;
+	OpenGL::Shader *_shader;
+	OpenGL::Shader *_shaderLights;
 	uint32 _texCoordsVBO;
 	uint32 _colorMapVBO;
 	uint32 _verticesVBO;
@@ -124,8 +124,8 @@ struct EMIModelUserData {
 };
 
 struct ModelUserData {
-	OpenGL::ShaderGL *_shader;
-	OpenGL::ShaderGL *_shaderLights;
+	OpenGL::Shader *_shader;
+	OpenGL::Shader *_shaderLights;
 	uint32 _meshInfoVBO;
 };
 
@@ -289,11 +289,11 @@ void GfxOpenGLS::setupQuadEBO() {
 		p[5] = start++;
 	}
 
-	_quadEBO = OpenGL::ShaderGL::createBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(quad_indices), quad_indices, GL_STATIC_DRAW);
+	_quadEBO = OpenGL::Shader::createBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(quad_indices), quad_indices, GL_STATIC_DRAW);
 }
 
 void GfxOpenGLS::setupTexturedQuad() {
-	_smushVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, sizeof(textured_quad), textured_quad, GL_STATIC_DRAW);
+	_smushVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(textured_quad), textured_quad, GL_STATIC_DRAW);
 	_smushProgram->enableVertexAttribute("position", _smushVBO, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
 	_smushProgram->enableVertexAttribute("texcoord", _smushVBO, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 2 * sizeof(float));
 
@@ -309,7 +309,7 @@ void GfxOpenGLS::setupTexturedQuad() {
 }
 
 void GfxOpenGLS::setupTexturedCenteredQuad() {
-	_spriteVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, sizeof(textured_quad_centered), textured_quad_centered, GL_STATIC_DRAW);
+	_spriteVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(textured_quad_centered), textured_quad_centered, GL_STATIC_DRAW);
 	_spriteProgram->enableVertexAttribute("position", _spriteVBO, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), 0);
 	_spriteProgram->enableVertexAttribute("texcoord", _spriteVBO, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), 3 * sizeof(float));
 	_spriteProgram->disableVertexAttribute("color", Math::Vector4d(1.0f, 1.0f, 1.0f, 1.0f));
@@ -371,27 +371,27 @@ void GfxOpenGLS::setupShaders() {
 	bool isEMI = g_grim->getGameType() == GType_MONKEY4;
 
 	static const char* commonAttributes[] = {"position", "texcoord", nullptr};
-	_backgroundProgram = OpenGL::ShaderGL::fromFiles(isEMI ? "emi_background" : "grim_background", commonAttributes);
-	_smushProgram = OpenGL::ShaderGL::fromFiles("grim_smush", commonAttributes);
-	_textProgram = OpenGL::ShaderGL::fromFiles("grim_text", commonAttributes);
-	_emergProgram = OpenGL::ShaderGL::fromFiles("grim_emerg", commonAttributes);
+	_backgroundProgram = OpenGL::Shader::fromFiles(isEMI ? "emi_background" : "grim_background", commonAttributes);
+	_smushProgram = OpenGL::Shader::fromFiles("grim_smush", commonAttributes);
+	_textProgram = OpenGL::Shader::fromFiles("grim_text", commonAttributes);
+	_emergProgram = OpenGL::Shader::fromFiles("grim_emerg", commonAttributes);
 
 	static const char* actorAttributes[] = {"position", "texcoord", "color", "normal", nullptr};
-	_actorProgram = OpenGL::ShaderGL::fromFiles(isEMI ? "emi_actor" : "grim_actor", actorAttributes);
-	_actorLightsProgram = OpenGL::ShaderGL::fromFiles(isEMI ? "emi_actorlights" : "grim_actorlights", actorAttributes);
-	_spriteProgram = OpenGL::ShaderGL::fromFiles(isEMI ? "emi_sprite" : "grim_actor", actorAttributes);
+	_actorProgram = OpenGL::Shader::fromFiles(isEMI ? "emi_actor" : "grim_actor", actorAttributes);
+	_actorLightsProgram = OpenGL::Shader::fromFiles(isEMI ? "emi_actorlights" : "grim_actorlights", actorAttributes);
+	_spriteProgram = OpenGL::Shader::fromFiles(isEMI ? "emi_sprite" : "grim_actor", actorAttributes);
 
 	static const char* primAttributes[] = { "position", nullptr };
-	_shadowPlaneProgram = OpenGL::ShaderGL::fromFiles("grim_shadowplane", primAttributes);
-	_primitiveProgram = OpenGL::ShaderGL::fromFiles("grim_primitive", primAttributes);
+	_shadowPlaneProgram = OpenGL::Shader::fromFiles("grim_shadowplane", primAttributes);
+	_primitiveProgram = OpenGL::Shader::fromFiles("grim_primitive", primAttributes);
 
 	if (!isEMI) {
 		_irisProgram = _primitiveProgram->clone();
 
-		_dimProgram = OpenGL::ShaderGL::fromFiles("grim_dim", commonAttributes);
+		_dimProgram = OpenGL::Shader::fromFiles("grim_dim", commonAttributes);
 		_dimRegionProgram = _dimProgram->clone();
 	} else {
-		_dimPlaneProgram = OpenGL::ShaderGL::fromFiles("emi_dimplane", primAttributes);
+		_dimPlaneProgram = OpenGL::Shader::fromFiles("emi_dimplane", primAttributes);
 	}
 
 	setupQuadEBO();
@@ -400,7 +400,7 @@ void GfxOpenGLS::setupShaders() {
 	setupPrimitives();
 
 	if (!isEMI) {
-		_blastVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, 128 * 16 * sizeof(float), nullptr, GL_DYNAMIC_DRAW);
+		_blastVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, 128 * 16 * sizeof(float), nullptr, GL_DYNAMIC_DRAW);
 	}
 }
 
@@ -729,7 +729,7 @@ void GfxOpenGLS::startActorDraw(const Actor *actor) {
 	Math::Matrix4 viewMatrix = _viewMatrix;
 	viewMatrix.transpose();
 
-	OpenGL::ShaderGL *shaders[] = { _spriteProgram, _actorProgram, _actorLightsProgram };
+	OpenGL::Shader *shaders[] = { _spriteProgram, _actorProgram, _actorLightsProgram };
 
 	if (g_grim->getGameType() == GType_MONKEY4) {
 		glEnable(GL_CULL_FACE);
@@ -950,8 +950,8 @@ void GfxOpenGLS::drawShadowPlanes() {
 		ShadowUserData *sud = new ShadowUserData;
 		_currentShadowArray->userData = sud;
 		sud->_numTriangles = numTriangles;
-		sud->_verticesVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, 3 * numVertices * sizeof(float), vertBuf, GL_STATIC_DRAW);
-		sud->_indicesVBO = OpenGL::ShaderGL::createBuffer(GL_ELEMENT_ARRAY_BUFFER, 3 * numTriangles * sizeof(uint16), idxBuf, GL_STATIC_DRAW);
+		sud->_verticesVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, 3 * numVertices * sizeof(float), vertBuf, GL_STATIC_DRAW);
+		sud->_indicesVBO = OpenGL::Shader::createBuffer(GL_ELEMENT_ARRAY_BUFFER, 3 * numTriangles * sizeof(uint16), idxBuf, GL_STATIC_DRAW);
 
 		delete[] vertBuf;
 		delete[] idxBuf;
@@ -1005,8 +1005,8 @@ void GfxOpenGLS::getShadowColor(byte *r, byte *g, byte *b) {
 void GfxOpenGLS::destroyShadow(Shadow *shadow) {
 	ShadowUserData *sud = static_cast<ShadowUserData *>(shadow->userData);
 	if (sud) {
-		OpenGL::ShaderGL::freeBuffer(sud->_verticesVBO);
-		OpenGL::ShaderGL::freeBuffer(sud->_indicesVBO);
+		OpenGL::Shader::freeBuffer(sud->_verticesVBO);
+		OpenGL::Shader::freeBuffer(sud->_indicesVBO);
 		delete sud;
 	}
 
@@ -1053,7 +1053,7 @@ void GfxOpenGLS::drawEMIModelFace(const EMIModel* model, const EMIMeshFace* face
 	if (face->_flags & EMIMeshFace::kAlphaBlend || face->_flags & EMIMeshFace::kUnknownBlend)
 		glEnable(GL_BLEND);
 	const EMIModelUserData *mud = (const EMIModelUserData *)model->_userData;
-	OpenGL::ShaderGL *actorShader;
+	OpenGL::Shader *actorShader;
 	if ((face->_flags & EMIMeshFace::kNoLighting) ? false : _lightsEnabled)
 		actorShader = mud->_shaderLights;
 	else
@@ -1074,7 +1074,7 @@ void GfxOpenGLS::drawMesh(const Mesh *mesh) {
 	const ModelUserData *mud = (const ModelUserData *)mesh->_userData;
 	if (!mud)
 		return;
-	OpenGL::ShaderGL *actorShader;
+	OpenGL::Shader *actorShader;
 	if (_lightsEnabled && !isShadowModeActive())
 		actorShader = mud->_shaderLights;
 	else
@@ -1390,11 +1390,11 @@ void GfxOpenGLS::createBitmap(BitmapData *bitmap) {
 			delete[] texData;
 		bitmap->freeData();
 
-		OpenGL::ShaderGL *shader = _backgroundProgram->clone();
+		OpenGL::Shader *shader = _backgroundProgram->clone();
 		bitmap->_userData = shader;
 
 		if (g_grim->getGameType() == GType_MONKEY4) {
-			GLuint vbo = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, bitmap->_numCoords * 4 * sizeof(float), bitmap->_texc, GL_STATIC_DRAW);
+			GLuint vbo = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, bitmap->_numCoords * 4 * sizeof(float), bitmap->_texc, GL_STATIC_DRAW);
 			shader->enableVertexAttribute("position", vbo, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
 			shader->enableVertexAttribute("texcoord", vbo, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 2*sizeof(float));
 		}
@@ -1408,7 +1408,7 @@ void GfxOpenGLS::createBitmap(BitmapData *bitmap) {
 void GfxOpenGLS::drawBitmap(const Bitmap *bitmap, int dx, int dy, uint32 layer) {
 	if (g_grim->getGameType() == GType_MONKEY4 && bitmap->_data && bitmap->_data->_texc) {
 		BitmapData *data = bitmap->_data;
-		OpenGL::ShaderGL *shader = (OpenGL::ShaderGL *)data->_userData;
+		OpenGL::Shader *shader = (OpenGL::Shader *)data->_userData;
 		GLuint *textures = (GLuint *)bitmap->getTexIds();
 
 		glDisable(GL_DEPTH_TEST);
@@ -1444,7 +1444,7 @@ void GfxOpenGLS::drawBitmap(const Bitmap *bitmap, int dx, int dy, uint32 layer)
 			glDisable(GL_BLEND);
 		}
 
-		OpenGL::ShaderGL *shader = (OpenGL::ShaderGL *)bitmap->_data->_userData;
+		OpenGL::Shader *shader = (OpenGL::Shader *)bitmap->_data->_userData;
 		shader->use();
 		glDisable(GL_DEPTH_TEST);
 		glDepthMask(GL_FALSE);
@@ -1508,7 +1508,7 @@ void GfxOpenGLS::destroyBitmap(BitmapData *bitmap) {
 		delete[] textures;
 		bitmap->_texIds = nullptr;
 	}
-	OpenGL::ShaderGL *shader = (OpenGL::ShaderGL *)bitmap->_userData;
+	OpenGL::Shader *shader = (OpenGL::Shader *)bitmap->_userData;
 	if (g_grim->getGameType() == GType_MONKEY4) {
 		glDeleteBuffers(1, &shader->getAttributeAt(0)._vbo);
 	}
@@ -1666,10 +1666,10 @@ void GfxOpenGLS::createTextObject(TextObject *text) {
 		glBindBuffer(GL_ARRAY_BUFFER, vbo);
 		glBufferSubData(GL_ARRAY_BUFFER, 0, numCharacters * 16 * sizeof(float), bufData);
 	} else {
-		vbo = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, numCharacters * 16 * sizeof(float), bufData, GL_STATIC_DRAW);
+		vbo = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, numCharacters * 16 * sizeof(float), bufData, GL_STATIC_DRAW);
 	}
 
-	OpenGL::ShaderGL * textShader = _textProgram->clone();
+	OpenGL::Shader * textShader = _textProgram->clone();
 	glBindBuffer(GL_ARRAY_BUFFER, vbo);
 
 	textShader->enableVertexAttribute("position", vbo, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
@@ -2079,15 +2079,15 @@ void GfxOpenGLS::renderZBitmaps(bool render) {
 void GfxOpenGLS::createEMIModel(EMIModel *model) {
 	EMIModelUserData *mud = new EMIModelUserData;
 	model->_userData = mud;
-	mud->_verticesVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, model->_numVertices * 3 * sizeof(float), model->_vertices, GL_STREAM_DRAW);
+	mud->_verticesVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, model->_numVertices * 3 * sizeof(float), model->_vertices, GL_STREAM_DRAW);
 
-	mud->_normalsVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, model->_numVertices * 3 * sizeof(float), model->_normals, GL_STREAM_DRAW);
+	mud->_normalsVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, model->_numVertices * 3 * sizeof(float), model->_normals, GL_STREAM_DRAW);
 
-	mud->_texCoordsVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, model->_numVertices * 2 * sizeof(float), model->_texVerts, GL_STATIC_DRAW);
+	mud->_texCoordsVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, model->_numVertices * 2 * sizeof(float), model->_texVerts, GL_STATIC_DRAW);
 
-	mud->_colorMapVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, model->_numVertices * 4 * sizeof(byte), model->_colorMap, GL_STATIC_DRAW);
+	mud->_colorMapVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, model->_numVertices * 4 * sizeof(byte), model->_colorMap, GL_STATIC_DRAW);
 
-	OpenGL::ShaderGL * actorShader = _actorProgram->clone();
+	OpenGL::Shader * actorShader = _actorProgram->clone();
 	actorShader->enableVertexAttribute("position", mud->_verticesVBO, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
 	actorShader->enableVertexAttribute("normal", mud->_normalsVBO, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
 	actorShader->enableVertexAttribute("texcoord", mud->_texCoordsVBO, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0);
@@ -2103,7 +2103,7 @@ void GfxOpenGLS::createEMIModel(EMIModel *model) {
 
 	for (uint32 i = 0; i < model->_numFaces; ++i) {
 		EMIMeshFace * face = &model->_faces[i];
-		face->_indicesEBO = OpenGL::ShaderGL::createBuffer(GL_ELEMENT_ARRAY_BUFFER, face->_faceLength * 3 * sizeof(uint16), face->_indexes, GL_STATIC_DRAW);
+		face->_indicesEBO = OpenGL::Shader::createBuffer(GL_ELEMENT_ARRAY_BUFFER, face->_faceLength * 3 * sizeof(uint16), face->_indexes, GL_STATIC_DRAW);
 	}
 
 	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@@ -2112,17 +2112,17 @@ void GfxOpenGLS::createEMIModel(EMIModel *model) {
 void GfxOpenGLS::destroyEMIModel(EMIModel *model) {
 	for (uint32 i = 0; i < model->_numFaces; ++i) {
 		EMIMeshFace *face = &model->_faces[i];
-		OpenGL::ShaderGL::freeBuffer(face->_indicesEBO);
+		OpenGL::Shader::freeBuffer(face->_indicesEBO);
 		face->_indicesEBO = 0;
 	}
 
 	EMIModelUserData *mud = static_cast<EMIModelUserData *>(model->_userData);
 
 	if (mud) {
-		OpenGL::ShaderGL::freeBuffer(mud->_verticesVBO);
-		OpenGL::ShaderGL::freeBuffer(mud->_normalsVBO);
-		OpenGL::ShaderGL::freeBuffer(mud->_texCoordsVBO);
-		OpenGL::ShaderGL::freeBuffer(mud->_colorMapVBO);
+		OpenGL::Shader::freeBuffer(mud->_verticesVBO);
+		OpenGL::Shader::freeBuffer(mud->_normalsVBO);
+		OpenGL::Shader::freeBuffer(mud->_texCoordsVBO);
+		OpenGL::Shader::freeBuffer(mud->_colorMapVBO);
 
 		delete mud->_shader;
 		delete mud;
@@ -2166,9 +2166,9 @@ void GfxOpenGLS::createMesh(Mesh *mesh) {
 	ModelUserData *mud = new ModelUserData;
 	mesh->_userData = mud;
 
-	mud->_meshInfoVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, meshInfo.size() * sizeof(GrimVertex), &meshInfo[0], GL_STATIC_DRAW);
+	mud->_meshInfoVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, meshInfo.size() * sizeof(GrimVertex), &meshInfo[0], GL_STATIC_DRAW);
 
-	OpenGL::ShaderGL *actorShader = _actorProgram->clone();
+	OpenGL::Shader *actorShader = _actorProgram->clone();
 	actorShader->enableVertexAttribute("position", mud->_meshInfoVBO, 3, GL_FLOAT, GL_FALSE, sizeof(GrimVertex), 0);
 	actorShader->enableVertexAttribute("texcoord", mud->_meshInfoVBO, 2, GL_FLOAT, GL_FALSE, sizeof(GrimVertex), 3 * sizeof(float));
 	actorShader->enableVertexAttribute("normal", mud->_meshInfoVBO, 3, GL_FLOAT, GL_FALSE, sizeof(GrimVertex), 5 * sizeof(float));
diff --git a/engines/grim/gfx_opengl_shaders.h b/engines/grim/gfx_opengl_shaders.h
index b60f2ab4d01..7034788ef83 100644
--- a/engines/grim/gfx_opengl_shaders.h
+++ b/engines/grim/gfx_opengl_shaders.h
@@ -222,21 +222,21 @@ private:
 	float _alpha;
 	int _maxLights;
 	GLuint _emergTexture;
-	OpenGL::ShaderGL* _emergProgram;
-
-	OpenGL::ShaderGL* _backgroundProgram;
-	OpenGL::ShaderGL* _actorProgram;
-	OpenGL::ShaderGL* _actorLightsProgram;
-	OpenGL::ShaderGL* _spriteProgram;
-	OpenGL::ShaderGL* _dimProgram;
-	OpenGL::ShaderGL* _dimPlaneProgram;
-	OpenGL::ShaderGL* _dimRegionProgram;
-	OpenGL::ShaderGL* _smushProgram;
+	OpenGL::Shader* _emergProgram;
+
+	OpenGL::Shader* _backgroundProgram;
+	OpenGL::Shader* _actorProgram;
+	OpenGL::Shader* _actorLightsProgram;
+	OpenGL::Shader* _spriteProgram;
+	OpenGL::Shader* _dimProgram;
+	OpenGL::Shader* _dimPlaneProgram;
+	OpenGL::Shader* _dimRegionProgram;
+	OpenGL::Shader* _smushProgram;
 	GLuint _smushVBO, _quadEBO;
-	OpenGL::ShaderGL* _textProgram;
-	OpenGL::ShaderGL* _primitiveProgram;
-	OpenGL::ShaderGL* _irisProgram;
-	OpenGL::ShaderGL* _shadowPlaneProgram;
+	OpenGL::Shader* _textProgram;
+	OpenGL::Shader* _primitiveProgram;
+	OpenGL::Shader* _irisProgram;
+	OpenGL::Shader* _shadowPlaneProgram;
 
 	int _smushWidth;
 	int _smushHeight;
diff --git a/engines/myst3/gfx_opengl_shaders.cpp b/engines/myst3/gfx_opengl_shaders.cpp
index 58dbe7d9e77..5c9ca164329 100644
--- a/engines/myst3/gfx_opengl_shaders.cpp
+++ b/engines/myst3/gfx_opengl_shaders.cpp
@@ -78,7 +78,7 @@ void ShaderRenderer::setupQuadEBO() {
 		p[5] = start++;
 	}
 
-	_quadEBO = OpenGL::ShaderGL::createBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(quadIndices), quadIndices, GL_STATIC_DRAW);
+	_quadEBO = OpenGL::Shader::createBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(quadIndices), quadIndices, GL_STATIC_DRAW);
 }
 
 Math::Vector2d ShaderRenderer::scaled(float x, float y) const {
@@ -102,11 +102,11 @@ ShaderRenderer::ShaderRenderer(OSystem *system) :
 }
 
 ShaderRenderer::~ShaderRenderer() {
-	OpenGL::ShaderGL::freeBuffer(_boxVBO);
-	OpenGL::ShaderGL::freeBuffer(_cubeVBO);
-	OpenGL::ShaderGL::freeBuffer(_rect3dVBO);
-	OpenGL::ShaderGL::freeBuffer(_textVBO);
-	OpenGL::ShaderGL::freeBuffer(_quadEBO);
+	OpenGL::Shader::freeBuffer(_boxVBO);
+	OpenGL::Shader::freeBuffer(_cubeVBO);
+	OpenGL::Shader::freeBuffer(_rect3dVBO);
+	OpenGL::Shader::freeBuffer(_textVBO);
+	OpenGL::Shader::freeBuffer(_quadEBO);
 
 	delete _boxShader;
 	delete _cubeShader;
@@ -126,23 +126,23 @@ void ShaderRenderer::init() {
 	glEnable(GL_DEPTH_TEST);
 
 	static const char* attributes[] = { "position", "texcoord", nullptr };
-	_boxShader = OpenGL::ShaderGL::fromFiles("myst3_box", attributes);
-	_boxVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, sizeof(boxVertices), boxVertices);
+	_boxShader = OpenGL::Shader::fromFiles("myst3_box", attributes);
+	_boxVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(boxVertices), boxVertices);
 	_boxShader->enableVertexAttribute("position", _boxVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
 	_boxShader->enableVertexAttribute("texcoord", _boxVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
 
-	_cubeShader = OpenGL::ShaderGL::fromFiles("myst3_cube", attributes);
-	_cubeVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, sizeof(cubeVertices), cubeVertices);
+	_cubeShader = OpenGL::Shader::fromFiles("myst3_cube", attributes);
+	_cubeVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(cubeVertices), cubeVertices);
 	_cubeShader->enableVertexAttribute("texcoord", _cubeVBO, 2, GL_FLOAT, GL_TRUE, 5 * sizeof(float), 0);
 	_cubeShader->enableVertexAttribute("position", _cubeVBO, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), 2 * sizeof(float));
 
-	_rect3dShader = OpenGL::ShaderGL::fromFiles("myst3_cube", attributes);
-	_rect3dVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, 20 * sizeof(float), nullptr);
+	_rect3dShader = OpenGL::Shader::fromFiles("myst3_cube", attributes);
+	_rect3dVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, 20 * sizeof(float), nullptr);
 	_rect3dShader->enableVertexAttribute("texcoord", _rect3dVBO, 2, GL_FLOAT, GL_TRUE, 5 * sizeof(float), 0);
 	_rect3dShader->enableVertexAttribute("position", _rect3dVBO, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), 2 * sizeof(float));
 
-	_textShader = OpenGL::ShaderGL::fromFiles("myst3_text", attributes);
-	_textVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, 100 * 16 * sizeof(float), nullptr, GL_DYNAMIC_DRAW);
+	_textShader = OpenGL::Shader::fromFiles("myst3_text", attributes);
+	_textVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, 100 * 16 * sizeof(float), nullptr, GL_DYNAMIC_DRAW);
 	_textShader->enableVertexAttribute("texcoord", _textVBO, 2, GL_FLOAT, GL_TRUE, 4 * sizeof(float), 0);
 	_textShader->enableVertexAttribute("position", _textVBO, 2, GL_FLOAT, GL_TRUE, 4 * sizeof(float), 2 * sizeof(float));
 
diff --git a/engines/myst3/gfx_opengl_shaders.h b/engines/myst3/gfx_opengl_shaders.h
index 4326dc0cfc1..2a89ac46a2d 100644
--- a/engines/myst3/gfx_opengl_shaders.h
+++ b/engines/myst3/gfx_opengl_shaders.h
@@ -61,10 +61,10 @@ private:
 	void setupQuadEBO();
 	Math::Vector2d scaled(float x, float y) const;
 
-	OpenGL::ShaderGL *_boxShader;
-	OpenGL::ShaderGL *_cubeShader;
-	OpenGL::ShaderGL *_rect3dShader;
-	OpenGL::ShaderGL *_textShader;
+	OpenGL::Shader *_boxShader;
+	OpenGL::Shader *_cubeShader;
+	OpenGL::Shader *_rect3dShader;
+	OpenGL::Shader *_textShader;
 
 	GLuint _boxVBO;
 	GLuint _cubeVBO;
diff --git a/engines/playground3d/gfx_opengl_shaders.cpp b/engines/playground3d/gfx_opengl_shaders.cpp
index 71cafb7d695..ee35a6f818c 100644
--- a/engines/playground3d/gfx_opengl_shaders.cpp
+++ b/engines/playground3d/gfx_opengl_shaders.cpp
@@ -70,9 +70,9 @@ ShaderRenderer::ShaderRenderer(OSystem *system) :
 }
 
 ShaderRenderer::~ShaderRenderer() {
-	OpenGL::ShaderGL::freeBuffer(_cubeVBO);
-	OpenGL::ShaderGL::freeBuffer(_fadeVBO);
-	OpenGL::ShaderGL::freeBuffer(_bitmapVBO);
+	OpenGL::Shader::freeBuffer(_cubeVBO);
+	OpenGL::Shader::freeBuffer(_fadeVBO);
+	OpenGL::Shader::freeBuffer(_bitmapVBO);
 
 	delete _cubeShader;
 	delete _fadeShader;
@@ -87,21 +87,21 @@ void ShaderRenderer::init() {
 	glEnable(GL_DEPTH_TEST);
 
 	static const char *cubeAttributes[] = { "position", "normal", "color", "texcoord", nullptr };
-	_cubeShader = OpenGL::ShaderGL::fromFiles("playground3d_cube", cubeAttributes);
-	_cubeVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, sizeof(cubeVertices), cubeVertices);
+	_cubeShader = OpenGL::Shader::fromFiles("playground3d_cube", cubeAttributes);
+	_cubeVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(cubeVertices), cubeVertices);
 	_cubeShader->enableVertexAttribute("texcoord", _cubeVBO, 2, GL_FLOAT, GL_FALSE, 11 * sizeof(float), 0);
 	_cubeShader->enableVertexAttribute("position", _cubeVBO, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), 8);
 	_cubeShader->enableVertexAttribute("normal", _cubeVBO, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), 20);
 	_cubeShader->enableVertexAttribute("color", _cubeVBO, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), 32);
 
 	static const char *fadeAttributes[] = { "position", nullptr };
-	_fadeShader = OpenGL::ShaderGL::fromFiles("playground3d_fade", fadeAttributes);
-	_fadeVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, sizeof(dimRegionVertices), dimRegionVertices);
+	_fadeShader = OpenGL::Shader::fromFiles("playground3d_fade", fadeAttributes);
+	_fadeVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(dimRegionVertices), dimRegionVertices);
 	_fadeShader->enableVertexAttribute("position", _fadeVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
 
 	static const char *bitmapAttributes[] = { "position", "texcoord", nullptr };
-	_bitmapShader = OpenGL::ShaderGL::fromFiles("playground3d_bitmap", bitmapAttributes);
-	_bitmapVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, sizeof(bitmapVertices), bitmapVertices);
+	_bitmapShader = OpenGL::Shader::fromFiles("playground3d_bitmap", bitmapAttributes);
+	_bitmapVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(bitmapVertices), bitmapVertices);
 	_bitmapShader->enableVertexAttribute("position", _bitmapVBO, 2, GL_FLOAT, GL_TRUE, 4 * sizeof(float), 0);
 	_bitmapShader->enableVertexAttribute("texcoord", _bitmapVBO, 2, GL_FLOAT, GL_TRUE, 4 * sizeof(float), 8);
 
diff --git a/engines/playground3d/gfx_opengl_shaders.h b/engines/playground3d/gfx_opengl_shaders.h
index 1ff57e3591d..0dee71431d1 100644
--- a/engines/playground3d/gfx_opengl_shaders.h
+++ b/engines/playground3d/gfx_opengl_shaders.h
@@ -58,9 +58,9 @@ public:
 	void enableFog(const Math::Vector4d &fogColor) override;
 
 private:
-	OpenGL::ShaderGL *_cubeShader;
-	OpenGL::ShaderGL *_fadeShader;
-	OpenGL::ShaderGL *_bitmapShader;
+	OpenGL::Shader *_cubeShader;
+	OpenGL::Shader *_fadeShader;
+	OpenGL::Shader *_bitmapShader;
 
 	GLuint _cubeVBO;
 	GLuint _fadeVBO;
diff --git a/engines/stark/gfx/opengls.cpp b/engines/stark/gfx/opengls.cpp
index bfce200afa8..d3786e79201 100644
--- a/engines/stark/gfx/opengls.cpp
+++ b/engines/stark/gfx/opengls.cpp
@@ -65,8 +65,8 @@ OpenGLSDriver::OpenGLSDriver() :
 }
 
 OpenGLSDriver::~OpenGLSDriver() {
-	OpenGL::ShaderGL::freeBuffer(_surfaceVBO);
-	OpenGL::ShaderGL::freeBuffer(_fadeVBO);
+	OpenGL::Shader::freeBuffer(_surfaceVBO);
+	OpenGL::Shader::freeBuffer(_fadeVBO);
 	delete _surfaceShader;
 	delete _actorShader;
 	delete _fadeShader;
@@ -77,20 +77,20 @@ void OpenGLSDriver::init() {
 	computeScreenViewport();
 
 	static const char* attributes[] = { "position", "texcoord", nullptr };
-	_surfaceShader = OpenGL::ShaderGL::fromFiles("stark_surface", attributes);
-	_surfaceVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, sizeof(surfaceVertices), surfaceVertices);
+	_surfaceShader = OpenGL::Shader::fromFiles("stark_surface", attributes);
+	_surfaceVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(surfaceVertices), surfaceVertices);
 	_surfaceShader->enableVertexAttribute("position", _surfaceVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
 	_surfaceShader->enableVertexAttribute("texcoord", _surfaceVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
 
 	static const char* actorAttributes[] = { "position1", "position2", "bone1", "bone2", "boneWeight", "normal", "texcoord", nullptr };
-	_actorShader = OpenGL::ShaderGL::fromFiles("stark_actor", actorAttributes);
+	_actorShader = OpenGL::Shader::fromFiles("stark_actor", actorAttributes);
 
 	static const char* shadowAttributes[] = { "position1", "position2", "bone1", "bone2", "boneWeight", nullptr };
-	_shadowShader = OpenGL::ShaderGL::fromFiles("stark_shadow", shadowAttributes);
+	_shadowShader = OpenGL::Shader::fromFiles("stark_shadow", shadowAttributes);
 
 	static const char* fadeAttributes[] = { "position", nullptr };
-	_fadeShader = OpenGL::ShaderGL::fromFiles("stark_fade", fadeAttributes);
-	_fadeVBO = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, sizeof(fadeVertices), fadeVertices);
+	_fadeShader = OpenGL::Shader::fromFiles("stark_fade", fadeAttributes);
+	_fadeVBO = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(fadeVertices), fadeVertices);
 	_fadeShader->enableVertexAttribute("position", _fadeVBO, 2, GL_FLOAT, GL_TRUE, 2 * sizeof(float), 0);
 }
 
@@ -205,19 +205,19 @@ Common::Rect OpenGLSDriver::getUnscaledViewport() const {
 	return _unscaledViewport;
 }
 
-OpenGL::ShaderGL *OpenGLSDriver::createActorShaderInstance() {
+OpenGL::Shader *OpenGLSDriver::createActorShaderInstance() {
 	return _actorShader->clone();
 }
 
-OpenGL::ShaderGL *OpenGLSDriver::createSurfaceShaderInstance() {
+OpenGL::Shader *OpenGLSDriver::createSurfaceShaderInstance() {
 	return _surfaceShader->clone();
 }
 
-OpenGL::ShaderGL *OpenGLSDriver::createFadeShaderInstance() {
+OpenGL::Shader *OpenGLSDriver::createFadeShaderInstance() {
 	return _fadeShader->clone();
 }
 
-OpenGL::ShaderGL *OpenGLSDriver::createShadowShaderInstance() {
+OpenGL::Shader *OpenGLSDriver::createShadowShaderInstance() {
 	return _shadowShader->clone();
 }
 
diff --git a/engines/stark/gfx/opengls.h b/engines/stark/gfx/opengls.h
index d8e84756dd7..fd36d3d2db8 100644
--- a/engines/stark/gfx/opengls.h
+++ b/engines/stark/gfx/opengls.h
@@ -31,7 +31,7 @@
 #include "graphics/opengl/system_headers.h"
 
 namespace OpenGL {
-class ShaderGL;
+class Shader;
 }
 
 namespace Stark {
@@ -57,10 +57,10 @@ public:
 	SurfaceRenderer *createSurfaceRenderer() override;
 	FadeRenderer *createFadeRenderer() override;
 
-	OpenGL::ShaderGL *createActorShaderInstance();
-	OpenGL::ShaderGL *createSurfaceShaderInstance();
-	OpenGL::ShaderGL *createFadeShaderInstance();
-	OpenGL::ShaderGL *createShadowShaderInstance();
+	OpenGL::Shader *createActorShaderInstance();
+	OpenGL::Shader *createSurfaceShaderInstance();
+	OpenGL::Shader *createFadeShaderInstance();
+	OpenGL::Shader *createShadowShaderInstance();
 
 	void start2DMode();
 	void end2DMode();
@@ -76,10 +76,10 @@ private:
 	Common::Rect _viewport;
 	Common::Rect _unscaledViewport;
 
-	OpenGL::ShaderGL *_surfaceShader;
-	OpenGL::ShaderGL *_actorShader;
-	OpenGL::ShaderGL *_fadeShader;
-	OpenGL::ShaderGL *_shadowShader;
+	OpenGL::Shader *_surfaceShader;
+	OpenGL::Shader *_actorShader;
+	OpenGL::Shader *_fadeShader;
+	OpenGL::Shader *_shadowShader;
 	GLuint _surfaceVBO;
 	GLuint _fadeVBO;
 };
diff --git a/engines/stark/gfx/openglsactor.cpp b/engines/stark/gfx/openglsactor.cpp
index fc6bfc7370d..630e6fcf923 100644
--- a/engines/stark/gfx/openglsactor.cpp
+++ b/engines/stark/gfx/openglsactor.cpp
@@ -155,11 +155,11 @@ void OpenGLSActorRenderer::render(const Math::Vector3d &position, float directio
 }
 
 void OpenGLSActorRenderer::clearVertices() {
-	OpenGL::ShaderGL::freeBuffer(_faceVBO); // Zero names are silently ignored
+	OpenGL::Shader::freeBuffer(_faceVBO); // Zero names are silently ignored
 	_faceVBO = 0;
 
 	for (FaceBufferMap::iterator it = _faceEBO.begin(); it != _faceEBO.end(); ++it) {
-		OpenGL::ShaderGL::freeBuffer(it->_value);
+		OpenGL::Shader::freeBuffer(it->_value);
 	}
 
 	_faceEBO.clear();
@@ -203,17 +203,17 @@ GLuint OpenGLSActorRenderer::createModelVBO(const Model *model) {
 		*vertPtr++ = (*tri)->_texT;
 	}
 
-	GLuint vbo = OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, sizeof(float) * 14 * modelVertices.size(), vertices);
+	GLuint vbo = OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(float) * 14 * modelVertices.size(), vertices);
 	delete[] vertices;
 
 	return vbo;
 }
 
 GLuint OpenGLSActorRenderer::createFaceEBO(const Face *face) {
-	return OpenGL::ShaderGL::createBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32) * face->vertexIndices.size(), &face->vertexIndices[0]);
+	return OpenGL::Shader::createBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32) * face->vertexIndices.size(), &face->vertexIndices[0]);
 }
 
-void OpenGLSActorRenderer::setBonePositionArrayUniform(OpenGL::ShaderGL *shader, const char *uniform) {
+void OpenGLSActorRenderer::setBonePositionArrayUniform(OpenGL::Shader *shader, const char *uniform) {
 	const Common::Array<BoneNode *> &bones = _model->getBones();
 
 	GLint pos = shader->getUniformLocation(uniform);
@@ -234,7 +234,7 @@ void OpenGLSActorRenderer::setBonePositionArrayUniform(OpenGL::ShaderGL *shader,
 	delete[] positions;
 }
 
-void OpenGLSActorRenderer::setBoneRotationArrayUniform(OpenGL::ShaderGL *shader, const char *uniform) {
+void OpenGLSActorRenderer::setBoneRotationArrayUniform(OpenGL::Shader *shader, const char *uniform) {
 	const Common::Array<BoneNode *> &bones = _model->getBones();
 
 	GLint rot = shader->getUniformLocation(uniform);
diff --git a/engines/stark/gfx/openglsactor.h b/engines/stark/gfx/openglsactor.h
index 65cc04e3194..6cddae0477c 100644
--- a/engines/stark/gfx/openglsactor.h
+++ b/engines/stark/gfx/openglsactor.h
@@ -33,7 +33,7 @@
 #if defined(USE_OPENGL_SHADERS)
 
 namespace OpenGL {
-	class ShaderGL;
+	class Shader;
 }
 
 namespace Stark {
@@ -52,7 +52,7 @@ protected:
 	typedef Common::HashMap<Face *, GLuint> FaceBufferMap;
 
 	OpenGLSDriver *_gfx;
-	OpenGL::ShaderGL *_shader, *_shadowShader;
+	OpenGL::Shader *_shader, *_shadowShader;
 
 	GLuint _faceVBO;
 	FaceBufferMap _faceEBO;
@@ -61,8 +61,8 @@ protected:
 	void uploadVertices();
 	GLuint createModelVBO(const Model *model);
 	GLuint createFaceEBO(const Face *face);
-	void setBonePositionArrayUniform(OpenGL::ShaderGL *shader, const char *uniform);
-	void setBoneRotationArrayUniform(OpenGL::ShaderGL *shader, const char *uniform);
+	void setBonePositionArrayUniform(OpenGL::Shader *shader, const char *uniform);
+	void setBoneRotationArrayUniform(OpenGL::Shader *shader, const char *uniform);
 	void setLightArrayUniform(const LightEntryArray &lights);
 
 	void setShadowUniform(const LightEntryArray &lights, const Math::Vector3d &actorPosition, Math::Matrix3 worldToModelRot);
diff --git a/engines/stark/gfx/openglsfade.h b/engines/stark/gfx/openglsfade.h
index 2efa44b3b7f..8f521464296 100644
--- a/engines/stark/gfx/openglsfade.h
+++ b/engines/stark/gfx/openglsfade.h
@@ -29,7 +29,7 @@
 #include "engines/stark/gfx/faderenderer.h"
 
 namespace OpenGL {
-class ShaderGL;
+class Shader;
 }
 
 namespace Stark {
@@ -50,7 +50,7 @@ public:
 
 private:
 	OpenGLSDriver *_gfx;
-	OpenGL::ShaderGL *_shader;
+	OpenGL::Shader *_shader;
 };
 
 } // End of namespace Gfx
diff --git a/engines/stark/gfx/openglsprop.cpp b/engines/stark/gfx/openglsprop.cpp
index 9b1bc9f6570..9fda2833eaa 100644
--- a/engines/stark/gfx/openglsprop.cpp
+++ b/engines/stark/gfx/openglsprop.cpp
@@ -40,7 +40,7 @@ OpenGLSPropRenderer::OpenGLSPropRenderer(Driver *gfx) :
 		_faceVBO(0),
 		_modelIsDirty(true) {
 	static const char* attributes[] = { "position", "normal", "texcoord", nullptr };
-	_shader = OpenGL::ShaderGL::fromFiles("stark_prop", attributes);
+	_shader = OpenGL::Shader::fromFiles("stark_prop", attributes);
 }
 
 OpenGLSPropRenderer::~OpenGLSPropRenderer() {
@@ -109,10 +109,10 @@ void OpenGLSPropRenderer::render(const Math::Vector3d &position, float direction
 }
 
 void OpenGLSPropRenderer::clearVertices() {
-	OpenGL::ShaderGL::freeBuffer(_faceVBO);
+	OpenGL::Shader::freeBuffer(_faceVBO);
 
 	for (FaceBufferMap::iterator it = _faceEBO.begin(); it != _faceEBO.end(); ++it) {
-		OpenGL::ShaderGL::freeBuffer(it->_value);
+		OpenGL::Shader::freeBuffer(it->_value);
 	}
 
 	_faceEBO.clear();
@@ -130,11 +130,11 @@ void OpenGLSPropRenderer::uploadVertices() {
 GLuint OpenGLSPropRenderer::createFaceVBO() {
 	const Common::Array<Formats::BiffMesh::Vertex> &vertices = _model->getVertices();
 
-	return OpenGL::ShaderGL::createBuffer(GL_ARRAY_BUFFER, sizeof(float) * 9 * vertices.size(), &vertices.front());
+	return OpenGL::Shader::createBuffer(GL_ARRAY_BUFFER, sizeof(float) * 9 * vertices.size(), &vertices.front());
 }
 
 GLuint OpenGLSPropRenderer::createFaceEBO(const Face *face) {
-	return OpenGL::ShaderGL::createBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32) * face->vertexIndices.size(), &face->vertexIndices.front());
+	return OpenGL::Shader::createBuffer(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32) * face->vertexIndices.size(), &face->vertexIndices.front());
 }
 
 void OpenGLSPropRenderer::setLightArrayUniform(const LightEntryArray &lights) {
diff --git a/engines/stark/gfx/openglsprop.h b/engines/stark/gfx/openglsprop.h
index c02a4338386..7cb109ceb4a 100644
--- a/engines/stark/gfx/openglsprop.h
+++ b/engines/stark/gfx/openglsprop.h
@@ -33,7 +33,7 @@
 #if defined(USE_OPENGL_SHADERS)
 
 namespace OpenGL {
-	class ShaderGL;
+	class Shader;
 }
 
 namespace Stark {
@@ -53,7 +53,7 @@ protected:
 	typedef Common::HashMap<const Face *, GLuint> FaceBufferMap;
 
 	Driver *_gfx;
-	OpenGL::ShaderGL *_shader;
+	OpenGL::Shader *_shader;
 
 	bool _modelIsDirty;
 	GLuint _faceVBO;
diff --git a/engines/stark/gfx/openglssurface.h b/engines/stark/gfx/openglssurface.h
index 6501a694159..4cf8acf277b 100644
--- a/engines/stark/gfx/openglssurface.h
+++ b/engines/stark/gfx/openglssurface.h
@@ -29,7 +29,7 @@
 #if defined(USE_OPENGL_SHADERS)
 
 namespace OpenGL {
-class ShaderGL;
+class Shader;
 }
 
 namespace Stark {
@@ -55,7 +55,7 @@ private:
 	Math::Vector2d normalizeCurrentCoordinates(int x, int y) const;
 
 	OpenGLSDriver *_gfx;
-	OpenGL::ShaderGL *_shader;
+	OpenGL::Shader *_shader;
 };
 
 } // End of namespace Gfx
diff --git a/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.cpp b/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.cpp
index c9bc5c0fac7..9e349e85e85 100644
--- a/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.cpp
+++ b/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.cpp
@@ -232,7 +232,7 @@ bool BaseRenderOpenGL3DShader::enableShadows() {
 		glBufferData(GL_ARRAY_BUFFER, 4 * 12, flatShadowMaskVertices, GL_STATIC_DRAW);
 
 		static const char *flatShadowMaskAttributes[] = { "position", nullptr };
-		_flatShadowMaskShader = OpenGL::ShaderGL::fromFiles("wme_flat_shadow_mask", flatShadowMaskAttributes);
+		_flatShadowMaskShader = OpenGL::Shader::fromFiles("wme_flat_shadow_mask", flatShadowMaskAttributes);
 		_flatShadowMaskShader->enableVertexAttribute("position", _flatShadowMaskVBO, 3, GL_FLOAT, false, 12, 0);
 
 		_flatShadowMaskShader->use();
@@ -490,26 +490,26 @@ bool BaseRenderOpenGL3DShader::initRenderer(int width, int height, bool windowed
 	glBindBuffer(GL_ARRAY_BUFFER, 0);
 
 	static const char *spriteAttributes[] = {"position", "texcoord", "color", nullptr};
-	_spriteShader = OpenGL::ShaderGL::fromFiles("wme_sprite", spriteAttributes);
+	_spriteShader = OpenGL::Shader::fromFiles("wme_sprite", spriteAttributes);
 
 	_spriteShader->enableVertexAttribute("position", _spriteVBO, 2, GL_FLOAT, false, sizeof(SpriteVertexShader), 0);
 	_spriteShader->enableVertexAttribute("texcoord", _spriteVBO, 2, GL_FLOAT, false, sizeof(SpriteVertexShader), 8);
 	_spriteShader->enableVertexAttribute("color", _spriteVBO, 4, GL_FLOAT, false, sizeof(SpriteVertexShader), 16);
 
 	static const char *geometryAttributes[] = { "position", nullptr };
-	_geometryShader = OpenGL::ShaderGL::fromFiles("wme_geometry", geometryAttributes);
+	_geometryShader = OpenGL::Shader::fromFiles("wme_geometry", geometryAttributes);
 
 	static const char *shadowVolumeAttributes[] = { "position", nullptr };
-	_shadowVolumeShader = OpenGL::ShaderGL::fromFiles("wme_shadow_volume", shadowVolumeAttributes);
+	_shadowVolumeShader = OpenGL::Shader::fromFiles("wme_shadow_volume", shadowVolumeAttributes);
 
 	static const char *shadowMaskAttributes[] = { "position", nullptr };
-	_shadowMaskShader = OpenGL::ShaderGL::fromFiles("wme_shadow_mask", shadowMaskAttributes);
+	_shadowMaskShader = OpenGL::Shader::fromFiles("wme_shadow_mask", shadowMaskAttributes);
 
 	_transformStack.push_back(Math::Matrix4());
 	_transformStack.back().setToIdentity();
 
 	static const char *modelXAttributes[] = {"position", "texcoord", "normal", nullptr};
-	_modelXShader = OpenGL::ShaderGL::fromFiles("wme_modelx", modelXAttributes);
+	_modelXShader = OpenGL::Shader::fromFiles("wme_modelx", modelXAttributes);
 
 	setDefaultAmbientLightColor();
 
@@ -544,7 +544,7 @@ bool BaseRenderOpenGL3DShader::initRenderer(int width, int height, bool windowed
 	glBindBuffer(GL_ARRAY_BUFFER, 0);
 
 	static const char *fadeAttributes[] = { "position", nullptr };
-	_fadeShader = OpenGL::ShaderGL::fromFiles("wme_fade", fadeAttributes);
+	_fadeShader = OpenGL::Shader::fromFiles("wme_fade", fadeAttributes);
 
 	_fadeShader->enableVertexAttribute("position", _fadeVBO, 2, GL_FLOAT, false, 8, 0);
 
@@ -554,11 +554,11 @@ bool BaseRenderOpenGL3DShader::initRenderer(int width, int height, bool windowed
 	glBindBuffer(GL_ARRAY_BUFFER, 0);
 
 	static const char *lineAttributes[] = { "position", nullptr };
-	_lineShader = OpenGL::ShaderGL::fromFiles("wme_line", lineAttributes);
+	_lineShader = OpenGL::Shader::fromFiles("wme_line", lineAttributes);
 	_lineShader->enableVertexAttribute("position", _lineVBO, 2, GL_FLOAT, false, 8, 0);
 
 	static const char *flatShadowModelXAttributes[] = { "position", nullptr };
-	_flatShadowModelXShader = OpenGL::ShaderGL::fromFiles("wme_flat_shadow_modelx", flatShadowModelXAttributes);
+	_flatShadowModelXShader = OpenGL::Shader::fromFiles("wme_flat_shadow_modelx", flatShadowModelXAttributes);
 
 	_active = true;
 	// setup a proper state
diff --git a/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.h b/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.h
index e720779945d..a15dd69e9c6 100644
--- a/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.h
+++ b/engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.h
@@ -148,15 +148,15 @@ private:
 	GLuint _flatShadowFrameBuffer;
 	GLuint _flatShadowRenderTexture;
 	GLuint _flatShadowDepthBuffer;
-	OpenGL::ShaderGL *_spriteShader;
-	OpenGL::ShaderGL *_fadeShader;
-	OpenGL::ShaderGL *_modelXShader;
-	OpenGL::ShaderGL *_geometryShader;
-	OpenGL::ShaderGL *_shadowVolumeShader;
-	OpenGL::ShaderGL *_shadowMaskShader;
-	OpenGL::ShaderGL *_lineShader;
-	OpenGL::ShaderGL *_flatShadowModelXShader;
-	OpenGL::ShaderGL *_flatShadowMaskShader;
+	OpenGL::Shader *_spriteShader;
+	OpenGL::Shader *_fadeShader;
+	OpenGL::Shader *_modelXShader;
+	OpenGL::Shader *_geometryShader;
+	OpenGL::Shader *_shadowVolumeShader;
+	OpenGL::Shader *_shadowMaskShader;
+	OpenGL::Shader *_lineShader;
+	OpenGL::Shader *_flatShadowModelXShader;
+	OpenGL::Shader *_flatShadowMaskShader;
 };
 
 } // namespace Wintermute
diff --git a/engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.cpp b/engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.cpp
index 10e500e03fa..99764674c29 100644
--- a/engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.cpp
+++ b/engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.cpp
@@ -29,7 +29,7 @@
 
 namespace Wintermute {
 
-Mesh3DSOpenGLShader::Mesh3DSOpenGLShader(OpenGL::ShaderGL *shader) : _shader(shader) {
+Mesh3DSOpenGLShader::Mesh3DSOpenGLShader(OpenGL::Shader *shader) : _shader(shader) {
 	glGenBuffers(1, &_vertexBuffer);
 	glGenBuffers(1, &_indexBuffer);
 }
diff --git a/engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.h b/engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.h
index 4ca34faed2e..5191256719c 100644
--- a/engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.h
+++ b/engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.h
@@ -32,7 +32,7 @@ namespace Wintermute {
 
 class Mesh3DSOpenGLShader : public Mesh3DS {
 public:
-	Mesh3DSOpenGLShader(OpenGL::ShaderGL *shader);
+	Mesh3DSOpenGLShader(OpenGL::Shader *shader);
 	~Mesh3DSOpenGLShader();
 	void fillVertexBuffer(uint32 color) override;
 	void render() override;
@@ -40,7 +40,7 @@ public:
 private:
 	GLuint _vertexBuffer;
 	GLuint _indexBuffer;
-	OpenGL::ShaderGL *_shader;
+	OpenGL::Shader *_shader;
 };
 
 } // namespace Wintermute
diff --git a/engines/wintermute/base/gfx/opengl/meshx_opengl_shader.cpp b/engines/wintermute/base/gfx/opengl/meshx_opengl_shader.cpp
index 74f37d7406f..9547c124dbc 100644
--- a/engines/wintermute/base/gfx/opengl/meshx_opengl_shader.cpp
+++ b/engines/wintermute/base/gfx/opengl/meshx_opengl_shader.cpp
@@ -37,7 +37,7 @@
 namespace Wintermute {
 
 //////////////////////////////////////////////////////////////////////////
-MeshXOpenGLShader::MeshXOpenGLShader(BaseGame *inGame, OpenGL::ShaderGL *shader, OpenGL::ShaderGL *flatShadowShader) :
+MeshXOpenGLShader::MeshXOpenGLShader(BaseGame *inGame, OpenGL::Shader *shader, OpenGL::Shader *flatShadowShader) :
 	MeshX(inGame), _shader(shader), _flatShadowShader(flatShadowShader) {
 	glGenBuffers(1, &_vertexBuffer);
 	glGenBuffers(1, &_indexBuffer);
diff --git a/engines/wintermute/base/gfx/opengl/meshx_opengl_shader.h b/engines/wintermute/base/gfx/opengl/meshx_opengl_shader.h
index ffa4589fc44..07a555e96a4 100644
--- a/engines/wintermute/base/gfx/opengl/meshx_opengl_shader.h
+++ b/engines/wintermute/base/gfx/opengl/meshx_opengl_shader.h
@@ -38,7 +38,7 @@ namespace Wintermute {
 
 class MeshXOpenGLShader : public MeshX {
 public:
-	MeshXOpenGLShader(BaseGame *inGame, OpenGL::ShaderGL *shader, OpenGL::ShaderGL *flatShadowShader);
+	MeshXOpenGLShader(BaseGame *inGame, OpenGL::Shader *shader, OpenGL::Shader *flatShadowShader);
 	~MeshXOpenGLShader() override;
 
 	bool loadFromX(const Common::String &filename, XFileLexer &lexer, Common::Array<MaterialReference> &materialReferences) override;
@@ -50,8 +50,8 @@ protected:
 	GLuint _vertexBuffer;
 	GLuint _indexBuffer;
 
-	OpenGL::ShaderGL *_shader;
-	OpenGL::ShaderGL *_flatShadowShader;
+	OpenGL::Shader *_shader;
+	OpenGL::Shader *_flatShadowShader;
 };
 
 } // namespace Wintermute
diff --git a/engines/wintermute/base/gfx/opengl/shadow_volume_opengl_shader.cpp b/engines/wintermute/base/gfx/opengl/shadow_volume_opengl_shader.cpp
index 373279bb72a..e35e87c35ad 100644
--- a/engines/wintermute/base/gfx/opengl/shadow_volume_opengl_shader.cpp
+++ b/engines/wintermute/base/gfx/opengl/shadow_volume_opengl_shader.cpp
@@ -43,7 +43,7 @@ struct ShadowVertexShader {
 };
 
 //////////////////////////////////////////////////////////////////////////
-ShadowVolumeOpenGLShader::ShadowVolumeOpenGLShader(BaseGame *inGame, OpenGL::ShaderGL *volumeShader, OpenGL::ShaderGL *maskShader)
+ShadowVolumeOpenGLShader::ShadowVolumeOpenGLShader(BaseGame *inGame, OpenGL::Shader *volumeShader, OpenGL::Shader *maskShader)
 	: ShadowVolume(inGame), _color(0x7f000000), _volumeShader(volumeShader), _maskShader(maskShader) {
 	ShadowVertexShader shadowMask[4];
 	Rect32 viewport = _gameRef->_renderer->getViewPort();
diff --git a/engines/wintermute/base/gfx/opengl/shadow_volume_opengl_shader.h b/engines/wintermute/base/gfx/opengl/shadow_volume_opengl_shader.h
index c56435fcbfd..c57cad442c5 100644
--- a/engines/wintermute/base/gfx/opengl/shadow_volume_opengl_shader.h
+++ b/engines/wintermute/base/gfx/opengl/shadow_volume_opengl_shader.h
@@ -40,7 +40,7 @@ namespace Wintermute {
 
 class ShadowVolumeOpenGLShader : public ShadowVolume {
 public:
-	ShadowVolumeOpenGLShader(BaseGame *inGame, OpenGL::ShaderGL *volumeShader, OpenGL::ShaderGL *maskShader);
+	ShadowVolumeOpenGLShader(BaseGame *inGame, OpenGL::Shader *volumeShader, OpenGL::Shader *maskShader);
 	virtual ~ShadowVolumeOpenGLShader();
 
 	bool renderToStencilBuffer() override;
@@ -52,8 +52,8 @@ private:
 	bool initMask() override;
 	GLuint _shadowVolumeVertexBuffer;
 	GLuint _shadowMaskVertexBuffer;
-	OpenGL::ShaderGL *_volumeShader;
-	OpenGL::ShaderGL *_maskShader;
+	OpenGL::Shader *_volumeShader;
+	OpenGL::Shader *_maskShader;
 };
 
 } // namespace Wintermute
diff --git a/graphics/opengl/shader.cpp b/graphics/opengl/shader.cpp
index 9cebcb115a2..bfff6766e6d 100644
--- a/graphics/opengl/shader.cpp
+++ b/graphics/opengl/shader.cpp
@@ -22,7 +22,7 @@
 #include "common/scummsys.h"
 #include "common/config-manager.h"
 
-#if defined(USE_OPENGL_SHADERS)
+#if defined(USE_OPENGL) && !USE_FORCED_GLES
 
 #include "graphics/opengl/shader.h"
 
@@ -132,8 +132,36 @@ static GLuint createDirectShader(const char *shaderSource, GLenum shaderType, co
 	return shader;
 }
 
-static GLuint createCompatShader(const char *shaderSource, GLenum shaderType, const Common::String &name) {
-	const GLchar *versionSource = OpenGLContext.type == kContextGLES2 ? "#version 100\n" : "#version 120\n";
+static GLuint createCompatShader(const char *shaderSource, GLenum shaderType, const Common::String &name, int compatGLSLVersion) {
+	GLchar versionSource[20];
+	if (OpenGLContext.type == kContextGLES2) {
+		switch(compatGLSLVersion) {
+			case 100:
+			case 110:
+			case 120:
+				// GLSL ES 1.00 is a subset of GLSL 1.20
+				compatGLSLVersion = 100;
+				break;
+			default:
+				error("Invalid GLSL version %d", compatGLSLVersion);
+		}
+	} else {
+		switch(compatGLSLVersion) {
+			case 100:
+			case 110:
+			case 120:
+				break;
+			default:
+				error("Invalid GLSL version %d", compatGLSLVersion);
+		}
+	}
+
+	if (OpenGLContext.glslVersion < compatGLSLVersion) {
+		error("Required GLSL version %d is not supported (%d maximum)", compatGLSLVersion, OpenGLContext.glslVersion);
+	}
+
+	sprintf(versionSource, "#version %d\n", compatGLSLVersion);
+
 	const GLchar *compatSource =
 			shaderType == GL_VERTEX_SHADER ? compatVertex : compatFragment;
 	const GLchar *shaderSources[] = {
@@ -160,11 +188,16 @@ static GLuint createCompatShader(const char *shaderSource, GLenum shaderType, co
 	return shader;
 }
 
-static GLuint loadShaderFromFile(const char *base, const char *extension, GLenum shaderType) {
+static GLuint loadShaderFromFile(const char *base, const char *extension, GLenum shaderType, int compatGLSLVersion) {
 	const Common::String filename = Common::String(base) + "." + extension;
 	const GLchar *shaderSource = readFile(filename);
 
-	GLuint shader = createCompatShader(shaderSource, shaderType, filename);
+	GLuint shader;
+	if (compatGLSLVersion) {
+		shader = createCompatShader(shaderSource, shaderType, filename, compatGLSLVersion);
+	} else {
+		shader = createDirectShader(shaderSource, shaderType, filename);
+	}
 
 	delete[] shaderSource;
 
@@ -183,9 +216,11 @@ struct SharedPtrProgramDeleter {
 	}
 };
 
-ShaderGL *ShaderGL::_previousShader = nullptr;
+Shader *Shader::_previousShader = nullptr;
+uint32 Shader::previousNumAttributes = 0;
 
-ShaderGL::ShaderGL(const Common::String &name, GLuint vertexShader, GLuint fragmentShader, const char **attributes)
+
+Shader::Shader(const Common::String &name, GLuint vertexShader, GLuint fragmentShader, const char *const *attributes)
 	: _name(name) {
 	assert(attributes);
 	GLuint shaderProgram = glCreateProgram();
@@ -218,22 +253,28 @@ ShaderGL::ShaderGL(const Common::String &name, GLuint vertexShader, GLuint fragm
 	_uniforms = Common::SharedPtr<UniformsMap>(new UniformsMap());
 }
 
-ShaderGL *ShaderGL::fromStrings(const Common::String &name, const char *vertex, const char *fragment, const char **attributes) {
-	GLuint vertexShader = createDirectShader(vertex, GL_VERTEX_SHADER, name + ".vertex");
-	GLuint fragmentShader = createDirectShader(fragment, GL_FRAGMENT_SHADER, name + ".fragment");
-	return new ShaderGL(name, vertexShader, fragmentShader, attributes);
+Shader *Shader::fromStrings(const Common::String &name, const char *vertex, const char *fragment, const char *const *attributes, int compatGLSLVersion) {
+	GLuint vertexShader, fragmentShader;
+
+	if (compatGLSLVersion) {
+		vertexShader = createCompatShader(vertex, GL_VERTEX_SHADER, name + ".vertex", compatGLSLVersion);
+		fragmentShader = createCompatShader(fragment, GL_FRAGMENT_SHADER, name + ".fragment", compatGLSLVersion);
+	} else {
+		vertexShader = createDirectShader(vertex, GL_VERTEX_SHADER, name + ".vertex");
+		fragmentShader = createDirectShader(fragment, GL_FRAGMENT_SHADER, name + ".fragment");
+	}
+	return new Shader(name, vertexShader, fragmentShader, attributes);
 }
 
-ShaderGL *ShaderGL::fromFiles(const char *vertex, const char *fragment, const char **attributes) {
-	GLuint vertexShader = loadShaderFromFile(vertex, "vertex", GL_VERTEX_SHADER);
-	GLuint fragmentShader = loadShaderFromFile(fragment, "fragment", GL_FRAGMENT_SHADER);
+Shader *Shader::fromFiles(const char *vertex, const char *fragment, const char *const *attributes, int compatGLSLVersion) {
+	GLuint vertexShader = loadShaderFromFile(vertex, "vertex", GL_VERTEX_SHADER, compatGLSLVersion);
+	GLuint fragmentShader = loadShaderFromFile(fragment, "fragment", GL_FRAGMENT_SHADER, compatGLSLVersion);
 
 	Common::String name = Common::String::format("%s/%s", vertex, fragment);
-	return new ShaderGL(name, vertexShader, fragmentShader, attributes);
+	return new Shader(name, vertexShader, fragmentShader, attributes);
 }
 
-void ShaderGL::use(bool forceReload) {
-	static uint32 previousNumAttributes = 0;
+void Shader::use(bool forceReload) {
 	if (this == _previousShader && !forceReload)
 		return;
 
@@ -272,7 +313,7 @@ void ShaderGL::use(bool forceReload) {
 	glBindBuffer(GL_ARRAY_BUFFER, 0);
 }
 
-GLuint ShaderGL::createBuffer(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) {
+GLuint Shader::createBuffer(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) {
 	GLuint vbo;
 	glGenBuffers(1, &vbo);
 	glBindBuffer(target, vbo);
@@ -281,16 +322,16 @@ GLuint ShaderGL::createBuffer(GLenum target, GLsizeiptr size, const GLvoid *data
 	return vbo;
 }
 
-void ShaderGL::freeBuffer(GLuint vbo) {
+void Shader::freeBuffer(GLuint vbo) {
 	glDeleteBuffers(1, &vbo);
 }
 
-VertexAttrib &ShaderGL::getAttributeAt(uint32 idx) {
+VertexAttrib &Shader::getAttributeAt(uint32 idx) {
 	assert(idx < _attributes.size());
 	return _attributes[idx];
 }
 
-VertexAttrib &ShaderGL::getAttribute(const char *attrib) {
+VertexAttrib &Shader::getAttribute(const char *attrib) {
 	for (uint32 i = 0; i < _attributes.size(); ++i)
 		if (_attributes[i]._name.equals(attrib))
 			return _attributes[i];
@@ -298,7 +339,7 @@ VertexAttrib &ShaderGL::getAttribute(const char *attrib) {
 	return _attributes[0];
 }
 
-void ShaderGL::enableVertexAttribute(const char *attrib, GLuint vbo, GLint size, GLenum type, GLboolean normalized, GLsizei stride, uint32 offset) {
+void Shader::enableVertexAttribute(const char *attrib, GLuint vbo, GLint size, GLenum type, GLboolean normalized, GLsizei stride, uint32 offset) {
 	VertexAttrib &va = getAttribute(attrib);
 	va._enabled = true;
 	va._vbo = vbo;
@@ -309,7 +350,7 @@ void ShaderGL::enableVertexAttribute(const char *attrib, GLuint vbo, GLint size,
 	va._offset = offset;
 }
 
-void ShaderGL::disableVertexAttribute(const char *attrib, int size, const float *data) {
+void Shader::disableVertexAttribute(const char *attrib, int size, const float *data) {
 	VertexAttrib &va = getAttribute(attrib);
 	va._enabled = false;
 	va._size = size;
@@ -317,12 +358,18 @@ void ShaderGL::disableVertexAttribute(const char *attrib, int size, const float
 		va._const[i] = data[i];
 }
 
-void ShaderGL::unbind() {
+void Shader::unbind() {
 	glUseProgram(0);
 	_previousShader = nullptr;
+
+	// Disable all vertex attributes as well
+	for (uint32 i = 0; i < previousNumAttributes; ++i) {
+		glDisableVertexAttribArray(i);
+	}
+	previousNumAttributes = 0;
 }
 
-ShaderGL::~ShaderGL() {
+Shader::~Shader() {
 	// If this is the currently active shader, unbind
 	if (_previousShader == this) {
 		unbind();
diff --git a/graphics/opengl/shader.h b/graphics/opengl/shader.h
index 4875f4d2c0e..730bb7cc8f3 100644
--- a/graphics/opengl/shader.h
+++ b/graphics/opengl/shader.h
@@ -52,58 +52,72 @@ struct VertexAttrib {
 	float _const[4];
 };
 
-class ShaderGL {
+class Shader {
 	typedef Common::HashMap<Common::String, GLint> UniformsMap;
 
 public:
-	~ShaderGL();
-	ShaderGL* clone() {
-		return new ShaderGL(*this);
+	~Shader();
+	Shader* clone() {
+		return new Shader(*this);
 	}
 
 	void use(bool forceReload = false);
 
 	void setUniform(const char *uniform, const Math::Matrix4 &m) {
 		GLint pos = getUniformLocation(uniform);
-		if (pos != -1)
+		if (pos != -1) {
+			use();
 			glUniformMatrix4fv(pos, 1, GL_FALSE, m.getData());
+		}
 	}
 
 	void setUniform(const char* uniform, const Math::Matrix3 &m) {
 		GLint pos = getUniformLocation(uniform);
-		if (pos != -1)
+		if (pos != -1) {
+			use();
 			glUniformMatrix3fv(pos, 1, GL_FALSE, m.getData());
+		}
 	}
 
 	void setUniform(const char *uniform, const Math::Vector4d &v) {
 		GLint pos = getUniformLocation(uniform);
-		if (pos != -1)
+		if (pos != -1) {
+			use();
 			glUniform4fv(pos, 1, v.getData());
+		}
 	}
 
 	void setUniform(const char *uniform, const Math::Vector3d &v) {
 		GLint pos = getUniformLocation(uniform);
-		if (pos != -1)
+		if (pos != -1) {
+			use();
 			glUniform3fv(pos, 1, v.getData());
+		}
 	}
 
 	void setUniform(const char *uniform, const Math::Vector2d &v) {
 		GLint pos = getUniformLocation(uniform);
-		if (pos != -1)
+		if (pos != -1) {
+			use();
 			glUniform2fv(pos, 1, v.getData());
+		}
 	}
 
 	void setUniform(const char *uniform, unsigned int x) {
 		GLint pos = getUniformLocation(uniform);
-		if (pos != -1)
+		if (pos != -1) {
+			use();
 			glUniform1i(pos, x);
+		}
 	}
 
 	// Different name to avoid overload ambiguity
 	void setUniform1f(const char *uniform, float f) {
 		GLint pos = getUniformLocation(uniform);
-		if (pos != -1)
+		if (pos != -1) {
+			use();
 			glUniform1f(pos, f);
+		}
 	}
 
 	GLint getUniformLocation(const char *uniform) const {
@@ -129,17 +143,45 @@ public:
 	static GLuint createBuffer(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage = GL_STATIC_DRAW);
 	static void freeBuffer(GLuint vbo);
 
-	static ShaderGL *fromFiles(const char *vertex, const char *fragment, const char **attributes);
-	static ShaderGL *fromFiles(const char *shared, const char **attributes) {
-		return fromFiles(shared, shared, attributes);
+	/**
+	 * Creates a shader object from strings
+	 *
+	 * For shader files (used by games), we used to require GLSL 1.20, this is the default for compatGLSLVersion.
+	 * The GLSL version is converted to GLSL ES version if needed.
+	 *
+	 * @param name The name of the shader for errors messages
+	 * @param vertex The vertex shader code
+	 * @param fragment The fragment shader code
+	 * @param attributes The vertex attributes names for indexing
+	 * @param compatGLSLVersion The GLSL version required: 0 for no preprocessing, 100 for GLSL 1.00 and so on
+	 *
+	 * @return the shader object created
+	 */
+	static Shader *fromFiles(const char *vertex, const char *fragment, const char *const *attributes, int compatGLSLVersion = 120);
+	static Shader *fromFiles(const char *shared, const char *const *attributes, int compatGLSLVersion = 120) {
+		return fromFiles(shared, shared, attributes, compatGLSLVersion);
 	}
 
-	static ShaderGL *fromStrings(const Common::String &name, const char *vertex, const char *fragment, const char **attributes);
+	/**
+	 * Creates a shader object from strings
+	 *
+	 * Shader strings are usually included in backends and don't need preprocessing, this is the default for compatGLSLVersion.
+	 * The GLSL version is converted to GLSL ES version if needed.
+	 *
+	 * @param name The name of the shader for errors messages
+	 * @param vertex The vertex shader code
+	 * @param fragment The fragment shader code
+	 * @param attributes The vertex attributes names for indexing
+	 * @param compatGLSLVersion The GLSL version required: 0 for no preprocessing, 100 for GLSL 1.00 and so on
+	 *
+	 * @return the shader object created
+	 */
+	static Shader *fromStrings(const Common::String &name, const char *vertex, const char *fragment, const char *const *attributes, int compatGLSLVersion = 0);
 
 	void unbind();
 
 private:
-	ShaderGL(const Common::String &name, GLuint vertexShader, GLuint fragmentShader, const char **attributes);
+	Shader(const Common::String &name, GLuint vertexShader, GLuint fragmentShader, const char *const *attributes);
 
 	// Since this class is cloned using the implicit copy constructor,
 	// a reference counting pointer is used to ensure deletion of the OpenGL
@@ -151,7 +193,8 @@ private:
 	Common::Array<VertexAttrib> _attributes;
 	Common::SharedPtr<UniformsMap> _uniforms;
 
-	static ShaderGL *_previousShader;
+	static Shader *_previousShader;
+	static uint32 previousNumAttributes;
 };
 
 } // End of namespace OpenGL




More information about the Scummvm-git-logs mailing list