]> git.sesse.net Git - movit/blobdiff - effect_chain.cpp
Properly check framebuffer status when generating FBOs.
[movit] / effect_chain.cpp
index 9aaa74829041028090079ed8d511abe8e4edd2dd..574c44e2a68a0c7dac6e5ff43693a628c7ae61af 100644 (file)
@@ -1,27 +1,29 @@
 #define GL_GLEXT_PROTOTYPES 1
 
-#include <stdio.h>
+#include <GL/glew.h>
+#include <assert.h>
+#include <locale.h>
 #include <math.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <locale.h>
-#include <assert.h>
-#include <GL/glew.h>
-
 #include <algorithm>
 #include <set>
 #include <stack>
 #include <vector>
 
-#include "util.h"
-#include "effect_chain.h"
-#include "gamma_expansion_effect.h"
-#include "gamma_compression_effect.h"
-#include "colorspace_conversion_effect.h"
-#include "alpha_multiplication_effect.h"
 #include "alpha_division_effect.h"
+#include "alpha_multiplication_effect.h"
+#include "colorspace_conversion_effect.h"
 #include "dither_effect.h"
-#include "input.h"
+#include "effect.h"
+#include "effect_chain.h"
+#include "gamma_compression_effect.h"
+#include "gamma_expansion_effect.h"
 #include "init.h"
+#include "input.h"
+#include "util.h"
 
 EffectChain::EffectChain(float aspect_nom, float aspect_denom)
        : aspect_nom(aspect_nom),
@@ -618,8 +620,8 @@ void EffectChain::inform_input_sizes(Phase *phase)
        }
        for (unsigned i = 0; i < phase->inputs.size(); ++i) {
                Node *input = phase->inputs[i];
-               input->output_width = input->phase->output_width;
-               input->output_height = input->phase->output_height;
+               input->output_width = input->phase->virtual_output_width;
+               input->output_height = input->phase->virtual_output_height;
                assert(input->output_width != 0);
                assert(input->output_height != 0);
        }
@@ -662,7 +664,8 @@ void EffectChain::find_output_size(Phase *phase)
 
        // If the last effect explicitly sets an output size, use that.
        if (output_node->effect->changes_output_size()) {
-               output_node->effect->get_output_size(&phase->output_width, &phase->output_height);
+               output_node->effect->get_output_size(&phase->output_width, &phase->output_height,
+                                                    &phase->virtual_output_width, &phase->virtual_output_height);
                return;
        }
 
@@ -675,10 +678,10 @@ void EffectChain::find_output_size(Phase *phase)
                assert(input->phase->output_width != 0);
                assert(input->phase->output_height != 0);
                if (output_width == 0 && output_height == 0) {
-                       output_width = input->phase->output_width;
-                       output_height = input->phase->output_height;
-               } else if (output_width != input->phase->output_width ||
-                          output_height != input->phase->output_height) {
+                       output_width = input->phase->virtual_output_width;
+                       output_height = input->phase->virtual_output_height;
+               } else if (output_width != input->phase->virtual_output_width ||
+                          output_height != input->phase->virtual_output_height) {
                        all_inputs_same_size = false;
                }
        }
@@ -701,8 +704,8 @@ void EffectChain::find_output_size(Phase *phase)
        if (all_inputs_same_size) {
                assert(output_width != 0);
                assert(output_height != 0);
-               phase->output_width = output_width;
-               phase->output_height = output_height;
+               phase->virtual_output_width = phase->output_width = output_width;
+               phase->virtual_output_height = phase->output_height = output_height;
                return;
        }
 
@@ -726,8 +729,8 @@ void EffectChain::find_output_size(Phase *phase)
        }
        assert(output_width != 0);
        assert(output_height != 0);
-       phase->output_width = output_width;
-       phase->output_height = output_height;
+       phase->virtual_output_width = phase->output_width = output_width;
+       phase->virtual_output_height = phase->output_height = output_height;
 }
 
 void EffectChain::sort_all_nodes_topologically()
@@ -775,12 +778,13 @@ void EffectChain::find_color_spaces_for_inputs()
                        case Effect::OUTPUT_BLANK_ALPHA:
                                node->output_alpha_type = ALPHA_BLANK;
                                break;
-                       case Effect::INPUT_AND_OUTPUT_ALPHA_PREMULTIPLIED:
+                       case Effect::INPUT_AND_OUTPUT_PREMULTIPLIED_ALPHA:
                                node->output_alpha_type = ALPHA_PREMULTIPLIED;
                                break;
