Add support to the ResourcePool for 2D textures.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Tue, 21 Jan 2014 19:42:34 +0000 (20:42 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Tue, 21 Jan 2014 19:42:34 +0000 (20:42 +0100)
Currently we don't have a freelist, but this will change shortly.

effect.h
effect_chain.cpp
effect_chain.h
flat_input.cpp
flat_input.h
resource_pool.cpp
resource_pool.h
ycbcr_input.cpp

index 4f740f3..a7d426c 100644 (file)
--- a/effect.h
+++ b/effect.h
@@ -196,6 +196,12 @@ public:
        // if you have several, they will be INPUT1(), INPUT2(), and so on.
        virtual unsigned num_inputs() const { return 1; }
 
+       // Inform the effect that it has been just added to the EffectChain.
+       // The primary use for this is to store the ResourcePool uesd by
+       // the chain; for modifications to it, rewrite_graph() below
+       // is probably a better fit.
+       virtual void inform_added(EffectChain *chain) {}
+
        // Let the effect rewrite the effect chain as it sees fit.
        // Most effects won't need to do this, but this is very useful
        // if you have an effect that consists of multiple sub-effects
index f324d1d..c3c23b6 100644 (file)
@@ -90,6 +90,7 @@ Node *EffectChain::add_node(Effect *effect)
 
        nodes.push_back(node);
        node_map[effect] = node;
+       effect->inform_added(this);
        return node;
 }
 
@@ -1424,7 +1425,7 @@ void EffectChain::finalize()
                        find_output_size(phases[i]);
 
                        Node *output_node = phases[i]->effects.back();
-                       glGenTextures(1, &output_node->output_texture);
+                       output_node->output_texture = resource_pool->create_2d_texture(GL_RGBA16F_ARB, phases[i]->output_width, phases[i]->output_height);
                        check_error();
                        glBindTexture(GL_TEXTURE_2D, output_node->output_texture);
                        check_error();
@@ -1432,8 +1433,6 @@ void EffectChain::finalize()
                        check_error();
                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
                        check_error();
-                       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, phases[i]->output_width, phases[i]->output_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-                       check_error();
 
                        output_node->output_texture_width = phases[i]->output_width;
                        output_node->output_texture_height = phases[i]->output_height;
index 6cd689d..a544e83 100644 (file)
@@ -174,6 +174,12 @@ public:
        void replace_sender(Node *new_sender, Node *receiver);
        void insert_node_between(Node *sender, Node *middle, Node *receiver);
 
+       // Get the current resource pool assigned to this EffectChain.
+       // Primarily to let effects allocate textures as needed.
+       // Any resources you get from the pool must be returned to the pool
+       // no later than in the Effect's destructor.
+       ResourcePool *get_resource_pool() { return resource_pool; }
+
 private:
        // Make sure the output rectangle is at least large enough to hold
        // the given input rectangle in both dimensions, and is of the
index b147725..5323dac 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "effect_util.h"
 #include "flat_input.h"
+#include "resource_pool.h"
 #include "util.h"
 
 FlatInput::FlatInput(ImageFormat image_format, MovitPixelFormat pixel_format, GLenum type, unsigned width, unsigned height)
@@ -29,8 +30,7 @@ FlatInput::FlatInput(ImageFormat image_format, MovitPixelFormat pixel_format, GL
 FlatInput::~FlatInput()
 {
        if (texture_num != 0) {
-               glDeleteTextures(1, &texture_num);
-               check_error();
+               resource_pool->release_2d_texture(texture_num);
        }
 }
 
@@ -64,16 +64,11 @@ void FlatInput::finalize()
        }
 
        // Create the texture itself.
-       glGenTextures(1, &texture_num);
-       check_error();
+       texture_num = resource_pool->create_2d_texture(internal_format, width, height);
        glBindTexture(GL_TEXTURE_2D, texture_num);
        check_error();
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, needs_mipmaps ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR);
        check_error();
-       glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, type, NULL);
-       check_error();
-       glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
-       check_error();
        glBindTexture(GL_TEXTURE_2D, 0);
        check_error();
 
