]> git.sesse.net Git - movit/blobdiff - effect_chain.cpp
Redo FBO association yet again, this time per-texture.
[movit] / effect_chain.cpp
index c5e10e84a39c2315773315c8ae871e05342e012c..ca6a7775eb56de0aab5b2e43dbe53a8003c34aaf 100644 (file)
@@ -53,6 +53,15 @@ EffectChain::~EffectChain()
                delete nodes[i];
        }
        for (unsigned i = 0; i < phases.size(); ++i) {
+               glBindVertexArray(phases[i]->vao);
+               check_error();
+
+               cleanup_vertex_attribute(phases[i]->glsl_program_num, "position", phases[i]->position_vbo);
+               cleanup_vertex_attribute(phases[i]->glsl_program_num, "texcoord", phases[i]->texcoord_vbo);
+
+               glBindVertexArray(0);
+               check_error();
+
                resource_pool->release_glsl_program(phases[i]->glsl_program_num);
                delete phases[i];
        }
@@ -282,6 +291,27 @@ void EffectChain::compile_glsl_program(Phase *phase)
        frag_shader.append(read_file("footer.frag"));
 
        phase->glsl_program_num = resource_pool->compile_glsl_program(read_file("vs.vert"), frag_shader);
+
+       // Prepare the geometry for the fullscreen quad used in this phase.
+       // (We have separate VAOs per shader, since the bindings can in theory
+       // be different.)
+       float vertices[] = {
+               0.0f, 1.0f,
+               0.0f, 0.0f,
+               1.0f, 1.0f,
+               1.0f, 0.0f
+       };
+
+       glGenVertexArrays(1, &phase->vao);
+       check_error();
+       glBindVertexArray(phase->vao);
+       check_error();
+
+       phase->position_vbo = fill_vertex_attribute(phase->glsl_program_num, "position", 2, GL_FLOAT, sizeof(vertices), vertices);
+       phase->texcoord_vbo = fill_vertex_attribute(phase->glsl_program_num, "texcoord", 2, GL_FLOAT, sizeof(vertices), vertices);  // Same as vertices.
+
+       glBindVertexArray(0);
+       check_error();
 }
 
 // Construct GLSL programs, starting at the given effect and following
@@ -1405,6 +1435,7 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height
        // Save original viewport.
        GLuint x = 0, y = 0;
        GLuint fbo = 0;
