Add a function to let non-input effects override texture bounce.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 1 Nov 2015 01:09:56 +0000 (02:09 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 1 Nov 2015 01:09:56 +0000 (02:09 +0100)
Definitely read the comment before using; it is not for the faint
of heart. Also make ResampleEffect tolerate this kind of abuse.

effect.h
effect_chain.cpp
effect_chain.h
resample_effect.cpp

index 6154dac..ebbb672 100644 (file)
--- a/effect.h
+++ b/effect.h
@@ -217,6 +217,20 @@ public:
        //     and allow dependent effects to change that sampler state.
        virtual bool is_single_texture() const { return false; }
 
+       // If set, this effect should never be bounced to an output, even if a
+       // dependent effect demands texture bounce.
+       //
+       // Note that setting this can invoke undefined behavior, up to and including crashing,
+       // so you should only use it if you have deep understanding of your entire chain
+       // and Movit's processing of it. The most likely use case is if you have an input
+       // that's cheap to compute but not a single texture (e.g. YCbCrInput), and want
+       // to run a ResampleEffect directly from it. Normally, this would require a bounce,
+       // but it's faster not to. (However, also note that in this case, effective texel
+       // subpixel precision will be too optimistic, since chroma is already subsampled.)
+       //
+       // Has no effect if is_single_texture() is set.
+       virtual bool override_disable_bounce() const { return false; }
+
        // If changes_output_size() is true, you must implement this to tell
        // the framework what output size you want. Also, you can set a
        // virtual width/height, which is the size the next effect (if any)
index 4a333ea..3905564 100644 (file)
@@ -184,6 +184,13 @@ GLenum EffectChain::get_input_sampler(Node *node, unsigned input_num) const
        return GL_TEXTURE0 + node->incoming_links[input_num]->bound_sampler_num;
 }
 
+GLenum EffectChain::has_input_sampler(Node *node, unsigned input_num) const
+{
+       assert(input_num < node->incoming_links.size());
+       return node->incoming_links[input_num]->bound_sampler_num >= 0 &&
+               node->incoming_links[input_num]->bound_sampler_num < 8;
+}
+
 void EffectChain::find_all_nonlinear_inputs(Node *node, vector<Node *> *nonlinear_inputs)
 {
        if (node->output_gamma_curve == GAMMA_LINEAR &&
@@ -500,7 +507,8 @@ Phase *EffectChain::construct_phase(Node *output, map<Node *, Phase *> *complete
                        bool start_new_phase = false;
 
                        if (node->effect->needs_texture_bounce() &&
-                           !deps[i]->effect->is_single_texture()) {
+                           !deps[i]->effect->is_single_texture() &&
+                           !deps[i]->effect->override_disable_bounce()) {
                                start_new_phase = true;
                        }
 
index 9fb1d4e..c3dadff 100644 (file)
@@ -303,6 +303,13 @@ public:
        // single-sampler input, or from an RTT texture.
        GLenum get_input_sampler(Node *node, unsigned input_num) const;
 
+       // Whether input <input_num> of <node> corresponds to a single sampler
+       // (see get_input_sampler()). Normally, you should not need to call this;
+       // however, if the input Effect has set override_texture_bounce(),
+       // this will return false, and you could be flexible and check it first
+       // if you want.
+       GLenum has_input_sampler(Node *node, unsigned input_num) const;
+
        // 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
index 95f5575..a731568 100644 (file)
@@ -717,10 +717,12 @@ void SingleResamplePassEffect::set_gl_state(GLuint glsl_program_num, const strin
        // We specifically do not want mipmaps on the input texture;
        // they break minification.
        Node *self = chain->find_node_for_effect(this);
-       glActiveTexture(chain->get_input_sampler(self, 0));
-       check_error();
-       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-       check_error();
+       if (chain->has_input_sampler(self, 0)) {
+               glActiveTexture(chain->get_input_sampler(self, 0));
+               check_error();
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+               check_error();
+       }
 }
 
 }  // namespace movit