From baca885cfce10acaa7a9892133aaa5b82c7183f7 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Wed, 2 Mar 2016 15:16:05 +0100 Subject: OPENGL: Let Shader store the uniform state. --- backends/graphics/opengl/opengl-func.h | 1 + backends/graphics/opengl/pipelines/clut8.cpp | 2 - backends/graphics/opengl/pipelines/shader.cpp | 10 +- backends/graphics/opengl/pipelines/shader.h | 1 + backends/graphics/opengl/shader.cpp | 90 ++++++++++++---- backends/graphics/opengl/shader.h | 141 +++++++++++++++++++++++--- 6 files changed, 210 insertions(+), 35 deletions(-) (limited to 'backends/graphics') 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(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. @@ -93,20 +166,60 @@ 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 value; + }; + + typedef Common::HashMap 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]; }; -- cgit v1.2.3