@@ -87,6 +82,8 @@ void FlatInput::set_gl_state(GLuint glsl_program_num, const std::string& prefix,
        check_error();
        glBindTexture(GL_TEXTURE_2D, texture_num);
        check_error();
+       glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+       check_error();
 
        if (needs_update) {
                // Re-upload the texture.
index 9fcaf53..33c685b 100644 (file)
@@ -6,10 +6,13 @@
 #include <string>
 
 #include "effect.h"
+#include "effect_chain.h"
 #include "image_format.h"
 #include "init.h"
 #include "input.h"
 
+class ResourcePool;
+
 // A FlatInput is the normal, “classic” case of an input, where everything
 // comes from a single 2D array with chunky pixels.
 class FlatInput : public Input {
@@ -93,6 +96,11 @@ public:
                this->pitch = pitch;
        }
 
+       virtual void inform_added(EffectChain *chain)
+       {
+               resource_pool = chain->get_resource_pool();
+       }
+
 private:
        ImageFormat image_format;
        MovitPixelFormat pixel_format;
@@ -102,6 +110,7 @@ private:
        int output_linear_gamma, needs_mipmaps;
        unsigned width, height, pitch;
        const void *pixel_data;
+       ResourcePool *resource_pool;
 };
 
 #endif // !defined(_MOVIT_FLAT_INPUT_H)
index e65d0a9..bfd5306 100644 (file)
@@ -127,3 +127,43 @@ void ResourcePool::release_glsl_program(GLuint glsl_program_num)
 
        pthread_mutex_unlock(&lock);
 }
+
+GLuint ResourcePool::create_2d_texture(GLint internal_format, GLsizei width, GLsizei height)
+{
+       // Find any reasonable format given the internal format; OpenGL validates it
+       // even though we give NULL as pointer.
+       GLenum format;
+       switch (internal_format) {
+       case GL_RGBA32F_ARB:
+       case GL_RGBA16F_ARB:
+       case GL_RGBA8:
+       case GL_SRGB8_ALPHA8:
+               format = GL_RGBA;
+               break;
+       case GL_RG32F:
+       case GL_RG16F:
+               format = GL_RG;
+               break;
+       default:
+               // TODO: Add more here as needed.
+               assert(false);
+       }
+
+       GLuint texture_num;
+       glGenTextures(1, &texture_num);
+       check_error();
+       glBindTexture(GL_TEXTURE_2D, texture_num);
+       check_error();
+       glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, GL_UNSIGNED_BYTE, NULL);
+       check_error();
+       glBindTexture(GL_TEXTURE_2D, 0);
+       check_error();
+
+       return texture_num;
+}
+
+void ResourcePool::release_2d_texture(GLuint texture_num)
+{
+       glDeleteTextures(1, &texture_num);
+       check_error();
+}
index a6e4327..0bb0a26 100644 (file)
@@ -41,6 +41,15 @@ public:
        GLuint compile_glsl_program(const std::string& vertex_shader, const std::string& fragment_shader);
        void release_glsl_program(GLuint glsl_program_num);
 
+       // Allocate a 2D texture of the given internal format and dimensions,
+       // or fetch a previous used if possible. Unbinds GL_TEXTURE_2D afterwards.
+       // Keeps ownership of the texture; you must call release_2d_texture() instead
+       // of deleting it when you no longer want it.
+       //
+       // Note: Currently we do not actually have a freelist, but this will change soon.
+       GLuint create_2d_texture(GLint internal_format, GLsizei width, GLsizei height);
+       void release_2d_texture(GLuint texture_num);
+
 private:
        // Delete the given program and both its shaders.
        void delete_program(GLuint program_num);
index e089e51..2a67ea7 100644 (file)
@@ -87,25 +87,22 @@ YCbCrInput::YCbCrInput(const ImageFormat &image_format,
 
 YCbCrInput::~YCbCrInput()
 {
-       if (texture_num[0] != 0) {
-               glDeleteTextures(3, texture_num);
-               check_error();
+       for (unsigned channel = 0; channel < 3; ++channel) {
+               if (texture_num[channel] != 0) {
+                       resource_pool->release_2d_texture(texture_num[channel]);
+               }
        }
 }
 
 void YCbCrInput::finalize()
 {
        // Create the textures themselves.
-       glGenTextures(3, texture_num);
-       check_error();
-
        for (unsigned channel = 0; channel < 3; ++channel) {
+               texture_num[channel] = resource_pool->create_2d_texture(GL_LUMINANCE8, widths[channel], heights[channel]);
                glBindTexture(GL_TEXTURE_2D, texture_num[channel]);
                check_error();
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                check_error();
-               glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE8, widths[channel], heights[channel], 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
-               check_error();
        }
 
        needs_update = true;