+       void *context = get_gl_context_identifier();
 
        if (width == 0 && height == 0) {
                GLint viewport[4];
@@ -1423,42 +1454,37 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height
        glDepthMask(GL_FALSE);
        check_error();
 
-       if (phases.size() > 1) {
-               glGenFramebuffers(1, &fbo);
-               check_error();
-               glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-               check_error();
-       }
-
        set<Phase *> generated_mipmaps;
 
        // We choose the simplest option of having one texture per output,
        // since otherwise this turns into an (albeit simple) register allocation problem.
        map<Phase *, GLuint> output_textures;
 
-       for (unsigned phase = 0; phase < phases.size(); ++phase) {
+       for (unsigned phase_num = 0; phase_num < phases.size(); ++phase_num) {
+               Phase *phase = phases[phase_num];
+
                // Find a texture for this phase.
-               inform_input_sizes(phases[phase]);
-               if (phase != phases.size() - 1) {
-                       find_output_size(phases[phase]);
+               inform_input_sizes(phase);
+               if (phase_num != phases.size() - 1) {
+                       find_output_size(phase);
 
-                       GLuint tex_num = resource_pool->create_2d_texture(GL_RGBA16F_ARB, phases[phase]->output_width, phases[phase]->output_height);
-                       output_textures.insert(make_pair(phases[phase], tex_num));
+                       GLuint tex_num = resource_pool->create_2d_texture(GL_RGBA16F, phase->output_width, phase->output_height);
+                       output_textures.insert(make_pair(phase, tex_num));
                }
 
-               const GLuint glsl_program_num = phases[phase]->glsl_program_num;
+               const GLuint glsl_program_num = phase->glsl_program_num;
                check_error();
                glUseProgram(glsl_program_num);
                check_error();
 
                // Set up RTT inputs for this phase.
-               for (unsigned sampler = 0; sampler < phases[phase]->inputs.size(); ++sampler) {
+               for (unsigned sampler = 0; sampler < phase->inputs.size(); ++sampler) {
                        glActiveTexture(GL_TEXTURE0 + sampler);
-                       Phase *input = phases[phase]->inputs[sampler];
+                       Phase *input = phase->inputs[sampler];
                        input->output_node->bound_sampler_num = sampler;
                        glBindTexture(GL_TEXTURE_2D, output_textures[input]);
                        check_error();
-                       if (phases[phase]->input_needs_mipmaps) {
+                       if (phase->input_needs_mipmaps) {
                                if (generated_mipmaps.count(input) == 0) {
                                        glGenerateMipmap(GL_TEXTURE_2D);
                                        check_error();
@@ -1475,13 +1501,13 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height
                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
                        check_error();
 
-                       string texture_name = string("tex_") + phases[phase]->effect_ids[input->output_node];
+                       string texture_name = string("tex_") + phase->effect_ids[input->output_node];
                        glUniform1i(glGetUniformLocation(glsl_program_num, texture_name.c_str()), sampler);
                        check_error();
                }
 
                // And now the output.
-               if (phase == phases.size() - 1) {
+               if (phase_num == phases.size() - 1) {
                        // Last phase goes to the output the user specified.
                        glBindFramebuffer(GL_FRAMEBUFFER, dest_fbo);
                        check_error();
@@ -1493,24 +1519,17 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height
                                CHECK(dither_effect->set_int("output_height", height));
                        }
                } else {
-                       glFramebufferTexture2D(
-                               GL_FRAMEBUFFER,
-                               GL_COLOR_ATTACHMENT0,
-                               GL_TEXTURE_2D,
-                               output_textures[phases[phase]],
-                               0);
-                       check_error();
-                       GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
-                       assert(status == GL_FRAMEBUFFER_COMPLETE);
-                       glViewport(0, 0, phases[phase]->output_width, phases[phase]->output_height);
+                       fbo = resource_pool->create_fbo(context, output_textures[phase]);
+                       glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+                       glViewport(0, 0, phase->output_width, phase->output_height);
                }
 
                // Give the required parameters to all the effects.
-               unsigned sampler_num = phases[phase]->inputs.size();
-               for (unsigned i = 0; i < phases[phase]->effects.size(); ++i) {
-                       Node *node = phases[phase]->effects[i];
+               unsigned sampler_num = phase->inputs.size();
+               for (unsigned i = 0; i < phase->effects.size(); ++i) {
+                       Node *node = phase->effects[i];
                        unsigned old_sampler_num = sampler_num;
-                       node->effect->set_gl_state(glsl_program_num, phases[phase]->effect_ids[node], &sampler_num);
+                       node->effect->set_gl_state(glsl_program_num, phase->effect_ids[node], &sampler_num);
                        check_error();
 
                        if (node->effect->is_single_texture()) {
@@ -1521,39 +1540,18 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height
                        }
                }
 
-               // Now draw!
-               float vertices[] = {
-                       0.0f, 1.0f,
-                       0.0f, 0.0f,
-                       1.0f, 1.0f,
-                       1.0f, 0.0f
-               };
-
-               GLuint vao;
-               glGenVertexArrays(1, &vao);
+               glBindVertexArray(phase->vao);
                check_error();
-               glBindVertexArray(vao);
-               check_error();
-
-               GLuint position_vbo = fill_vertex_attribute(glsl_program_num, "position", 2, GL_FLOAT, sizeof(vertices), vertices);
-               GLuint texcoord_vbo = fill_vertex_attribute(glsl_program_num, "texcoord", 2, GL_FLOAT, sizeof(vertices), vertices);  // Same as vertices.
-
                glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
                check_error();
 
-               cleanup_vertex_attribute(glsl_program_num, "position", position_vbo);
-               cleanup_vertex_attribute(glsl_program_num, "texcoord", texcoord_vbo);
-
-               glUseProgram(0);
-               check_error();
-
-               for (unsigned i = 0; i < phases[phase]->effects.size(); ++i) {
-                       Node *node = phases[phase]->effects[i];
+               for (unsigned i = 0; i < phase->effects.size(); ++i) {
+                       Node *node = phase->effects[i];
                        node->effect->clear_gl_state();
                }
-
-               glDeleteVertexArrays(1, &vao);
-               check_error();
+               if (phase_num != phases.size() - 1) {
+                       resource_pool->release_fbo(fbo);
+               }
        }
 
        for (map<Phase *, GLuint>::const_iterator texture_it = output_textures.begin();
@@ -1564,11 +1562,10 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height
 
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        check_error();
-
-       if (fbo != 0) {
-               glDeleteFramebuffers(1, &fbo);
-               check_error();
-       }
+       glBindVertexArray(0);
+       check_error();
+       glUseProgram(0);
+       check_error();
 }
 
 }  // namespace movit