From 3b04eeeec8fa58e2f78509c943eac53fe27531c2 Mon Sep 17 00:00:00 2001 From: vrld Date: Sun, 3 Nov 2013 18:27:36 +0100 Subject: [PATCH] Fix #756: Sending an Image to a shader does not retain it Each shader contains a map of uniform name -> bound retainable Object. After setting the uniform, sendImage() and sendCanvas() release() the Object with the requested name (if present) and record the new Image/Canvas. Related bugfix: Shader::attach() calls retain()/release() on the shader. --- src/modules/graphics/opengl/Shader.cpp | 29 +++++++++++++++++++++++--- src/modules/graphics/opengl/Shader.h | 8 +++++-- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index cbf18ec4b..ab8e7c32a 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -91,6 +91,12 @@ Shader::~Shader() if (current == this) detach(); + for (auto it = boundRetainables.begin(); it != boundRetainables.end(); ++it) + { + it->second->release(); + boundRetainables.erase(it); + } + unloadVolatile(); } @@ -331,8 +337,13 @@ void Shader::attach(bool temporary) { if (current != this) { + if (current != NULL) + current->release(); + glUseProgram(program); current = this; + + current->retain(); } if (!temporary) @@ -558,14 +569,26 @@ void Shader::sendTexture(const std::string &name, GLuint texture) activeTextureUnits[textureunit-1] = texture; } -void Shader::sendImage(const std::string &name, const Image &image) +void Shader::retainTexture(const std::string &name, Object *texture) { - sendTexture(name, image.getTextureName()); + auto it = boundRetainables.find(name); + if (it != boundRetainables.end()) + it->second->release(); + + texture->retain(); + boundRetainables[name] = texture; } -void Shader::sendCanvas(const std::string &name, const Canvas &canvas) +void Shader::sendImage(const std::string &name, Image &image) +{ + sendTexture(name, image.getTextureName()); + retainTexture(name, &image); +} + +void Shader::sendCanvas(const std::string &name, Canvas &canvas) { sendTexture(name, canvas.getTextureName()); + retainTexture(name, &canvas); } int Shader::getTextureUnit(const std::string &name) diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index 0e9a3994d..3c93d5197 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -124,14 +124,14 @@ public: * * @param name The name of the uniform variable in the source code. **/ - void sendImage(const std::string &name, const Image &image); + void sendImage(const std::string &name, Image &image); /** * Send a canvas to this Shader as a uniform. * * @param name The name of the uniform variable in the source code. **/ - void sendCanvas(const std::string &name, const Canvas &canvas); + void sendCanvas(const std::string &name, Canvas &canvas); static std::string getGLSLVersion(); static bool isSupported(); @@ -173,6 +173,7 @@ private: int getTextureUnit(const std::string &name); void sendTexture(const std::string &name, GLuint texture); + void retainTexture(const std::string &name, Object *texture); // Get any warnings or errors generated only by the shader program object. std::string getProgramWarnings() const; @@ -193,6 +194,9 @@ private: std::map textureUnitPool; // textureUnitPool[name] = textureunit std::vector activeTextureUnits; // activeTextureUnits[textureunit-1] = textureid + // Uniform name to retainable objects + std::map boundRetainables; + // Max GPU texture units available for sent images static GLint maxTextureUnits;