Currently we don't have a freelist, but this will change shortly.
// 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
nodes.push_back(node);
node_map[effect] = node;
+ effect->inform_added(this);
return node;
}
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();
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;
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
#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)
FlatInput::~FlatInput()
{
if (texture_num != 0) {
- glDeleteTextures(1, &texture_num);
- check_error();
+ resource_pool->release_2d_texture(texture_num);
}
}
}
// 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();
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.
#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 {
this->pitch = pitch;
}
+ virtual void inform_added(EffectChain *chain)
+ {
+ resource_pool = chain->get_resource_pool();
+ }
+
private:
ImageFormat image_format;
MovitPixelFormat pixel_format;
int output_linear_gamma, needs_mipmaps;
unsigned width, height, pitch;
const void *pixel_data;
+ ResourcePool *resource_pool;
};
#endif // !defined(_MOVIT_FLAT_INPUT_H)
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();
+}
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);
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;