From: Steinar H. Gunderson Date: Tue, 21 Jan 2014 19:42:34 +0000 (+0100) Subject: Add support to the ResourcePool for 2D textures. X-Git-Tag: 1.0~75 X-Git-Url: https://git.sesse.net/?p=movit;a=commitdiff_plain;h=ecab6f3b08bc0a995dd96542758031f1ba2c6a27;hp=99d570aa1e5e72e6c2adcb8401b1451738e7dec2 Add support to the ResourcePool for 2D textures. Currently we don't have a freelist, but this will change shortly. --- diff --git a/effect.h b/effect.h index 4f740f3..a7d426c 100644 --- 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 diff --git a/effect_chain.cpp b/effect_chain.cpp index f324d1d..c3c23b6 100644 --- a/effect_chain.cpp +++ b/effect_chain.cpp @@ -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; diff --git a/effect_chain.h b/effect_chain.h index 6cd689d..a544e83 100644 --- a/effect_chain.h +++ b/effect_chain.h @@ -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 diff --git a/flat_input.cpp b/flat_input.cpp index b147725..5323dac 100644 --- a/flat_input.cpp +++ b/flat_input.cpp @@ -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. diff --git a/flat_input.h b/flat_input.h index 9fcaf53..33c685b 100644 --- a/flat_input.h +++ b/flat_input.h @@ -6,10 +6,13 @@ #include #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) diff --git a/resource_pool.cpp b/resource_pool.cpp index e65d0a9..bfd5306 100644 --- a/resource_pool.cpp +++ b/resource_pool.cpp @@ -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(); +} diff --git a/resource_pool.h b/resource_pool.h index a6e4327..0bb0a26 100644 --- a/resource_pool.h +++ b/resource_pool.h @@ -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); diff --git a/ycbcr_input.cpp b/ycbcr_input.cpp index e089e51..2a67ea7 100644 --- a/ycbcr_input.cpp +++ b/ycbcr_input.cpp @@ -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;