-                       case Effect::OUTPUT_ALPHA_POSTMULTIPLIED:
+                       case Effect::OUTPUT_POSTMULTIPLIED_ALPHA:
                                node->output_alpha_type = ALPHA_POSTMULTIPLIED;
                                break;
+                       case Effect::INPUT_PREMULTIPLIED_ALPHA_KEEP_BLANK:
                        case Effect::DONT_CARE_ALPHA_TYPE:
                        default:
                                assert(false);
@@ -884,7 +888,7 @@ void EffectChain::propagate_alpha()
                }
 
                // Only inputs can have unconditional alpha output (OUTPUT_BLANK_ALPHA
-               // or OUTPUT_ALPHA_POSTMULTIPLIED), and they have already been
+               // or OUTPUT_POSTMULTIPLIED_ALPHA), and they have already been
                // taken care of above. Rationale: Even if you could imagine
                // e.g. an effect that took in an image and set alpha=1.0
                // unconditionally, it wouldn't make any sense to have it as
@@ -892,7 +896,8 @@ void EffectChain::propagate_alpha()
                // got its input pre- or postmultiplied, so it wouldn't know
                // whether to divide away the old alpha or not.
                Effect::AlphaHandling alpha_handling = node->effect->alpha_handling();
-               assert(alpha_handling == Effect::INPUT_AND_OUTPUT_ALPHA_PREMULTIPLIED ||
+               assert(alpha_handling == Effect::INPUT_AND_OUTPUT_PREMULTIPLIED_ALPHA ||
+                      alpha_handling == Effect::INPUT_PREMULTIPLIED_ALPHA_KEEP_BLANK ||
                       alpha_handling == Effect::DONT_CARE_ALPHA_TYPE);
 
                // If the node has multiple inputs, check that they are all valid and
@@ -932,16 +937,16 @@ void EffectChain::propagate_alpha()
                        continue;
                }
 
-               if (alpha_handling == Effect::INPUT_AND_OUTPUT_ALPHA_PREMULTIPLIED) {
+               if (alpha_handling == Effect::INPUT_AND_OUTPUT_PREMULTIPLIED_ALPHA ||
+                   alpha_handling == Effect::INPUT_PREMULTIPLIED_ALPHA_KEEP_BLANK) {
                        // If the effect has asked for premultiplied alpha, check that it has got it.
                        if (any_postmultiplied) {
                                node->output_alpha_type = ALPHA_INVALID;
+                       } else if (!any_premultiplied &&
+                                  alpha_handling == Effect::INPUT_PREMULTIPLIED_ALPHA_KEEP_BLANK) {
+                               // Blank input alpha, and the effect preserves blank alpha.
+                               node->output_alpha_type = ALPHA_BLANK;
                        } else {
-                               // In some rare cases, it might be advantageous to say
-                               // that blank input alpha yields blank output alpha.
-                               // However, this would cause a more complex Effect interface
-                               // an effect would need to guarantee that it doesn't mess with
-                               // blank alpha), so this is the simplest.
                                node->output_alpha_type = ALPHA_PREMULTIPLIED;
                        }
                } else {
@@ -1140,14 +1145,14 @@ void EffectChain::fix_output_alpha()
                return;
        }
        if (output->output_alpha_type == ALPHA_PREMULTIPLIED &&
-           output_alpha_format == OUTPUT_ALPHA_POSTMULTIPLIED) {
+           output_alpha_format == OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED) {
                Node *conversion = add_node(new AlphaDivisionEffect());
                connect_nodes(output, conversion);
                propagate_alpha();
                propagate_gamma_and_color_space();
        }
        if (output->output_alpha_type == ALPHA_POSTMULTIPLIED &&
-           output_alpha_format == OUTPUT_ALPHA_PREMULTIPLIED) {
+           output_alpha_format == OUTPUT_ALPHA_FORMAT_PREMULTIPLIED) {
                Node *conversion = add_node(new AlphaMultiplicationEffect());
                connect_nodes(output, conversion);
                propagate_alpha();
@@ -1554,6 +1559,8 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height
                        // Last phase goes to the output the user specified.
                        glBindFramebuffer(GL_FRAMEBUFFER, dest_fbo);
                        check_error();
+                       GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+                       assert(status == GL_FRAMEBUFFER_COMPLETE);
                        glViewport(x, y, width, height);
                        if (dither_effect != NULL) {
                                CHECK(dither_effect->set_int("output_width", width));
@@ -1568,6 +1575,8 @@ void EffectChain::render_to_fbo(GLuint dest_fbo, unsigned width, unsigned height
                                output_node->output_texture,
                                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);
                }