]> git.sesse.net Git - movit/blobdiff - effect_chain.cpp
Merge branch 'master' into epoxy
[movit] / effect_chain.cpp
index d80c4f82a28b33c39c983b38f02894ad514979e1..ef4402491ab2c3c23b613336235f7f884a5874b6 100644 (file)
@@ -1,6 +1,6 @@
 #define GL_GLEXT_PROTOTYPES 1
 
-#include <GL/glew.h>
+#include <epoxy/gl.h>
 #include <assert.h>
 #include <locale.h>
 #include <math.h>
@@ -11,6 +11,7 @@
 #include <algorithm>
 #include <set>
 #include <stack>
+#include <utility>
 #include <vector>
 
 #include "alpha_division_effect.h"
@@ -28,6 +29,8 @@
 
 using namespace std;
 
+namespace movit {
+
 EffectChain::EffectChain(float aspect_nom, float aspect_denom, ResourcePool *resource_pool)
        : aspect_nom(aspect_nom),
          aspect_denom(aspect_denom),
@@ -146,6 +149,15 @@ void EffectChain::insert_node_between(Node *sender, Node *middle, Node *receiver
        assert(middle->incoming_links.size() == middle->effect->num_inputs());
 }
 
+GLenum EffectChain::get_input_sampler(Node *node, unsigned input_num) const
+{
+       assert(node->effect->needs_texture_bounce());
+       assert(input_num < node->incoming_links.size());
+       assert(node->incoming_links[input_num]->bound_sampler_num >= 0);
+       assert(node->incoming_links[input_num]->bound_sampler_num < 8);
+       return GL_TEXTURE0 + node->incoming_links[input_num]->bound_sampler_num;
+}
+
 void EffectChain::find_all_nonlinear_inputs(Node *node, vector<Node *> *nonlinear_inputs)
 {
        if (node->output_gamma_curve == GAMMA_LINEAR &&
@@ -356,13 +368,13 @@ void EffectChain::construct_glsl_programs(Node *output)
                        for (unsigned i = 0; i < deps.size(); ++i) {
                                bool start_new_phase = false;
 
-                               // FIXME: If we sample directly from a texture, we won't need this.
-                               if (node->effect->needs_texture_bounce()) {
+                               if (node->effect->needs_texture_bounce() &&
+                                   !deps[i]->effect->is_single_texture()) {
                                        start_new_phase = true;
                                }
 
                                if (deps[i]->outgoing_links.size() > 1) {
-                                       if (deps[i]->effect->num_inputs() > 0) {
+                                       if (!deps[i]->effect->is_single_texture()) {
                                                // More than one effect uses this as the input,
                                                // and it is not a texture itself.
                                                // The easiest thing to do (and probably also the safest
@@ -370,6 +382,8 @@ void EffectChain::construct_glsl_programs(Node *output)
                                                // and then let the next passes read from that.
                                                start_new_phase = true;
                                        } else {
+                                               assert(deps[i]->effect->num_inputs() == 0);
+
                                                // For textures, we try to be slightly more clever;
                                                // if none of our outputs need a bounce, we don't bounce
                                                // but instead simply use the effect many times.
@@ -1412,10 +1426,6 @@ void EffectChain::finalize()
 
        output_dot("step19-split-to-phases.dot");
 
-       for (unsigned i = 0; i < inputs.size(); ++i) {
-               inputs[i]->finalize();
-       }
-
        assert(phases[0]->inputs.empty());
        
        finalized = true;
@@ -1447,13 +1457,6 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height
        glDepthMask(GL_FALSE);
        check_error();
 
-       glMatrixMode(GL_PROJECTION);
-       glLoadIdentity();
-       glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0);
-
-       glMatrixMode(GL_MODELVIEW);
-       glLoadIdentity();
-
        if (phases.size() > 1) {
                glGenFramebuffers(1, &fbo);
                check_error();
@@ -1477,13 +1480,16 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height
                        output_textures.insert(make_pair(phases[phase], tex_num));
                }
 
-               glUseProgram(phases[phase]->glsl_program_num);
+               const GLuint glsl_program_num = phases[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) {
                        glActiveTexture(GL_TEXTURE0 + sampler);
                        Node *input = phases[phase]->inputs[sampler];
+                       input->bound_sampler_num = sampler;
                        glBindTexture(GL_TEXTURE_2D, output_textures[input->phase]);
                        check_error();
                        if (phases[phase]->input_needs_mipmaps) {
@@ -1504,7 +1510,7 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height
                        check_error();
 
                        string texture_name = string("tex_") + phases[phase]->effect_ids[input];
-                       glUniform1i(glGetUniformLocation(phases[phase]->glsl_program_num, texture_name.c_str()), sampler);
+                       glUniform1i(glGetUniformLocation(glsl_program_num, texture_name.c_str()), sampler);
                        check_error();
                }
 
@@ -1537,32 +1543,51 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height
                unsigned sampler_num = phases[phase]->inputs.size();
                for (unsigned i = 0; i < phases[phase]->effects.size(); ++i) {
                        Node *node = phases[phase]->effects[i];
-                       node->effect->set_gl_state(phases[phase]->glsl_program_num, phases[phase]->effect_ids[node], &sampler_num);
+                       unsigned old_sampler_num = sampler_num;
+                       node->effect->set_gl_state(glsl_program_num, phases[phase]->effect_ids[node], &sampler_num);
                        check_error();
+
+                       if (node->effect->is_single_texture()) {
+                               assert(sampler_num - old_sampler_num == 1);
+                               node->bound_sampler_num = old_sampler_num;
+                       } else {
+                               node->bound_sampler_num = -1;
+                       }
                }
 
                // Now draw!
-               glBegin(GL_QUADS);
-
-               glTexCoord2f(0.0f, 0.0f);
-               glVertex2f(0.0f, 0.0f);
+               float vertices[] = {
+                       0.0f, 1.0f,
+                       0.0f, 0.0f,
+                       1.0f, 1.0f,
+                       1.0f, 0.0f
+               };
+
+               GLuint vao;
+               glGenVertexArrays(1, &vao);
+               check_error();
+               glBindVertexArray(vao);
+               check_error();
 
-               glTexCoord2f(1.0f, 0.0f);
-               glVertex2f(1.0f, 0.0f);
+               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.
 
-               glTexCoord2f(1.0f, 1.0f);
-               glVertex2f(1.0f, 1.0f);
+               glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+               check_error();
 
-               glTexCoord2f(0.0f, 1.0f);
-               glVertex2f(0.0f, 1.0f);
+               cleanup_vertex_attribute(glsl_program_num, "position", position_vbo);
+               cleanup_vertex_attribute(glsl_program_num, "texcoord", texcoord_vbo);
 
-               glEnd();
+               glUseProgram(0);
                check_error();
 
                for (unsigned i = 0; i < phases[phase]->effects.size(); ++i) {
                        Node *node = phases[phase]->effects[i];
                        node->effect->clear_gl_state();
                }
+
+               glDeleteVertexArrays(1, &vao);
+               check_error();
        }
 
        for (map<Phase *, GLuint>::const_iterator texture_it = output_textures.begin();
@@ -1579,3 +1604,5 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height
                check_error();
        }
 }
+
+}  // namespace movit