aboutsummaryrefslogtreecommitdiff
path: root/backends/graphics
diff options
context:
space:
mode:
authorJohannes Schickel2016-03-02 15:16:05 +0100
committerJohannes Schickel2016-03-16 20:29:31 +0100
commitbaca885cfce10acaa7a9892133aaa5b82c7183f7 (patch)
tree8f1c0d94fac540185c385dac292615f7d82cfe51 /backends/graphics
parent6dacc96d1f6ed804197382c59765c8cec5146c62 (diff)
downloadscummvm-rg350-baca885cfce10acaa7a9892133aaa5b82c7183f7.tar.gz
scummvm-rg350-baca885cfce10acaa7a9892133aaa5b82c7183f7.tar.bz2
scummvm-rg350-baca885cfce10acaa7a9892133aaa5b82c7183f7.zip
OPENGL: Let Shader store the uniform state.
Diffstat (limited to 'backends/graphics')
-rw-r--r--backends/graphics/opengl/opengl-func.h1
-rw-r--r--backends/graphics/opengl/pipelines/clut8.cpp2
-rw-r--r--backends/graphics/opengl/pipelines/shader.cpp10
-rw-r--r--backends/graphics/opengl/pipelines/shader.h1
-rw-r--r--backends/graphics/opengl/shader.cpp90
-rw-r--r--backends/graphics/opengl/shader.h141
6 files changed, 210 insertions, 35 deletions
diff --git a/backends/graphics/opengl/opengl-func.h b/backends/graphics/opengl/opengl-func.h
index 554ac3c6ff..ad7c572ca9 100644
--- a/backends/graphics/opengl/opengl-func.h
+++ b/backends/graphics/opengl/opengl-func.h
@@ -108,6 +108,7 @@ GL_FUNC_DEF(GLenum, glGetError, ());
#if !USE_FORCED_GLES
GL_FUNC_2_DEF(void, glEnableVertexAttribArray, glEnableVertexAttribArrayARB, (GLuint index));
GL_FUNC_2_DEF(void, glUniform1i, glUniform1iARB, (GLint location, GLint v0));
+GL_FUNC_2_DEF(void, glUniform1f, glUniform1fARB, (GLint location, GLfloat v0));
GL_FUNC_2_DEF(void, glUniformMatrix4fv, glUniformMatrix4fvARB, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value));
GL_FUNC_2_DEF(void, glVertexAttrib4f, glVertexAttrib4fARB, (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w));
GL_FUNC_2_DEF(void, glVertexAttribPointer, glVertexAttribPointerARB, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer));
diff --git a/backends/graphics/opengl/pipelines/clut8.cpp b/backends/graphics/opengl/pipelines/clut8.cpp
index 9f2aa94b90..fca40074f0 100644
--- a/backends/graphics/opengl/pipelines/clut8.cpp
+++ b/backends/graphics/opengl/pipelines/clut8.cpp
@@ -32,8 +32,6 @@ CLUT8LookUpPipeline::CLUT8LookUpPipeline()
}
void CLUT8LookUpPipeline::drawTexture(const GLTexture &texture, const GLfloat *coordinates) {
- _activeShader->setUniformI(_activeShader->getUniformLocation("palette"), 1);
-
// Set the palette texture.
GL_CALL(glActiveTexture(GL_TEXTURE1));
if (_paletteTexture) {
diff --git a/backends/graphics/opengl/pipelines/shader.cpp b/backends/graphics/opengl/pipelines/shader.cpp
index 69af911fc6..46e81423c5 100644
--- a/backends/graphics/opengl/pipelines/shader.cpp
+++ b/backends/graphics/opengl/pipelines/shader.cpp
@@ -38,6 +38,12 @@ void ShaderPipeline::activateInternal() {
if (g_context.multitextureSupported) {
GL_CALL(glActiveTexture(GL_TEXTURE0));
}
+
+ _activeShader->activate();
+}
+
+void ShaderPipeline::deactivateInternal() {
+ _activeShader->deactivate();
}
void ShaderPipeline::setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
@@ -53,9 +59,7 @@ void ShaderPipeline::drawTexture(const GLTexture &texture, const GLfloat *coordi
}
void ShaderPipeline::setProjectionMatrix(const GLfloat *projectionMatrix) {
- if (isActive() && _activeShader) {
- _activeShader->activate(projectionMatrix);
- }
+ _activeShader->setUniform("projection", new ShaderUniformMatrix44(projectionMatrix));
}
#endif // !USE_FORCED_GLES
diff --git a/backends/graphics/opengl/pipelines/shader.h b/backends/graphics/opengl/pipelines/shader.h
index 52046f8dd5..8e82bd7a31 100644
--- a/backends/graphics/opengl/pipelines/shader.h
+++ b/backends/graphics/opengl/pipelines/shader.h
@@ -42,6 +42,7 @@ public:
protected:
virtual void activateInternal();
+ virtual void deactivateInternal();
Shader *const _activeShader;
};
diff --git a/backends/graphics/opengl/shader.cpp b/backends/graphics/opengl/shader.cpp
index 2f2d5d82eb..59749ba1f0 100644
--- a/backends/graphics/opengl/shader.cpp
+++ b/backends/graphics/opengl/shader.cpp
@@ -35,6 +35,8 @@ namespace OpenGL {
namespace {
+#pragma mark - Builtin Shader Sources -
+
const char *const g_defaultVertexShader =
"attribute vec4 position;\n"
"attribute vec2 texCoordIn;\n"
@@ -92,8 +94,25 @@ const char *const g_precisionDefines =
} // End of anonymous namespace
+#pragma mark - Uniform Values -
+
+void ShaderUniformInteger::set(GLint location) const {
+ GL_CALL(glUniform1i(location, _value));
+}
+
+void ShaderUniformFloat::set(GLint location) const {
+ GL_CALL(glUniform1f(location, _value));
+}
+
+void ShaderUniformMatrix44::set(GLint location) const {
+ GL_CALL(glUniformMatrix4fv(location, 1, GL_FALSE, _matrix));
+}
+
+#pragma mark - Shader Implementation -
+
Shader::Shader(const Common::String &vertex, const Common::String &fragment)
- : _vertex(vertex), _fragment(fragment), _program(0), _projectionLocation(-1), _textureLocation(-1) {
+ : _vertex(vertex), _fragment(fragment), _isActive(false), _program(0), _uniforms() {
+ recreate();
}
Shader::~Shader() {
@@ -167,15 +186,26 @@ bool Shader::recreate() {
return false;
}
- GL_ASSIGN(_projectionLocation, glGetUniformLocation(_program, "projection"));
- if (_projectionLocation == -1) {
+ // Set program object in case shader is active during recreation.
+ if (_isActive) {
+ GL_CALL(glUseProgram(_program));
+ }
+
+ for (UniformMap::iterator i = _uniforms.begin(), end = _uniforms.end(); i != end; ++i) {
+ i->_value.location = getUniformLocation(i->_key.c_str());
+ i->_value.altered = true;
+ if (_isActive) {
+ i->_value.set();
+ }
+ }
+
+ if (getUniformLocation("projection") == -1) {
warning("Shader misses \"projection\" uniform.");
destroy();
return false;
}
- GL_ASSIGN(_textureLocation, glGetUniformLocation(_program, "texture"));
- if (_textureLocation == -1) {
+ if (!setUniform1I("texture", 0)) {
warning("Shader misses \"texture\" uniform.");
destroy();
return false;
@@ -184,15 +214,20 @@ bool Shader::recreate() {
return true;
}
-void Shader::activate(const GLfloat *projectionMatrix) {
+void Shader::activate() {
// Activate program.
GL_CALL(glUseProgram(_program));
- // Set projection matrix.
- GL_CALL(glUniformMatrix4fv(_projectionLocation, 1, GL_FALSE, projectionMatrix));
+ // Reset changed uniform values.
+ for (UniformMap::iterator i = _uniforms.begin(), end = _uniforms.end(); i != end; ++i) {
+ i->_value.set();
+ }
+
+ _isActive = true;
+}
- // We always use texture unit 0.
- GL_CALL(glUniform1i(_textureLocation, 0));
+void Shader::deactivate() {
+ _isActive = false;
}
GLint Shader::getUniformLocation(const char *name) const {
@@ -201,8 +236,23 @@ GLint Shader::getUniformLocation(const char *name) const {
return result;
}
-void Shader::setUniformI(GLint location, GLint value) {
- GL_CALL(glUniform1i(location, value));
+bool Shader::setUniform(const Common::String &name, ShaderUniformValue *value) {
+ UniformMap::iterator uniformIter = _uniforms.find(name);
+ Uniform *uniform;
+
+ if (uniformIter == _uniforms.end()) {
+ uniform = &_uniforms[name];
+ uniform->location = getUniformLocation(name.c_str());
+ } else {
+ uniform = &uniformIter->_value;
+ }
+
+ uniform->value = Common::SharedPtr<ShaderUniformValue>(value);
+ uniform->altered = true;
+ if (_isActive) {
+ uniform->set();
+ }
+ return uniform->location != -1;
}
GLshader Shader::compileShader(const char *source, GLenum shaderType) {
@@ -238,9 +288,7 @@ GLshader Shader::compileShader(const char *source, GLenum shaderType) {
return handle;
}
-ShaderManager::ShaderManager() {
- _builtIn[kDefault] = new Shader(g_defaultVertexShader, g_defaultFragmentShader);
- _builtIn[kCLUT8LookUp] = new Shader(g_defaultVertexShader, g_lookUpFragmentShader);
+ShaderManager::ShaderManager() : _initializeShaders(true) {
}
ShaderManager::~ShaderManager() {
@@ -256,8 +304,16 @@ void ShaderManager::notifyDestroy() {
}
void ShaderManager::notifyCreate() {
- for (int i = 0; i < ARRAYSIZE(_builtIn); ++i) {
- _builtIn[i]->recreate();
+ if (_initializeShaders) {
+ _initializeShaders = false;
+
+ _builtIn[kDefault] = new Shader(g_defaultVertexShader, g_defaultFragmentShader);
+ _builtIn[kCLUT8LookUp] = new Shader(g_defaultVertexShader, g_lookUpFragmentShader);
+ _builtIn[kCLUT8LookUp]->setUniform1I("palette", 1);
+ } else {
+ for (int i = 0; i < ARRAYSIZE(_builtIn); ++i) {
+ _builtIn[i]->recreate();
+ }
}
}
diff --git a/backends/graphics/opengl/shader.h b/backends/graphics/opengl/shader.h
index e5dbcacfad..1aee8ed681 100644
--- a/backends/graphics/opengl/shader.h
+++ b/backends/graphics/opengl/shader.h
@@ -27,8 +27,9 @@
#if !USE_FORCED_GLES
-#include "common/str.h"
#include "common/singleton.h"
+#include "common/hash-str.h"
+#include "common/ptr.h"
namespace OpenGL {
@@ -38,6 +39,62 @@ enum {
kColorAttribLocation = 2
};
+/**
+ * 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) {}
+
+ virtual 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) {}
+
+ virtual 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));
+ }
+
+ virtual void set(GLint location) const override;
+
+private:
+ GLfloat _matrix[4*4];
+};
+
class Shader {
public:
Shader(const Common::String &vertex, const Common::String &fragment);
@@ -47,7 +104,8 @@ public:
* Destroy the shader program.
*
* This keeps the vertex and fragment shader sources around and thus
- * allows for recreating the shader on context recreation.
+ * allows for recreating the shader on context recreation. It also keeps
+ * the uniform state around.
*/
void destroy();
@@ -60,10 +118,13 @@ public:
/**
* Make shader active.
- *
- * @param projectionMatrix Projection matrix to use.
*/
- void activate(const GLfloat *projectionMatrix);
+ void activate();
+
+ /**
+ * Make shader inactive.
+ */
+ void deactivate();
/**
* Return location for uniform with given name.
@@ -76,12 +137,24 @@ public:
/**
* Bind value to uniform.
*
- * Note: this only works when the shader is actived by activate.
+ * @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 location Location of the uniform.
- * @param value The value to be set.
+ * @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.
*/
- void setUniformI(GLint location, GLint value);
+ bool setUniform1I(const Common::String &name, GLint value) {
+ return setUniform(name, new ShaderUniformInteger(value));
+ }
protected:
/**
* Vertex shader sources.
@@ -94,19 +167,59 @@ protected:
const Common::String _fragment;
/**
+ * Whether the shader is active or not.
+ */
+ bool _isActive;
+
+ /**
* Shader program handle.
*/
GLprogram _program;
/**
- * Location of the matrix uniform in the shader 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.
*/
- GLint _projectionLocation;
+ 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;
/**
- * Location of the texture sampler location in the shader program.
+ * Map from uniform name to associated uniform description.
*/
- GLint _textureLocation;
+ UniformMap _uniforms;
/**
* Compile a vertex or fragment shader.
@@ -152,6 +265,8 @@ private:
ShaderManager();
~ShaderManager();
+ bool _initializeShaders;
+
Shader *_builtIn[kMaxUsages];
};