Rework uniform setting.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 13 Sep 2015 15:44:58 +0000 (17:44 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 13 Sep 2015 15:52:47 +0000 (17:52 +0200)
One would think something as mundane as setting a few uniforms wouldn't
really mean much for performance, but seemingly this is not always so --
I had a real-world shader that counted no less than 55 uniforms.
Of course, not all of these were actually used, but we still have to go
through looking up the name etc. for every single one, every single frame.

Thus, we introduce a new way of dealing with uniforms: Register them before
finalization time, and then EffectChain can store their numbers once and
for all, instead of this repeated lookup. The system is also set up such
that we can go to uniform buffer objects (UBOs) in the very near future.

It's a bit unfortunate that uniform declaration now is removed from the
.frag files, where it sat very nicely, but the alternative would be to
try to parse GLSL, which I'm a bit wary at right now. All effects are
converted, leaving the set_uniform_* functions without any users, but
they are kept around for now in case external effects want them.

This seems to bring 1–2% speedup for my use case; hopefully UBOs will
bring a tiny bit more.

59 files changed:
blur_effect.cpp
blur_effect.frag
blur_effect.h
complex_modulate_effect.cpp
complex_modulate_effect.frag
complex_modulate_effect.h
deconvolution_sharpen_effect.cpp
deconvolution_sharpen_effect.frag
deconvolution_sharpen_effect.h
dither_effect.cpp
dither_effect.frag
dither_effect.h
effect.cpp
effect.h
effect_chain.cpp
effect_chain.h
effect_util.h
fft_input.cpp
fft_input.h
fft_pass_effect.cpp
fft_pass_effect.frag
fft_pass_effect.h
flat_input.cpp
flat_input.frag
flat_input.h
gamma_compression_effect.cpp
gamma_compression_effect.frag
gamma_compression_effect.h
gamma_expansion_effect.cpp
gamma_expansion_effect.frag
gamma_expansion_effect.h
lift_gamma_gain_effect.cpp
lift_gamma_gain_effect.frag
lift_gamma_gain_effect.h
luma_mix_effect.cpp
luma_mix_effect.frag
luma_mix_effect.h
padding_effect.cpp
padding_effect.frag
padding_effect.h
resample_effect.cpp
resample_effect.frag
resample_effect.h
slice_effect.cpp
slice_effect.frag
slice_effect.h
version.h
vignette_effect.cpp
vignette_effect.frag
vignette_effect.h
white_balance_effect.cpp
white_balance_effect.frag
white_balance_effect.h
ycbcr_422interleaved_input.cpp
ycbcr_422interleaved_input.frag
ycbcr_422interleaved_input.h
ycbcr_input.cpp
ycbcr_input.frag
ycbcr_input.h

index 29e46b0..2084768 100644 (file)
@@ -108,8 +108,9 @@ SingleBlurPassEffect::SingleBlurPassEffect(BlurEffect *parent)
          num_taps(16),
          radius(3.0f),
          direction(HORIZONTAL),
-         width(1280),
-         height(720)
+         width(1280),
+         height(720),
+         uniform_samples(NULL)
 {
        register_float("radius", &radius);
        register_int("direction", (int *)&direction);
@@ -120,11 +121,18 @@ SingleBlurPassEffect::SingleBlurPassEffect(BlurEffect *parent)
        register_int("num_taps", &num_taps);
 }
 
+SingleBlurPassEffect::~SingleBlurPassEffect()
+{
+       delete[] uniform_samples;
+}
+
 string SingleBlurPassEffect::output_fragment_shader()
 {
        char buf[256];
        sprintf(buf, "#define DIRECTION_VERTICAL %d\n#define NUM_TAPS %d\n",
                (direction == VERTICAL), num_taps);
+       uniform_samples = new float[2 * (num_taps / 2 + 1)];
+       register_uniform_vec2_array("samples", uniform_samples, num_taps / 2 + 1);
        return buf + read_file("blur_effect.frag");
 }
 
@@ -176,11 +184,10 @@ void SingleBlurPassEffect::set_gl_state(GLuint glsl_program_num, const string &p
        //
        // We pack the parameters into a float4: The relative sample coordinates
        // in (x,y), and the weight in z. w is unused.
-       float* samples = new float[2 * (num_taps / 2 + 1)];
 
        // Center sample.
-       samples[2 * 0 + 0] = 0.0f;
-       samples[2 * 0 + 1] = weight[0];
+       uniform_samples[2 * 0 + 0] = 0.0f;
+       uniform_samples[2 * 0 + 1] = weight[0];
 
        // All other samples.
        for (int i = 1; i < num_taps / 2 + 1; ++i) {
@@ -201,14 +208,11 @@ void SingleBlurPassEffect::set_gl_state(GLuint glsl_program_num, const string &p
                float pos, total_weight;
                combine_two_samples(w1, w2, pos1, pos2, size, &pos, &total_weight, NULL);
 
-               samples[2 * i + 0] = pos;
-               samples[2 * i + 1] = total_weight;
+               uniform_samples[2 * i + 0] = pos;
+               uniform_samples[2 * i + 1] = total_weight;
        }
 
-       set_uniform_vec2_array(glsl_program_num, prefix, "samples", samples, num_taps / 2 + 1);
-
        delete[] weight;
-       delete[] samples;
 }
 
 void SingleBlurPassEffect::clear_gl_state()
index 8a7a4a6..f8497b3 100644 (file)
@@ -2,7 +2,8 @@
 // DIRECTION_VERTICAL will be #defined to 1 if we are doing a vertical blur,
 // 0 otherwise.
 
-uniform vec2 PREFIX(samples)[NUM_TAPS / 2 + 1];
+// Implicit uniforms:
+// uniform vec2 PREFIX(samples)[NUM_TAPS / 2 + 1];
 
 vec4 FUNCNAME(vec2 tc) {
        vec4 sum = vec4(PREFIX(samples)[0].y) * INPUT(tc);
index eb35790..8ad3da9 100644 (file)
@@ -66,6 +66,7 @@ public:
        // If parent is non-NULL, calls to inform_input_size will be forwarded
        // so that it can make reasonable decisions for both blur passes.
        SingleBlurPassEffect(BlurEffect *parent);
+       virtual ~SingleBlurPassEffect();
        virtual std::string effect_type_id() const { return "SingleBlurPassEffect"; }
 
        std::string output_fragment_shader();
@@ -102,6 +103,7 @@ private:
        float radius;
        Direction direction;
        int width, height, virtual_width, virtual_height;
+       float *uniform_samples;
 };
 
 }  // namespace movit
index 9483f6b..6b50823 100644 (file)
@@ -14,6 +14,7 @@ ComplexModulateEffect::ComplexModulateEffect()
 {
        register_int("num_repeats_x", &num_repeats_x);
        register_int("num_repeats_y", &num_repeats_y);
+       register_vec2("num_repeats", uniform_num_repeats);
 }
 
 string ComplexModulateEffect::output_fragment_shader()
@@ -25,8 +26,8 @@ void ComplexModulateEffect::set_gl_state(GLuint glsl_program_num, const string &
 {
        Effect::set_gl_state(glsl_program_num, prefix, sampler_num);
 
-       float num_repeats[] = { float(num_repeats_x), float(num_repeats_y) };
-       set_uniform_vec2(glsl_program_num, prefix, "num_repeats", num_repeats);
+       uniform_num_repeats[0] = float(num_repeats_x);
+       uniform_num_repeats[1] = float(num_repeats_y);
 
        // Set the secondary input to repeat (and nearest while we're at it).
        Node *self = chain->find_node_for_effect(this);
index 46de5da..d07a729 100644 (file)
@@ -1,4 +1,5 @@
-uniform vec2 PREFIX(num_repeats);
+// Implicit uniforms:
+// uniform vec2 PREFIX(num_repeats);
 
 vec4 FUNCNAME(vec2 tc) {
        vec4 pixel = INPUT1(tc);
index e2bf50d..335c900 100644 (file)
@@ -55,6 +55,7 @@ private:
        EffectChain *chain;
        int primary_input_width, primary_input_height;
        int num_repeats_x, num_repeats_y;
+       float uniform_num_repeats[2];
 };
 
 }  // namespace movit
index c4ad5cd..2db15dc 100644 (file)
@@ -31,7 +31,8 @@ DeconvolutionSharpenEffect::DeconvolutionSharpenEffect()
          last_circle_radius(-1.0f),
          last_gaussian_radius(-1.0f),
          last_correlation(-1.0f),
-         last_noise(-1.0f)
+         last_noise(-1.0f),
+         uniform_samples(NULL)
 {
        register_int("matrix_size", &R);
        register_float("circle_radius", &circle_radius);
@@ -40,6 +41,11 @@ DeconvolutionSharpenEffect::DeconvolutionSharpenEffect()
        register_float("noise", &noise);
 }
 
+DeconvolutionSharpenEffect::~DeconvolutionSharpenEffect()
+{
+       delete[] uniform_samples;
+}
+
 string DeconvolutionSharpenEffect::output_fragment_shader()
 {
        char buf[256];
@@ -48,6 +54,9 @@ string DeconvolutionSharpenEffect::output_fragment_shader()
        assert(R >= 1);
        assert(R <= 25);  // Same limit as Refocus.
 
+       uniform_samples = new float[4 * (R + 1) * (R + 1)];
+       register_uniform_vec4_array("samples", uniform_samples, (R + 1) * (R + 1));
+
        last_R = R;
        return buf + read_file("deconvolution_sharpen_effect.frag");
 }
@@ -433,18 +442,15 @@ void DeconvolutionSharpenEffect::set_gl_state(GLuint glsl_program_num, const str
                update_deconvolution_kernel();
        }
        // Now encode it as uniforms, and pass it on to the shader.
-       float samples[4 * (R + 1) * (R + 1)];
        for (int y = 0; y <= R; ++y) {
                for (int x = 0; x <= R; ++x) {
                        int i = y * (R + 1) + x;
-                       samples[i * 4 + 0] = x / float(width);
-                       samples[i * 4 + 1] = y / float(height);
-                       samples[i * 4 + 2] = g(y, x);
-                       samples[i * 4 + 3] = 0.0f;
+                       uniform_samples[i * 4 + 0] = x / float(width);
+                       uniform_samples[i * 4 + 1] = y / float(height);
+                       uniform_samples[i * 4 + 2] = g(y, x);
+                       uniform_samples[i * 4 + 3] = 0.0f;
                }
        }
-
-       set_uniform_vec4_array(glsl_program_num, prefix, "samples", samples, (R + 1) * (R + 1));
 }
 
 }  // namespace movit
index 75f249a..e9c560d 100644 (file)
@@ -1,4 +1,5 @@
-uniform vec4 PREFIX(samples)[(R + 1) * (R + 1)];
+// Implicit uniforms:
+// uniform vec4 PREFIX(samples)[(R + 1) * (R + 1)];
 
 vec4 FUNCNAME(vec2 tc) {
        // The full matrix has five different symmetry cases, that look like this:
index 1f68071..c2ccbcb 100644 (file)
@@ -30,6 +30,7 @@ namespace movit {
 class DeconvolutionSharpenEffect : public Effect {
 public:
        DeconvolutionSharpenEffect();
+       virtual ~DeconvolutionSharpenEffect();
        virtual std::string effect_type_id() const { return "DeconvolutionSharpenEffect"; }
        std::string output_fragment_shader();
 
@@ -66,6 +67,8 @@ private:
        Eigen::MatrixXf g;
        int last_R;
        float last_circle_radius, last_gaussian_radius, last_correlation, last_noise;
+
+       float *uniform_samples;
        
        void update_deconvolution_kernel();
 };
index 41ea9b4..574d70a 100644 (file)
@@ -35,6 +35,10 @@ DitherEffect::DitherEffect()
        register_int("output_width", &width);
        register_int("output_height", &height);
        register_int("num_bits", &num_bits);
+       register_uniform_float("round_fac", &uniform_round_fac);
+       register_uniform_float("inv_round_fac", &uniform_inv_round_fac);
+       register_uniform_vec2("tc_scale", uniform_tc_scale);
+       register_uniform_sampler2d("dither_tex", &uniform_dither_tex);
 
        glGenTextures(1, &texnum);
 }
@@ -110,19 +114,19 @@ void DitherEffect::set_gl_state(GLuint glsl_program_num, const string &prefix, u
        glBindTexture(GL_TEXTURE_2D, texnum);
        check_error();
 
-       set_uniform_int(glsl_program_num, prefix, "dither_tex", *sampler_num);
+       uniform_dither_tex = *sampler_num;
        ++*sampler_num;
 
        // In theory, we should adjust for the texel centers that have moved here as well,
        // but since we use GL_NEAREST and we don't really care a lot what texel we sample,
        // we don't have to worry about it.     
-       float tc_scale[] = { float(width) / float(texture_width), float(height) / float(texture_height) };
-       set_uniform_vec2(glsl_program_num, prefix, "tc_scale", tc_scale);
+       uniform_tc_scale[0] = float(width) / float(texture_width);
+       uniform_tc_scale[1] = float(height) / float(texture_height);
 
        // Used if the shader needs to do explicit rounding.
        int round_fac = (1 << num_bits) - 1;
-       set_uniform_float(glsl_program_num, prefix, "round_fac", round_fac);
-       set_uniform_float(glsl_program_num, prefix, "inv_round_fac", 1.0f / round_fac);
+       uniform_round_fac = round_fac;
+       uniform_inv_round_fac = 1.0f / round_fac;
 }
 
 }  // namespace movit
index 3b6b892..b12ecd7 100644 (file)
@@ -1,6 +1,7 @@
-uniform sampler2D PREFIX(dither_tex);
-uniform vec2 PREFIX(tc_scale);
-uniform float PREFIX(round_fac), PREFIX(inv_round_fac);
+// Implicit uniforms:
+// uniform sampler2D PREFIX(dither_tex);
+// uniform vec2 PREFIX(tc_scale);
+// uniform float PREFIX(round_fac), PREFIX(inv_round_fac);
 
 vec4 FUNCNAME(vec2 tc) {
        vec4 result = INPUT(tc);
index e580586..921a1ef 100644 (file)
@@ -78,6 +78,9 @@ private:
        int texture_width, texture_height;
 
        GLuint texnum;
+       float uniform_round_fac, uniform_inv_round_fac;
+       float uniform_tc_scale[2];
+       GLint uniform_dither_tex;
 };
 
 }  // namespace movit
index fb66514..df73eea 100644 (file)
@@ -7,6 +7,7 @@
 #include "effect.h"
 #include "effect_util.h"
 
+using namespace Eigen;
 using namespace std;
 
 namespace movit {
@@ -66,86 +67,132 @@ void Effect::register_float(const string &key, float *value)
 {
        assert(params_float.count(key) == 0);
        params_float[key] = value;
+       register_uniform_float(key, value);
 }
 
 void Effect::register_vec2(const string &key, float *values)
 {
        assert(params_vec2.count(key) == 0);
        params_vec2[key] = values;
+       register_uniform_vec2(key, values);
 }
 
 void Effect::register_vec3(const string &key, float *values)
 {
        assert(params_vec3.count(key) == 0);
        params_vec3[key] = values;
+       register_uniform_vec3(key, values);
 }
 
 void Effect::register_vec4(const string &key, float *values)
 {
        assert(params_vec4.count(key) == 0);
        params_vec4[key] = values;
+       register_uniform_vec4(key, values);
 }
 
-// Output convenience uniforms for each parameter.
-// These will be filled in per-frame.
-string Effect::output_convenience_uniforms() const
+void Effect::set_gl_state(GLuint glsl_program_num, const string& prefix, unsigned *sampler_num) {}
+
+void Effect::clear_gl_state() {}
+
+void Effect::register_uniform_bool(const std::string &key, const bool *value)
 {
-       string output = "";
-       for (map<string, float*>::const_iterator it = params_float.begin();
-            it != params_float.end();
-            ++it) {
-               char buf[256];
-               sprintf(buf, "uniform float PREFIX(%s);\n", it->first.c_str());
-               output.append(buf);
-       }
-       for (map<string, float*>::const_iterator it = params_vec2.begin();
-            it != params_vec2.end();
-            ++it) {
-               char buf[256];
-               sprintf(buf, "uniform vec2 PREFIX(%s);\n", it->first.c_str());
-               output.append(buf);
-       }
-       for (map<string, float*>::const_iterator it = params_vec3.begin();
-            it != params_vec3.end();
-            ++it) {
-               char buf[256];
-               sprintf(buf, "uniform vec3 PREFIX(%s);\n", it->first.c_str());
-               output.append(buf);
-       }
-       for (map<string, float*>::const_iterator it = params_vec4.begin();
-            it != params_vec4.end();
-            ++it) {
-               char buf[256];
-               sprintf(buf, "uniform vec4 PREFIX(%s);\n", it->first.c_str());
-               output.append(buf);
-       }
-       return output;
+       Uniform<bool> uniform;
+       uniform.name = key;
+       uniform.value = value;
+       uniform.num_values = 1;
+       uniform.location = -1;
+       uniforms_bool.push_back(uniform);
 }
 
-void Effect::set_gl_state(GLuint glsl_program_num, const string& prefix, unsigned *sampler_num)
+void Effect::register_uniform_int(const std::string &key, const int *value)
 {
-       for (map<string, float*>::const_iterator it = params_float.begin();
-            it != params_float.end();
-            ++it) {
-               set_uniform_float(glsl_program_num, prefix, it->first, *it->second);
-       }
-       for (map<string, float*>::const_iterator it = params_vec2.begin();
-            it != params_vec2.end();
-            ++it) {
-               set_uniform_vec2(glsl_program_num, prefix, it->first, it->second);
-       }
-       for (map<string, float*>::const_iterator it = params_vec3.begin();
-            it != params_vec3.end();
-            ++it) {
-               set_uniform_vec3(glsl_program_num, prefix, it->first, it->second);
-       }
-       for (map<string, float*>::const_iterator it = params_vec4.begin();
-            it != params_vec4.end();
-            ++it) {
-               set_uniform_vec4(glsl_program_num, prefix, it->first, it->second);
-       }
+       Uniform<int> uniform;
+       uniform.name = key;
+       uniform.value = value;
+       uniform.num_values = 1;
+       uniform.location = -1;
+       uniforms_int.push_back(uniform);
 }
 
-void Effect::clear_gl_state() {}
+void Effect::register_uniform_sampler2d(const std::string &key, const GLint *value)
+{
+       Uniform<int> uniform;
+       uniform.name = key;
+       uniform.value = value;
+       uniform.num_values = 1;
+       uniform.location = -1;
+       uniforms_sampler2d.push_back(uniform);
+}
+
+void Effect::register_uniform_float(const std::string &key, const float *value)
+{
+       Uniform<float> uniform;
+       uniform.name = key;
+       uniform.value = value;
+       uniform.num_values = 1;
+       uniform.location = -1;
+       uniforms_float.push_back(uniform);
+}
+
+void Effect::register_uniform_vec2(const std::string &key, const float *values)
+{
+       Uniform<float> uniform;
+       uniform.name = key;
+       uniform.value = values;
+       uniform.num_values = 1;
+       uniform.location = -1;
+       uniforms_vec2.push_back(uniform);
+}
+
+void Effect::register_uniform_vec3(const std::string &key, const float *values)
+{
+       Uniform<float> uniform;
+       uniform.name = key;
+       uniform.value = values;
+       uniform.num_values = 1;
+       uniform.location = -1;
+       uniforms_vec3.push_back(uniform);
+}
+
+void Effect::register_uniform_vec4(const std::string &key, const float *values)
+{
+       Uniform<float> uniform;
+       uniform.name = key;
+       uniform.value = values;
+       uniform.num_values = 1;
+       uniform.location = -1;
+       uniforms_vec4.push_back(uniform);
+}
+
+void Effect::register_uniform_vec2_array(const std::string &key, const float *values, size_t num_values)
+{
+       Uniform<float> uniform;
+       uniform.name = key;
+       uniform.value = values;
+       uniform.num_values = num_values;
+       uniform.location = -1;
+       uniforms_vec2_array.push_back(uniform);
+}
+
+void Effect::register_uniform_vec4_array(const std::string &key, const float *values, size_t num_values)
+{
+       Uniform<float> uniform;
+       uniform.name = key;
+       uniform.value = values;
+       uniform.num_values = num_values;
+       uniform.location = -1;
+       uniforms_vec4_array.push_back(uniform);
+}
+
+void Effect::register_uniform_mat3(const std::string &key, const Matrix3d *matrix)
+{
+       Uniform<Matrix3d> uniform;
+       uniform.name = key;
+       uniform.value = matrix;
+       uniform.num_values = 1;
+       uniform.location = -1;
+       uniforms_mat3.push_back(uniform);
+}
 
 }  // namespace movit
index 56c34d9..9d81a56 100644 (file)
--- a/effect.h
+++ b/effect.h
@@ -15,6 +15,8 @@
 #include <stddef.h>
 #include <map>
 #include <string>
+#include <vector>
+#include <Eigen/Core>
 
 #include "defs.h"
 
@@ -50,6 +52,16 @@ struct RGBATuple {
        float r, g, b, a;
 };
 
+// Represents a registered uniform.
+template<class T>
+struct Uniform {
+       std::string name;  // Without prefix.
+       const T *value;  // Owner by the effect.
+       size_t num_values;  // Number of elements; for arrays only. _Not_ the vector length.
+       std::string prefix;  // Filled in only after phases have been constructed.
+       GLint location;  // Filled in only after phases have been constructed. -1 if no location.
+};
+
 class Effect {
 public:
        virtual ~Effect() {}
@@ -256,11 +268,6 @@ public:
        // itself from all other effects.
        virtual void rewrite_graph(EffectChain *graph, Node *self) {}
 
-       // Outputs one GLSL uniform declaration for each registered parameter
-       // (see below), with the right prefix prepended to each uniform name.
-       // If you do not want this behavior, you can override this function.
-       virtual std::string output_convenience_uniforms() const;
-
        // Returns the GLSL fragment shader string for this effect.
        virtual std::string output_fragment_shader() = 0;
 
@@ -289,7 +296,9 @@ public:
 protected:
        // Register a parameter. Whenever set_*() is called with the same key,
        // it will update the value in the given pointer (typically a pointer
-       // to some private member variable in your effect).
+       // to some private member variable in your effect). It will also
+       // register a uniform of the same name (plus an arbitrary prefix
+       // which you can access using the PREFIX macro) that you can access.
        //
        // Neither of these take ownership of the pointer.
 
@@ -303,12 +312,56 @@ protected:
        void register_vec3(const std::string &key, float *values);
        void register_vec4(const std::string &key, float *values);
 
+       // Register uniforms, such that they will automatically be set
+       // before the shader runs. This is more efficient than set_uniform_*
+       // in effect_util.h, because it doesn't need to do name lookups
+       // every time. Also, in the future, it will use uniform buffer objects
+       // (UBOs) if available to reduce the number of calls into the driver.
+       //
+       // May not be called after output_fragment_shader() has returned.
+       // The pointer must be valid for the entire lifetime of the Effect,
+       // since the value is pulled from it each execution. The value is
+       // guaranteed to be read after set_gl_state() for the effect has
+       // returned, so you can safely update its value from there.
+       //
+       // Note that this will also declare the uniform in the shader for you,
+       // so you should not do that yourself. (This is so it can be part of
+       // the right uniform block.) However, it is probably a good idea to
+       // have a commented-out declaration so that it is easier to see the
+       // type and thus understand the shader on its own.
+       //
+       // Calling register_* will automatically imply register_uniform_*,
+       // except for register_int as noted above.
+       void register_uniform_bool(const std::string &key, const bool *value);
+       void register_uniform_int(const std::string &key, const int *value);  // Note: Requires GLSL 1.30 or newer.
+       void register_uniform_sampler2d(const std::string &key, const int *value);
+       void register_uniform_float(const std::string &key, const float *value);
+       void register_uniform_vec2(const std::string &key, const float *values);
+       void register_uniform_vec3(const std::string &key, const float *values);
+       void register_uniform_vec4(const std::string &key, const float *values);
+       void register_uniform_vec2_array(const std::string &key, const float *values, size_t num_values);
+       void register_uniform_vec4_array(const std::string &key, const float *values, size_t num_values);
+       void register_uniform_mat3(const std::string &key, const Eigen::Matrix3d *matrix);
+
 private:
        std::map<std::string, int *> params_int;
        std::map<std::string, float *> params_float;
        std::map<std::string, float *> params_vec2;
        std::map<std::string, float *> params_vec3;
        std::map<std::string, float *> params_vec4;
+
+       // Picked out by EffectChain during finalization.
+       std::vector<Uniform<bool> > uniforms_bool;
+       std::vector<Uniform<int> > uniforms_int;
+       std::vector<Uniform<int> > uniforms_sampler2d;
+       std::vector<Uniform<float> > uniforms_float;
+       std::vector<Uniform<float> > uniforms_vec2;
+       std::vector<Uniform<float> > uniforms_vec3;
+       std::vector<Uniform<float> > uniforms_vec4;
+       std::vector<Uniform<float> > uniforms_vec2_array;
+       std::vector<Uniform<float> > uniforms_vec4_array;
+       std::vector<Uniform<Eigen::Matrix3d> > uniforms_mat3;
+       friend class EffectChain;
 };
 
 }  // namespace movit
index e1ae832..6e297df 100644 (file)
@@ -12,6 +12,7 @@
 #include <stack>
 #include <utility>
 #include <vector>
+#include <Eigen/Core>
 
 #include "alpha_division_effect.h"
 #include "alpha_multiplication_effect.h"
@@ -19,6 +20,7 @@
 #include "dither_effect.h"
 #include "effect.h"
 #include "effect_chain.h"
+#include "effect_util.h"
 #include "gamma_compression_effect.h"
 #include "gamma_expansion_effect.h"
 #include "init.h"
@@ -27,6 +29,7 @@
 #include "util.h"
 #include "ycbcr_conversion_effect.h"
 
+using namespace Eigen;
 using namespace std;
 
 namespace movit {
@@ -246,7 +249,8 @@ string replace_prefix(const string &text, const string &prefix)
 
 void EffectChain::compile_glsl_program(Phase *phase)
 {
-       string frag_shader = read_version_dependent_file("header", "frag");
+       string frag_shader_header = read_version_dependent_file("header", "frag");
+       string frag_shader = "";
 
        // Create functions for all the texture inputs that we need.
        for (unsigned i = 0; i < phase->inputs.size(); ++i) {
@@ -262,12 +266,17 @@ void EffectChain::compile_glsl_program(Phase *phase)
                frag_shader += "\n";
        }
 
+       // Give each effect in the phase its own ID.
        for (unsigned i = 0; i < phase->effects.size(); ++i) {
                Node *node = phase->effects[i];
                char effect_id[256];
                sprintf(effect_id, "eff%u", i);
                phase->effect_ids.insert(make_pair(node, effect_id));
+       }
 
+       for (unsigned i = 0; i < phase->effects.size(); ++i) {
+               Node *node = phase->effects[i];
+               const string effect_id = phase->effect_ids[node];
                if (node->incoming_links.size() == 1) {
                        frag_shader += string("#define INPUT ") + phase->effect_ids[node->incoming_links[0]] + "\n";
                } else {
@@ -280,7 +289,6 @@ void EffectChain::compile_glsl_program(Phase *phase)
        
                frag_shader += "\n";
                frag_shader += string("#define FUNCNAME ") + effect_id + "\n";
-               frag_shader += replace_prefix(node->effect->output_convenience_uniforms(), effect_id);
                frag_shader += replace_prefix(node->effect->output_fragment_shader(), effect_id);
                frag_shader += "#undef PREFIX\n";
                frag_shader += "#undef FUNCNAME\n";
@@ -298,8 +306,119 @@ void EffectChain::compile_glsl_program(Phase *phase)
        frag_shader += string("#define INPUT ") + phase->effect_ids[phase->effects.back()] + "\n";
        frag_shader.append(read_version_dependent_file("footer", "frag"));
 
+       // Collect uniforms from all effects and output them. Note that this needs
+       // to happen after output_fragment_shader(), even though the uniforms come
+       // before in the output source, since output_fragment_shader() is allowed
+       // to register new uniforms (e.g. arrays that are of unknown length until
+       // finalization time).
+       // TODO: Make a uniform block for platforms that support it.
+       string frag_shader_uniforms = "";
+       for (unsigned i = 0; i < phase->effects.size(); ++i) {
+               Node *node = phase->effects[i];
+               Effect *effect = node->effect;
+               const string effect_id = phase->effect_ids[node];
+               for (unsigned j = 0; j < effect->uniforms_bool.size(); ++j) {
+                       phase->uniforms_bool.push_back(effect->uniforms_bool[j]);
+                       phase->uniforms_bool.back().prefix = effect_id;
+                       frag_shader_uniforms += string("uniform bool ") + effect_id
+                               + "_" + effect->uniforms_bool[j].name + ";\n";
+               }
+               for (unsigned j = 0; j < effect->uniforms_int.size(); ++j) {
+                       phase->uniforms_int.push_back(effect->uniforms_int[j]);
+                       phase->uniforms_int.back().prefix = effect_id;
+                       frag_shader_uniforms += string("uniform int ") + effect_id
+                               + "_" + effect->uniforms_int[j].name + ";\n";
+               }
+               for (unsigned j = 0; j < effect->uniforms_sampler2d.size(); ++j) {
+                       phase->uniforms_int.push_back(effect->uniforms_sampler2d[j]);
+                       phase->uniforms_int.back().prefix = effect_id;
+                       frag_shader_uniforms += string("uniform sampler2D ") + effect_id
+                               + "_" + effect->uniforms_sampler2d[j].name + ";\n";
+               }
+               for (unsigned j = 0; j < effect->uniforms_float.size(); ++j) {
+                       phase->uniforms_float.push_back(effect->uniforms_float[j]);
+                       phase->uniforms_float.back().prefix = effect_id;
+                       frag_shader_uniforms += string("uniform float ") + effect_id
+                               + "_" + effect->uniforms_float[j].name + ";\n";
+               }
+               for (unsigned j = 0; j < effect->uniforms_vec2.size(); ++j) {
+                       phase->uniforms_vec2.push_back(effect->uniforms_vec2[j]);
+                       phase->uniforms_vec2.back().prefix = effect_id;
+                       frag_shader_uniforms += string("uniform vec2 ") + effect_id
+                               + "_" + effect->uniforms_vec2[j].name + ";\n";
+               }
+               for (unsigned j = 0; j < effect->uniforms_vec3.size(); ++j) {
+                       phase->uniforms_vec3.push_back(effect->uniforms_vec3[j]);
+                       phase->uniforms_vec3.back().prefix = effect_id;
+                       frag_shader_uniforms += string("uniform vec3 ") + effect_id
+                               + "_" + effect->uniforms_vec3[j].name + ";\n";
+               }
+               for (unsigned j = 0; j < effect->uniforms_vec4.size(); ++j) {
+                       phase->uniforms_vec4.push_back(effect->uniforms_vec4[j]);
+                       phase->uniforms_vec4.back().prefix = effect_id;
+                       frag_shader_uniforms += string("uniform vec4 ") + effect_id
+                               + "_" + effect->uniforms_vec4[j].name + ";\n";
+               }
+               for (unsigned j = 0; j < effect->uniforms_vec2_array.size(); ++j) {
+                       char buf[256];
+                       phase->uniforms_vec2.push_back(effect->uniforms_vec2_array[j]);
+                       phase->uniforms_vec2.back().prefix = effect_id;
+                       snprintf(buf, sizeof(buf), "uniform vec2 %s_%s[%d];\n",
+                               effect_id.c_str(), effect->uniforms_vec2_array[j].name.c_str(),
+                               int(effect->uniforms_vec2_array[j].num_values));
+                       frag_shader_uniforms += buf;
+               }
+               for (unsigned j = 0; j < effect->uniforms_vec4_array.size(); ++j) {
+                       char buf[256];
+                       phase->uniforms_vec4.push_back(effect->uniforms_vec4_array[j]);
+                       phase->uniforms_vec4.back().prefix = effect_id;
+                       snprintf(buf, sizeof(buf), "uniform vec4 %s_%s[%d];\n",
+                               effect_id.c_str(), effect->uniforms_vec4_array[j].name.c_str(),
+                               int(effect->uniforms_vec4_array[j].num_values));
+                       frag_shader_uniforms += buf;
+               }
+               for (unsigned j = 0; j < effect->uniforms_mat3.size(); ++j) {
+                       phase->uniforms_mat3.push_back(effect->uniforms_mat3[j]);
+                       phase->uniforms_mat3.back().prefix = effect_id;
+                       frag_shader_uniforms += string("uniform mat3 ") + effect_id
+                               + "_" + effect->uniforms_mat3[j].name + ";\n";
+               }
+       }
+
+       frag_shader = frag_shader_header + frag_shader_uniforms + frag_shader;
+
        string vert_shader = read_version_dependent_file("vs", "vert");
        phase->glsl_program_num = resource_pool->compile_glsl_program(vert_shader, frag_shader);
+
+       // Collect the resulting program numbers for each uniform.
+       for (unsigned i = 0; i < phase->uniforms_bool.size(); ++i) {
+               Uniform<bool> &uniform = phase->uniforms_bool[i];
+               uniform.location = get_uniform_location(phase->glsl_program_num, uniform.prefix, uniform.name);
+       }
+       for (unsigned i = 0; i < phase->uniforms_int.size(); ++i) {
+               Uniform<int> &uniform = phase->uniforms_int[i];
+               uniform.location = get_uniform_location(phase->glsl_program_num, uniform.prefix, uniform.name);
+       }
+       for (unsigned i = 0; i < phase->uniforms_float.size(); ++i) {
+               Uniform<float> &uniform = phase->uniforms_float[i];
+               uniform.location = get_uniform_location(phase->glsl_program_num, uniform.prefix, uniform.name);
+       }
+       for (unsigned i = 0; i < phase->uniforms_vec2.size(); ++i) {
+               Uniform<float> &uniform = phase->uniforms_vec2[i];
+               uniform.location = get_uniform_location(phase->glsl_program_num, uniform.prefix, uniform.name);
+       }
+       for (unsigned i = 0; i < phase->uniforms_vec3.size(); ++i) {
+               Uniform<float> &uniform = phase->uniforms_vec3[i];
+               uniform.location = get_uniform_location(phase->glsl_program_num, uniform.prefix, uniform.name);
+       }
+       for (unsigned i = 0; i < phase->uniforms_vec4.size(); ++i) {
+               Uniform<float> &uniform = phase->uniforms_vec4[i];
+               uniform.location = get_uniform_location(phase->glsl_program_num, uniform.prefix, uniform.name);
+       }
+       for (unsigned i = 0; i < phase->uniforms_mat3.size(); ++i) {
+               Uniform<Matrix3d> &uniform = phase->uniforms_mat3[i];
+               uniform.location = get_uniform_location(phase->glsl_program_num, uniform.prefix, uniform.name);
+       }
 }
 
 // Construct GLSL programs, starting at the given effect and following
@@ -1671,6 +1790,10 @@ void EffectChain::execute_phase(Phase *phase, bool last_phase, map<Phase *, GLui
                }
        }
 
+       // Uniforms need to come after set_gl_state(), since they can be updated
+       // from there.
+       setup_uniforms(phase);
+
        // Now draw!
        float vertices[] = {
                0.0f, 2.0f,
@@ -1709,6 +1832,62 @@ void EffectChain::execute_phase(Phase *phase, bool last_phase, map<Phase *, GLui
        check_error();
 }
 
+void EffectChain::setup_uniforms(Phase *phase)
+{
+       // TODO: Use UBO blocks.
+       for (size_t i = 0; i < phase->uniforms_bool.size(); ++i) {
+               const Uniform<bool> &uniform = phase->uniforms_bool[i];
+               assert(uniform.num_values == 1);
+               if (uniform.location != -1) {
+                       glUniform1i(uniform.location, *uniform.value);
+               }
+       }
+       for (size_t i = 0; i < phase->uniforms_int.size(); ++i) {
+               const Uniform<int> &uniform = phase->uniforms_int[i];
+               if (uniform.location != -1) {
+                       glUniform1iv(uniform.location, uniform.num_values, uniform.value);
+               }
+       }
+       for (size_t i = 0; i < phase->uniforms_float.size(); ++i) {
+               const Uniform<float> &uniform = phase->uniforms_float[i];
+               if (uniform.location != -1) {
+                       glUniform1fv(uniform.location, uniform.num_values, uniform.value);
+               }
+       }
+       for (size_t i = 0; i < phase->uniforms_vec2.size(); ++i) {
+               const Uniform<float> &uniform = phase->uniforms_vec2[i];
+               if (uniform.location != -1) {
+                       glUniform2fv(uniform.location, uniform.num_values, uniform.value);
+               }
+       }
+       for (size_t i = 0; i < phase->uniforms_vec3.size(); ++i) {
+               const Uniform<float> &uniform = phase->uniforms_vec3[i];
+               if (uniform.location != -1) {
+                       glUniform3fv(uniform.location, uniform.num_values, uniform.value);
+               }
+       }
+       for (size_t i = 0; i < phase->uniforms_vec4.size(); ++i) {
+               const Uniform<float> &uniform = phase->uniforms_vec4[i];
+               if (uniform.location != -1) {
+                       glUniform4fv(uniform.location, uniform.num_values, uniform.value);
+               }
+       }
+       for (size_t i = 0; i < phase->uniforms_mat3.size(); ++i) {
+               const Uniform<Matrix3d> &uniform = phase->uniforms_mat3[i];
+               assert(uniform.num_values == 1);
+               if (uniform.location != -1) {
+                       // Convert to float (GLSL has no double matrices).
+                       float matrixf[9];
+                       for (unsigned y = 0; y < 3; ++y) {
+                               for (unsigned x = 0; x < 3; ++x) {
+                                       matrixf[y + x * 3] = (*uniform.value)(y, x);
+                               }
+                       }
+                       glUniformMatrix3fv(uniform.location, 1, GL_FALSE, matrixf);
+               }
+       }
+}
+
 void EffectChain::setup_rtt_sampler(GLuint glsl_program_num, int sampler_num, const string &effect_id, bool use_mipmaps)
 {
        glActiveTexture(GL_TEXTURE0 + sampler_num);
index d1ab0a2..ee4c7ba 100644 (file)
@@ -27,7 +27,9 @@
 #include <set>
 #include <string>
 #include <vector>
+#include <Eigen/Core>
 
+#include "effect.h"
 #include "image_format.h"
 #include "ycbcr.h"
 
@@ -114,6 +116,15 @@ struct Phase {
        // Unique per-phase to increase cacheability of compiled shaders.
        std::map<Node *, std::string> effect_ids;
 
+       // Uniforms for this phase; combined from all the effects.
+       std::vector<Uniform<bool> > uniforms_bool;
+       std::vector<Uniform<int> > uniforms_int;
+       std::vector<Uniform<float> > uniforms_float;
+       std::vector<Uniform<float> > uniforms_vec2;
+       std::vector<Uniform<float> > uniforms_vec3;
+       std::vector<Uniform<float> > uniforms_vec4;
+       std::vector<Uniform<Eigen::Matrix3d> > uniforms_mat3;
+
        // For measurement of GPU time used.
        GLuint timer_query_object;
        uint64_t time_elapsed_ns;
@@ -265,6 +276,9 @@ private:
        // Execute one phase, ie. set up all inputs, effects and outputs, and render the quad.
        void execute_phase(Phase *phase, bool last_phase, std::map<Phase *, GLuint> *output_textures, std::set<Phase *> *generated_mipmaps);
 
+       // Set up uniforms for one phase. The program must already be bound.
+       void setup_uniforms(Phase *phase);
+
        // Set up the given sampler number for sampling from an RTT texture,
        // and bind it to "tex_" plus the given GLSL variable.
        void setup_rtt_sampler(GLuint glsl_program_num, int sampler_num, const std::string &effect_id, bool use_mipmaps);
index a1588ef..1a8f04a 100644 (file)
@@ -20,6 +20,8 @@ class EffectChain;
 class Node;
 
 // Convenience functions that deal with prepending the prefix.
+// Note that using EffectChain::register_uniform_*() is more efficient
+// than calling these from set_gl_state().
 GLint get_uniform_location(GLuint glsl_program_num, const std::string &prefix, const std::string &key);
 void set_uniform_int(GLuint glsl_program_num, const std::string &prefix, const std::string &key, int value);
 void set_uniform_float(GLuint glsl_program_num, const std::string &prefix, const std::string &key, float value);
index c88a7c4..b37d520 100644 (file)
@@ -23,6 +23,7 @@ FFTInput::FFTInput(unsigned width, unsigned height)
 {
        register_int("fft_width", &fft_width);
        register_int("fft_height", &fft_height);
+       register_uniform_sampler2d("tex", &uniform_tex);
 }
 
 FFTInput::~FFTInput()
@@ -98,7 +99,7 @@ void FFTInput::set_gl_state(GLuint glsl_program_num, const string& prefix, unsig
        }
 
        // Bind it to a sampler.
-       set_uniform_int(glsl_program_num, prefix, "tex", *sampler_num);
+       uniform_tex = *sampler_num;
        ++*sampler_num;
 }
 
index a75414c..472a218 100644 (file)
@@ -75,6 +75,7 @@ private:
        unsigned convolve_width, convolve_height;
        const float *pixel_data;
        ResourcePool *resource_pool;
+       GLint uniform_tex;
 };
 
 }  // namespace movit
index 48e2677..434ce22 100644 (file)
@@ -25,6 +25,8 @@ FFTPassEffect::FFTPassEffect()
        register_int("direction", (int *)&direction);
        register_int("pass_number", &pass_number);
        register_int("inverse", &inverse);
+       register_uniform_float("num_repeats", &uniform_num_repeats);
+       register_uniform_sampler2d("support_tex", &uniform_support_tex);
        glGenTextures(1, &tex);
 }
 
@@ -83,11 +85,11 @@ void FFTPassEffect::set_gl_state(GLuint glsl_program_num, const string &prefix,
                generate_support_texture();
        }
 
-       set_uniform_int(glsl_program_num, prefix, "support_tex", *sampler_num);
+       uniform_support_tex = *sampler_num;
        ++*sampler_num;
 
        assert(input_size % fft_size == 0);
-       set_uniform_float(glsl_program_num, prefix, "num_repeats", input_size / fft_size);
+       uniform_num_repeats = input_size / fft_size;
 }
 
 void FFTPassEffect::generate_support_texture()
index eb26f33..9750e8b 100644 (file)
@@ -1,8 +1,9 @@
 // DIRECTION_VERTICAL will be #defined to 1 if we are doing a vertical FFT,
 // and 0 otherwise.
 
-uniform float PREFIX(num_repeats);
-uniform sampler2D PREFIX(support_tex);
+// Implicit uniforms:
+// uniform float PREFIX(num_repeats);
+// uniform sampler2D PREFIX(support_tex);
 
 vec4 FUNCNAME(vec2 tc) {
 #if DIRECTION_VERTICAL
index 561bc6d..53428bd 100644 (file)
@@ -110,6 +110,8 @@ private:
        EffectChain *chain;
        int input_width, input_height;
        GLuint tex;
+       float uniform_num_repeats;
+       GLint uniform_support_tex;
 
        int fft_size;
        Direction direction;
index f6ae827..1795902 100644 (file)
@@ -28,6 +28,7 @@ FlatInput::FlatInput(ImageFormat image_format, MovitPixelFormat pixel_format_in,
        assert(type == GL_FLOAT || type == GL_HALF_FLOAT || type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_BYTE);
        register_int("output_linear_gamma", &output_linear_gamma);
        register_int("needs_mipmaps", &needs_mipmaps);
+       register_uniform_sampler2d("tex", &uniform_tex);
 
        // Some types are not supported in all GL versions (e.g. GLES),
        // and will corrected into the right format in the shader.
@@ -168,7 +169,7 @@ void FlatInput::set_gl_state(GLuint glsl_program_num, const string& prefix, unsi
        }
 
        // Bind it to a sampler.
-       set_uniform_int(glsl_program_num, prefix, "tex", *sampler_num);
+       uniform_tex = *sampler_num;
        ++*sampler_num;
 }
 
index 855d4fb..78d4edd 100644 (file)
@@ -1,4 +1,5 @@
-uniform sampler2D PREFIX(tex);
+// Implicit uniforms:
+// uniform sampler2D PREFIX(tex);
 
 vec4 FUNCNAME(vec2 tc) {
        // OpenGL's origin is bottom-left, but most graphics software assumes
index 25b9091..495a36c 100644 (file)
@@ -127,6 +127,7 @@ private:
        const void *pixel_data;
        ResourcePool *resource_pool;
        bool fixup_swap_rb, fixup_red_to_grayscale;
+       GLint uniform_tex;
 };
 
 }  // namespace movit
index 079f849..b0f6372 100644 (file)
@@ -12,6 +12,13 @@ GammaCompressionEffect::GammaCompressionEffect()
        : destination_curve(GAMMA_LINEAR)
 {
        register_int("destination_curve", (int *)&destination_curve);
+       register_uniform_float("linear_scale", &uniform_linear_scale);
+       register_uniform_float("c0", &uniform_c0);
+       register_uniform_float("c1", &uniform_c1);
+       register_uniform_float("c2", &uniform_c2);
+       register_uniform_float("c3", &uniform_c3);
+       register_uniform_float("c4", &uniform_c4);
+       register_uniform_float("beta", &uniform_beta);
 }
 
 string GammaCompressionEffect::output_fragment_shader()
@@ -73,25 +80,25 @@ void GammaCompressionEffect::set_gl_state(GLuint glsl_program_num, const string
                // β = 0.0031308, ɣ = 1/2.4.
                // maxerror      = 0.000785 = 0.200 * 255
                // error at 1.0  = 0.000078 = 0.020 * 255
-               set_uniform_float(glsl_program_num, prefix, "linear_scale", 12.92);
-               set_uniform_float(glsl_program_num, prefix, "c0", -0.03679675939);
-               set_uniform_float(glsl_program_num, prefix, "c1", 1.443803073);
-               set_uniform_float(glsl_program_num, prefix, "c2", -0.9239780987);
-               set_uniform_float(glsl_program_num, prefix, "c3", 0.8060491596);
-               set_uniform_float(glsl_program_num, prefix, "c4", -0.2891558568);
-               set_uniform_float(glsl_program_num, prefix, "beta", 0.0031308);
+               uniform_linear_scale = 12.92;
+               uniform_c0 = -0.03679675939;
+               uniform_c1 = 1.443803073;
+               uniform_c2 = -0.9239780987;
+               uniform_c3 = 0.8060491596;
+               uniform_c4 = -0.2891558568;
+               uniform_beta = 0.0031308;
        }
        if (destination_curve == GAMMA_REC_709) {  // Also includes Rec. 601, and 10-bit Rec. 2020.
                // Rec. 2020, page 3; ɑ = 1.099, β = 0.018, ɣ = 0.45.
                // maxerror      = 0.000131 = 0.033 * 255 = 0.134 * 1023
                // error at 1.0  = 0.000013 = 0.003 * 255 = 0.013 * 1023
-               set_uniform_float(glsl_program_num, prefix, "linear_scale", 4.5);
-               set_uniform_float(glsl_program_num, prefix, "c0", -0.08541688528);
-               set_uniform_float(glsl_program_num, prefix, "c1", 1.292793370);
-               set_uniform_float(glsl_program_num, prefix, "c2", -0.4070417645);
-               set_uniform_float(glsl_program_num, prefix, "c3", 0.2923891828);
-               set_uniform_float(glsl_program_num, prefix, "c4", -0.09273699351);
-               set_uniform_float(glsl_program_num, prefix, "beta", 0.018);
+               uniform_linear_scale = 4.5;
+               uniform_c0 = -0.08541688528;
+               uniform_c1 = 1.292793370;
+               uniform_c2 = -0.4070417645;
+               uniform_c3 = 0.2923891828;
+               uniform_c4 = -0.09273699351;
+               uniform_beta = 0.018;
        }
        if (destination_curve == GAMMA_REC_2020_12_BIT) {
                // Rec. 2020, page 3; ɑ = 1.0993, β = 0.0181, ɣ = 0.45.
@@ -103,13 +110,13 @@ void GammaCompressionEffect::set_gl_state(GLuint glsl_program_num, const string
                // bit. (Removing the constraint for x=1 will only take this down
                // from 0.553 to 0.501; adding a fifth order can get it down to
                // 0.167, although this assumes working in fp64 and not fp32.)
-               set_uniform_float(glsl_program_num, prefix, "linear_scale", 4.5);
-               set_uniform_float(glsl_program_num, prefix, "c0", -0.08569685663);
-               set_uniform_float(glsl_program_num, prefix, "c1", 1.293000900);
-               set_uniform_float(glsl_program_num, prefix, "c2", -0.4067291321);
-               set_uniform_float(glsl_program_num, prefix, "c3", 0.2919741179);
-               set_uniform_float(glsl_program_num, prefix, "c4", -0.09256205770);
-               set_uniform_float(glsl_program_num, prefix, "beta", 0.0181);
+               uniform_linear_scale = 4.5;
+               uniform_c0 = -0.08569685663;
+               uniform_c1 = 1.293000900;
+               uniform_c2 = -0.4067291321;
+               uniform_c3 = 0.2919741179;
+               uniform_c4 = -0.09256205770;
+               uniform_beta = 0.0181;
        }
 }
 
index e1e786c..2d84f32 100644 (file)
@@ -1,8 +1,9 @@
 // Compress gamma curve.
 
-uniform float PREFIX(linear_scale);
-uniform float PREFIX(c0), PREFIX(c1), PREFIX(c2), PREFIX(c3), PREFIX(c4);
-uniform float PREFIX(beta);
+// Implicit uniforms:
+// uniform float PREFIX(linear_scale);
+// uniform float PREFIX(c0), PREFIX(c1), PREFIX(c2), PREFIX(c3), PREFIX(c4);
+// uniform float PREFIX(beta);
 
 vec4 FUNCNAME(vec2 tc) {
        vec4 x = INPUT(tc);
index 52a8654..08fa194 100644 (file)
@@ -37,6 +37,7 @@ public:
 
 private:
        GammaCurve destination_curve;
+       float uniform_linear_scale, uniform_c0, uniform_c1, uniform_c2, uniform_c3, uniform_c4, uniform_beta;
 };
 
 }  // namespace movit
index 9543790..15e0bff 100644 (file)
@@ -12,6 +12,13 @@ GammaExpansionEffect::GammaExpansionEffect()
        : source_curve(GAMMA_LINEAR)
 {
        register_int("source_curve", (int *)&source_curve);
+       register_uniform_float("linear_scale", &uniform_linear_scale);
+       register_uniform_float("c0", &uniform_c0);
+       register_uniform_float("c1", &uniform_c1);
+       register_uniform_float("c2", &uniform_c2);
+       register_uniform_float("c3", &uniform_c3);
+       register_uniform_float("c4", &uniform_c4);
+       register_uniform_float("beta", &uniform_beta);
 }
 
 string GammaExpansionEffect::output_fragment_shader()
@@ -80,13 +87,13 @@ void GammaExpansionEffect::set_gl_state(GLuint glsl_program_num, const string &p
                //
                // Note that the worst _relative_ error by far is just at the beginning
                // of the exponential curve, ie., just around β.
-               set_uniform_float(glsl_program_num, prefix, "linear_scale", 1.0 / 12.92);
-               set_uniform_float(glsl_program_num, prefix, "c0", 0.001324469581);
-               set_uniform_float(glsl_program_num, prefix, "c1", 0.02227416690);
-               set_uniform_float(glsl_program_num, prefix, "c2", 0.5917615253);
-               set_uniform_float(glsl_program_num, prefix, "c3", 0.4733532353);
-               set_uniform_float(glsl_program_num, prefix, "c4", -0.08880738120);
-               set_uniform_float(glsl_program_num, prefix, "beta", 0.04045);
+               uniform_linear_scale = 1.0 / 12.92;
+               uniform_c0 = 0.001324469581;
+               uniform_c1 = 0.02227416690;
+               uniform_c2 = 0.5917615253;
+               uniform_c3 = 0.4733532353;
+               uniform_c4 = -0.08880738120;
+               uniform_beta = 0.04045;
        }
        if (source_curve == GAMMA_REC_709) {  // Also includes Rec. 601, and 10-bit Rec. 2020.
                // Rec. 2020, page 3; ɑ = 1.099, β = 0.018 * 4.5, ɣ = 1/0.45.
@@ -97,13 +104,13 @@ void GammaExpansionEffect::set_gl_state(GLuint glsl_program_num, const string &p
                // Note that Rec. 2020 only gives the other direction, which is why
                // our beta and gamma are different from the numbers mentioned
                // (we've inverted the formula).
-               set_uniform_float(glsl_program_num, prefix, "linear_scale", 1.0 / 4.5);
-               set_uniform_float(glsl_program_num, prefix, "c0", 0.005137028744);
-               set_uniform_float(glsl_program_num, prefix, "c1", 0.09802596889);
-               set_uniform_float(glsl_program_num, prefix, "c2", 0.7255768864);
-               set_uniform_float(glsl_program_num, prefix, "c3", 0.2135067966);
-               set_uniform_float(glsl_program_num, prefix, "c4", -0.04225094667);
-               set_uniform_float(glsl_program_num, prefix, "beta", 0.018 * 4.5);
+               uniform_linear_scale = 1.0 / 4.5;
+               uniform_c0 = 0.005137028744;
+               uniform_c1 = 0.09802596889;
+               uniform_c2 = 0.7255768864;
+               uniform_c3 = 0.2135067966;
+               uniform_c4 = -0.04225094667;
+               uniform_beta = 0.018 * 4.5;
        }
        if (source_curve == GAMMA_REC_2020_12_BIT) {
                // Rec. 2020, page 3; ɑ = 1.0993, β = 0.0181 * 4.5, ɣ = 1/0.45.
@@ -114,13 +121,13 @@ void GammaExpansionEffect::set_gl_state(GLuint glsl_program_num, const string &p
                // Note that Rec. 2020 only gives the other direction, which is why
                // our beta and gamma are different from the numbers mentioned
                // (we've inverted the formula).
-               set_uniform_float(glsl_program_num, prefix, "linear_scale", 1.0 / 4.5);
-               set_uniform_float(glsl_program_num, prefix, "c0", 0.005167545928);
-               set_uniform_float(glsl_program_num, prefix, "c1", 0.09835585809);
-               set_uniform_float(glsl_program_num, prefix, "c2", 0.7254820139);
-               set_uniform_float(glsl_program_num, prefix, "c3", 0.2131291155);
-               set_uniform_float(glsl_program_num, prefix, "c4", -0.04213877222);
-               set_uniform_float(glsl_program_num, prefix, "beta", 0.0181 * 4.5);
+               uniform_linear_scale = 1.0 / 4.5;
+               uniform_c0 = 0.005167545928;
+               uniform_c1 = 0.09835585809;
+               uniform_c2 = 0.7254820139;
+               uniform_c3 = 0.2131291155;
+               uniform_c4 = -0.04213877222;
+               uniform_beta = 0.0181 * 4.5;
        }
 }
 
index 359b026..051d2fa 100644 (file)
@@ -1,8 +1,9 @@
 // Expand gamma curve.
 
-uniform float PREFIX(linear_scale);
-uniform float PREFIX(c0), PREFIX(c1), PREFIX(c2), PREFIX(c3), PREFIX(c4);
-uniform float PREFIX(beta);
+// Implicit uniforms:
+// uniform float PREFIX(linear_scale);
+// uniform float PREFIX(c0), PREFIX(c1), PREFIX(c2), PREFIX(c3), PREFIX(c4);
+// uniform float PREFIX(beta);
 
 vec4 FUNCNAME(vec2 tc) {
        vec4 x = INPUT(tc);
index 1025695..20a5a76 100644 (file)
@@ -38,6 +38,7 @@ public:
 
 private:
        GammaCurve source_curve;
+       float uniform_linear_scale, uniform_c0, uniform_c1, uniform_c2, uniform_c3, uniform_c4, uniform_beta;
 };
 
 }  // namespace movit
index 60cd7df..ac8ccb6 100644 (file)
@@ -17,6 +17,8 @@ LiftGammaGainEffect::LiftGammaGainEffect()
        register_vec3("lift", (float *)&lift);
        register_vec3("gamma", (float *)&gamma);
        register_vec3("gain", (float *)&gain);
+       register_uniform_vec3("gain_pow_inv_gamma", (float *)&uniform_gain_pow_inv_gamma);
+       register_uniform_vec3("inv_gamma_22", (float *)&uniform_inv_gamma22);
 }
 
 string LiftGammaGainEffect::output_fragment_shader()
@@ -28,17 +30,15 @@ void LiftGammaGainEffect::set_gl_state(GLuint glsl_program_num, const string &pr
 {
        Effect::set_gl_state(glsl_program_num, prefix, sampler_num);
 
-       RGBTriplet gain_pow_inv_gamma(
+       uniform_gain_pow_inv_gamma = RGBTriplet(
                pow(gain.r, 1.0f / gamma.r),
                pow(gain.g, 1.0f / gamma.g),
                pow(gain.b, 1.0f / gamma.b));
-       set_uniform_vec3(glsl_program_num, prefix, "gain_pow_inv_gamma", (float *)&gain_pow_inv_gamma);
 
-       RGBTriplet inv_gamma_22(
+       uniform_inv_gamma22 = RGBTriplet(
                2.2f / gamma.r,
                2.2f / gamma.g,
                2.2f / gamma.b);
-       set_uniform_vec3(glsl_program_num, prefix, "inv_gamma_22", (float *)&inv_gamma_22);
 }
 
 }  // namespace movit
index 9047d64..7342d75 100644 (file)
@@ -1,6 +1,8 @@
+// Implicit uniforms:
+//
 // These are calculated in the host code to save some arithmetic.
-uniform vec3 PREFIX(gain_pow_inv_gamma);  // gain^(1/gamma).
-uniform vec3 PREFIX(inv_gamma_22);  // 2.2 / gamma.
+// uniform vec3 PREFIX(gain_pow_inv_gamma);  // gain^(1/gamma).
+// uniform vec3 PREFIX(inv_gamma_22);  // 2.2 / gamma.
 
 vec4 FUNCNAME(vec2 tc) {
        vec4 x = INPUT(tc);
index 9183c58..7967448 100644 (file)
@@ -39,6 +39,7 @@ public:
 
 private:
        RGBTriplet lift, gamma, gain;
+       RGBTriplet uniform_gain_pow_inv_gamma, uniform_inv_gamma22;
 };
 
 }  // namespace movit
index 92c599e..6d5af73 100644 (file)
@@ -12,6 +12,8 @@ LumaMixEffect::LumaMixEffect()
        register_float("transition_width", &transition_width);
        register_float("progress", &progress);
        register_int("inverse", &inverse);
+       register_uniform_bool("inverse", &uniform_inverse);
+       register_uniform_float("progress_mul_w_plus_one", &uniform_progress_mul_w_plus_one);
 }
 
 string LumaMixEffect::output_fragment_shader()
@@ -22,8 +24,8 @@ string LumaMixEffect::output_fragment_shader()
 void LumaMixEffect::set_gl_state(GLuint glsl_program_num, const string &prefix, unsigned *sampler_num)
 {
        Effect::set_gl_state(glsl_program_num, prefix, sampler_num);
-       set_uniform_float(glsl_program_num, prefix, "progress_mul_w_plus_one", progress * (transition_width + 1.0));
-       set_uniform_int(glsl_program_num, prefix, "inverse", inverse);
+       uniform_progress_mul_w_plus_one = progress * (transition_width + 1.0);
+       uniform_inverse = inverse;
 }
 
 }  // namespace movit
index c8a05c1..e721a88 100644 (file)
@@ -1,5 +1,6 @@
-uniform float PREFIX(progress_mul_w_plus_one);
-uniform bool PREFIX(inverse);
+// Implicit uniforms:
+// uniform float PREFIX(progress_mul_w_plus_one);
+// uniform bool PREFIX(inverse);
 
 vec4 FUNCNAME(vec2 tc) {
        vec4 first = INPUT1(tc);
index c4b2476..3ff81bf 100644 (file)
@@ -32,6 +32,8 @@ public:
 private:
        float transition_width, progress;
        int inverse;  // 0 or 1.
+       bool uniform_inverse;
+       float uniform_progress_mul_w_plus_one;
 };
 
 }  // namespace movit
index 5ca976c..d96d104 100644 (file)
@@ -29,6 +29,11 @@ PaddingEffect::PaddingEffect()
        register_float("border_offset_left", &border_offset_left);
        register_float("border_offset_bottom", &border_offset_bottom);
        register_float("border_offset_right", &border_offset_right);
+       register_uniform_vec2("offset", uniform_offset);
+       register_uniform_vec2("scale", uniform_scale);
+       register_uniform_vec2("normalized_coords_to_texels", uniform_normalized_coords_to_texels);
+       register_uniform_vec2("offset_bottomleft", uniform_offset_bottomleft);
+       register_uniform_vec2("offset_topright", uniform_offset_topright);
 }
 
 string PaddingEffect::output_fragment_shader()
@@ -40,36 +45,23 @@ void PaddingEffect::set_gl_state(GLuint glsl_program_num, const string &prefix,
 {
        Effect::set_gl_state(glsl_program_num, prefix, sampler_num);
 
-       float offset[2] = {
-               left / output_width,
-               (output_height - input_height - top) / output_height
-       };
-       set_uniform_vec2(glsl_program_num, prefix, "offset", offset);
+       uniform_offset[0] = left / output_width;
+       uniform_offset[1] = (output_height - input_height - top) / output_height;
 
-       float scale[2] = {
-               float(output_width) / input_width,
-               float(output_height) / input_height
-       };
-       set_uniform_vec2(glsl_program_num, prefix, "scale", scale);
+       uniform_scale[0] = float(output_width) / input_width;
+       uniform_scale[1] = float(output_height) / input_height;
 
-       float normalized_coords_to_texels[2] = {
-               float(input_width), float(input_height)
-       };
-       set_uniform_vec2(glsl_program_num, prefix, "normalized_coords_to_texels", normalized_coords_to_texels);
+       uniform_normalized_coords_to_texels[0] = float(input_width);
+       uniform_normalized_coords_to_texels[1] = float(input_height);
 
        // Texels -0.5..0.5 should map to light level 0..1 (and then we
        // clamp the rest).
-       float offset_bottomleft[2] = {
-               0.5f - border_offset_left, 0.5f + border_offset_bottom,
-       };
+       uniform_offset_bottomleft[0] = 0.5f - border_offset_left;
+       uniform_offset_bottomleft[1] = 0.5f + border_offset_bottom;
 
        // Texels size-0.5..size+0.5 should map to light level 1..0 (and then clamp).
-       float offset_topright[2] = {
-               input_width + 0.5f + border_offset_right, input_height + 0.5f - border_offset_top,
-       };
-
-       set_uniform_vec2(glsl_program_num, prefix, "offset_bottomleft", offset_bottomleft);
-       set_uniform_vec2(glsl_program_num, prefix, "offset_topright", offset_topright);
+       uniform_offset_topright[0] = input_width + 0.5f + border_offset_right;
+       uniform_offset_topright[1] = input_height + 0.5f - border_offset_top;
 }
        
 // We don't change the pixels of the image itself, so the only thing that 
index 32ae840..80b9633 100644 (file)
@@ -1,9 +1,10 @@
-uniform vec2 PREFIX(offset);
-uniform vec2 PREFIX(scale);
-
-uniform vec2 PREFIX(normalized_coords_to_texels);
-uniform vec2 PREFIX(offset_bottomleft);
-uniform vec2 PREFIX(offset_topright);
+// Implicit uniforms:
+// uniform vec2 PREFIX(offset);
+// uniform vec2 PREFIX(scale);
+//
+// uniform vec2 PREFIX(normalized_coords_to_texels);
+// uniform vec2 PREFIX(offset_bottomleft);
+// uniform vec2 PREFIX(offset_topright);
 
 vec4 FUNCNAME(vec2 tc) {
        tc -= PREFIX(offset);
index 16ed179..d922944 100644 (file)
@@ -56,6 +56,9 @@ private:
        float top, left;
        float border_offset_top, border_offset_left;
        float border_offset_bottom, border_offset_right;
+       float uniform_offset[2], uniform_scale[2];
+       float uniform_normalized_coords_to_texels[2];
+       float uniform_offset_bottomleft[2], uniform_offset_topright[2];
 };
 
 class IntegralPaddingEffect : public PaddingEffect {
index 0ec611a..4dd3ea8 100644 (file)
@@ -390,6 +390,13 @@ SingleResamplePassEffect::SingleResamplePassEffect(ResampleEffect *parent)
        register_int("output_height", &output_height);
        register_float("offset", &offset);
        register_float("zoom", &zoom);
+       register_uniform_sampler2d("sample_tex", &uniform_sample_tex);
+       register_uniform_int("num_samples", &uniform_num_samples);  // FIXME: What about GLSL pre-1.30?
+       register_uniform_float("num_loops", &uniform_num_loops);
+       register_uniform_float("slice_height", &uniform_slice_height);
+       register_uniform_float("sample_x_scale", &uniform_sample_x_scale);
+       register_uniform_float("sample_x_offset", &uniform_sample_x_offset);
+       register_uniform_float("whole_pixel_offset", &uniform_whole_pixel_offset);
 
        glGenTextures(1, &texnum);
 }
@@ -625,23 +632,21 @@ void SingleResamplePassEffect::set_gl_state(GLuint glsl_program_num, const strin
        glBindTexture(GL_TEXTURE_2D, texnum);
        check_error();
 
-       set_uniform_int(glsl_program_num, prefix, "sample_tex", *sampler_num);
+       uniform_sample_tex = *sampler_num;
        ++*sampler_num;
-       set_uniform_int(glsl_program_num, prefix, "num_samples", src_bilinear_samples);
-       set_uniform_float(glsl_program_num, prefix, "num_loops", num_loops);
-       set_uniform_float(glsl_program_num, prefix, "slice_height", slice_height);
+       uniform_num_samples = src_bilinear_samples;
+       uniform_num_loops = num_loops;
+       uniform_slice_height = slice_height;
 
        // Instructions for how to convert integer sample numbers to positions in the weight texture.
-       set_uniform_float(glsl_program_num, prefix, "sample_x_scale", 1.0f / src_bilinear_samples);
-       set_uniform_float(glsl_program_num, prefix, "sample_x_offset", 0.5f / src_bilinear_samples);
+       uniform_sample_x_scale = 1.0f / src_bilinear_samples;
+       uniform_sample_x_offset = 0.5f / src_bilinear_samples;
 
-       float whole_pixel_offset;
        if (direction == SingleResamplePassEffect::VERTICAL) {
-               whole_pixel_offset = lrintf(offset) / float(input_height);
+               uniform_whole_pixel_offset = lrintf(offset) / float(input_height);
        } else {
-               whole_pixel_offset = lrintf(offset) / float(input_width);
+               uniform_whole_pixel_offset = lrintf(offset) / float(input_width);
        }
-       set_uniform_float(glsl_program_num, prefix, "whole_pixel_offset", whole_pixel_offset);
 
        // We specifically do not want mipmaps on the input texture;
        // they break minification.
index f54a8be..015bc98 100644 (file)
@@ -1,12 +1,13 @@
 // DIRECTION_VERTICAL will be #defined to 1 if we are scaling vertically,
 // and 0 otherwise.
 
-uniform sampler2D PREFIX(sample_tex);
-uniform int PREFIX(num_samples);
-uniform float PREFIX(num_loops);
-uniform float PREFIX(sample_x_scale);
-uniform float PREFIX(sample_x_offset);
-uniform float PREFIX(slice_height);
+// Implicit uniforms:
+// uniform sampler2D PREFIX(sample_tex);
+// uniform int PREFIX(num_samples);
+// uniform float PREFIX(num_loops);
+// uniform float PREFIX(sample_x_scale);
+// uniform float PREFIX(sample_x_offset);
+// uniform float PREFIX(slice_height);
 
 // We put the fractional part of the offset (-0.5 to 0.5 pixels) in the weights
 // because we have to (otherwise they'd do nothing). However, the support texture
@@ -24,7 +25,9 @@ uniform float PREFIX(slice_height);
 // measured in _input_ pixels and tc is in _output_ pixels, although we could
 // compensate for that.) However, the shader should be mostly bandwidth bound
 // and not ALU bound, so an extra add per sample shouldn't be too hopeless.
-uniform float PREFIX(whole_pixel_offset);
+//
+// Implicitly declared:
+// uniform float PREFIX(whole_pixel_offset);
 
 // Sample a single weight. First fetch information about where to sample
 // and the weight from sample_tex, and then read the pixel itself.
index 73dfc21..b06b09b 100644 (file)
@@ -103,6 +103,11 @@ private:
        EffectChain *chain;
        Direction direction;
        GLuint texnum;
+       GLint uniform_sample_tex;
+       float uniform_num_loops, uniform_slice_height, uniform_sample_x_scale, uniform_sample_x_offset;
+       float uniform_whole_pixel_offset;
+       int uniform_num_samples;
+
        int input_width, input_height, output_width, output_height;
        float offset, zoom;
        int last_input_width, last_input_height, last_output_width, last_output_height;
index 50504fe..66fed51 100644 (file)
@@ -19,6 +19,10 @@ SliceEffect::SliceEffect()
        register_int("output_slice_size", &output_slice_size);
        register_int("offset", &offset);
        register_int("direction", (int *)&direction);
+       register_uniform_float("output_coord_to_slice_num", &uniform_output_coord_to_slice_num);
+       register_uniform_float("slice_num_to_input_coord", &uniform_slice_num_to_input_coord);
+       register_uniform_float("slice_offset_to_input_coord", &uniform_slice_offset_to_input_coord);
+       register_uniform_float("offset", &uniform_offset);
 }
 
 string SliceEffect::output_fragment_shader()
@@ -57,15 +61,15 @@ void SliceEffect::set_gl_state(GLuint glsl_program_num, const string &prefix, un
        get_output_size(&output_width, &output_height, &output_width, &output_height);
 
        if (direction == HORIZONTAL) {
-               set_uniform_float(glsl_program_num, prefix, "output_coord_to_slice_num", float(output_width) / float(output_slice_size));
-               set_uniform_float(glsl_program_num, prefix, "slice_num_to_input_coord", float(input_slice_size) / float(input_width));
-               set_uniform_float(glsl_program_num, prefix, "slice_offset_to_input_coord", float(output_slice_size) / float(input_width));
-               set_uniform_float(glsl_program_num, prefix, "offset", float(offset) / float(input_width));
+               uniform_output_coord_to_slice_num = float(output_width) / float(output_slice_size);
+               uniform_slice_num_to_input_coord = float(input_slice_size) / float(input_width);
+               uniform_slice_offset_to_input_coord = float(output_slice_size) / float(input_width);
+               uniform_offset = float(offset) / float(input_width);
        } else {
-               set_uniform_float(glsl_program_num, prefix, "output_coord_to_slice_num", float(output_height) / float(output_slice_size));
-               set_uniform_float(glsl_program_num, prefix, "slice_num_to_input_coord", float(input_slice_size) / float(input_height));
-               set_uniform_float(glsl_program_num, prefix, "slice_offset_to_input_coord", float(output_slice_size) / float(input_height));
-               set_uniform_float(glsl_program_num, prefix, "offset", float(offset) / float(input_height));
+               uniform_output_coord_to_slice_num = float(output_height) / float(output_slice_size);
+               uniform_slice_num_to_input_coord = float(input_slice_size) / float(input_height);
+               uniform_slice_offset_to_input_coord = float(output_slice_size) / float(input_height);
+               uniform_offset = float(offset) / float(input_height);
        }
 
        // Normalized coordinates could potentially cause blurring of the image.
index e77c9fa..e9c2c37 100644 (file)
@@ -1,7 +1,8 @@
-uniform float PREFIX(output_coord_to_slice_num);
-uniform float PREFIX(slice_num_to_input_coord);
-uniform float PREFIX(slice_offset_to_input_coord);
-uniform float PREFIX(offset);
+// Implicit uniforms:
+// uniform float PREFIX(output_coord_to_slice_num);
+// uniform float PREFIX(slice_num_to_input_coord);
+// uniform float PREFIX(slice_offset_to_input_coord);
+// uniform float PREFIX(offset);
  
 vec4 FUNCNAME(vec2 tc) {
        // DIRECTION_VERTICAL will be #defined to 1 if we are expanding vertically,
index ccca527..ef96ddd 100644 (file)
@@ -40,6 +40,9 @@ private:
        int input_slice_size, output_slice_size;
        int offset;
        Direction direction;
+
+       float uniform_output_coord_to_slice_num, uniform_slice_num_to_input_coord;
+       float uniform_slice_offset_to_input_coord, uniform_offset;
 };
 
 }  // namespace movit
index a4b3683..616c4be 100644 (file)
--- a/version.h
+++ b/version.h
@@ -5,6 +5,6 @@
 // changes, even within git versions. There is no specific version
 // documentation outside the regular changelogs, though.
 
-#define MOVIT_VERSION 1
+#define MOVIT_VERSION 2
 
 #endif // !defined(_MOVIT_VERSION_H)
index d8b4f9b..088406b 100644 (file)
@@ -12,13 +12,17 @@ namespace movit {
 
 VignetteEffect::VignetteEffect()
        : center(0.5f, 0.5f),
-         aspect_correction(1.0f, 1.0f),
+         uniform_aspect_correction(1.0f, 1.0f),
+         uniform_flipped_center(0.5f, 0.5f),
          radius(0.3f),
          inner_radius(0.3f)
 {
        register_vec2("center", (float *)&center);
        register_float("radius", (float *)&radius);
        register_float("inner_radius", (float *)&inner_radius);
+       register_uniform_float("pihalf_div_radius", &uniform_pihalf_div_radius);
+       register_uniform_vec2("aspect_correction", (float *)&uniform_aspect_correction);
+       register_uniform_vec2("flipped_center", (float *)&uniform_flipped_center);
 }
 
 string VignetteEffect::output_fragment_shader()
@@ -29,9 +33,9 @@ string VignetteEffect::output_fragment_shader()
 void VignetteEffect::inform_input_size(unsigned input_num, unsigned width, unsigned height) {
        assert(input_num == 0);
        if (width >= height) {
-               aspect_correction = Point2D(float(width) / float(height), 1.0f);
+               uniform_aspect_correction = Point2D(float(width) / float(height), 1.0f);
        } else {
-               aspect_correction = Point2D(1.0f, float(height) / float(width));
+               uniform_aspect_correction = Point2D(1.0f, float(height) / float(width));
        }
 }
 
@@ -39,11 +43,8 @@ void VignetteEffect::set_gl_state(GLuint glsl_program_num, const string &prefix,
 {
        Effect::set_gl_state(glsl_program_num, prefix, sampler_num);
 
-       set_uniform_float(glsl_program_num, prefix, "pihalf_div_radius", 0.5 * M_PI / radius);
-       set_uniform_vec2(glsl_program_num, prefix, "aspect_correction", (float *)&aspect_correction);
-
-       Point2D flipped_center(center.x, 1.0f - center.y);
-       set_uniform_vec2(glsl_program_num, prefix, "flipped_center", (float *)&flipped_center);
+       uniform_pihalf_div_radius = 0.5 * M_PI / radius;
+       uniform_flipped_center = Point2D(center.x, 1.0f - center.y);
 }
 
 }  // namespace movit
index 60d4b33..e8d185f 100644 (file)
@@ -1,8 +1,10 @@
 // A simple, circular vignette, with a cos² falloff.
-       
-uniform float PREFIX(pihalf_div_radius);
-uniform vec2 PREFIX(aspect_correction);
-uniform vec2 PREFIX(flipped_center);
+
+// Implicit uniforms:
+// uniform float PREFIX(pihalf_div_radius);
+//
+// uniform vec2 PREFIX(aspect_correction);
+// uniform vec2 PREFIX(flipped_center);
 
 vec4 FUNCNAME(vec2 tc) {
        vec4 x = INPUT(tc);
index 582e676..926a5be 100644 (file)
@@ -25,8 +25,10 @@ public:
        void set_gl_state(GLuint glsl_program_num, const std::string &prefix, unsigned *sampler_num);
 
 private:
-       Point2D center, aspect_correction;
+       Point2D center;
+       Point2D uniform_aspect_correction, uniform_flipped_center;
        float radius, inner_radius;
+       float uniform_pihalf_div_radius;
 };
 
 }  // namespace movit
index 69759ad..07c95ca 100644 (file)
@@ -105,6 +105,7 @@ WhiteBalanceEffect::WhiteBalanceEffect()
 {
        register_vec3("neutral_color", (float *)&neutral_color);
        register_float("output_color_temperature", &output_color_temperature);
+       register_uniform_mat3("correction_matrix", &uniform_correction_matrix);
 }
 
 string WhiteBalanceEffect::output_fragment_shader()
@@ -142,13 +143,12 @@ void WhiteBalanceEffect::set_gl_state(GLuint glsl_program_num, const string &pre
         * Note that since we postmultiply our vectors, the order of the matrices
         * has to be the opposite of the execution order.
         */
-       Matrix3d corr_matrix =
+       uniform_correction_matrix =
                rgb_to_xyz_matrix.inverse() *
                Map<const Matrix3d>(xyz_to_lms_matrix).inverse() *
                lms_scale.asDiagonal() *
                Map<const Matrix3d>(xyz_to_lms_matrix) *
                rgb_to_xyz_matrix;
-       set_uniform_mat3(glsl_program_num, prefix, "correction_matrix", corr_matrix);
 }
 
 }  // namespace movit
index 926e0de..2d196a4 100644 (file)
@@ -1,4 +1,5 @@
-uniform mat3 PREFIX(correction_matrix);
+// Implicit uniforms:
+// uniform mat3 PREFIX(correction_matrix);
 
 vec4 FUNCNAME(vec2 tc) {
        vec4 ret = INPUT(tc);
index 342426b..2370847 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <epoxy/gl.h>
 #include <string>
+#include <Eigen/Core>
 
 #include "effect.h"
 
@@ -27,6 +28,8 @@ private:
        // Output color temperature (in Kelvins).
        // Choosing 6500 will lead to no color cast (ie., the neutral color becomes perfectly gray).
        float output_color_temperature;
+
+       Eigen::Matrix3d uniform_correction_matrix;
 };
 
 }  // namespace movit
index b634289..c345f8d 100644 (file)
@@ -36,6 +36,9 @@ YCbCr422InterleavedInput::YCbCr422InterleavedInput(const ImageFormat &image_form
        pitches[CHANNEL_CHROMA] = width / ycbcr_format.chroma_subsampling_x;
 
        pixel_data = NULL;
+
+       register_uniform_sampler2d("tex_y", &uniform_tex_y);
+       register_uniform_sampler2d("tex_cbcr", &uniform_tex_cbcr);
 }
 
 YCbCr422InterleavedInput::~YCbCr422InterleavedInput()
@@ -94,8 +97,8 @@ void YCbCr422InterleavedInput::set_gl_state(GLuint glsl_program_num, const strin
        check_error();
 
        // Bind samplers.
-       set_uniform_int(glsl_program_num, prefix, "tex_y", *sampler_num + 0);
-       set_uniform_int(glsl_program_num, prefix, "tex_cbcr", *sampler_num + 1);
+       uniform_tex_y = *sampler_num + 0;
+       uniform_tex_cbcr = *sampler_num + 1;
 
        *sampler_num += 2;
 }
index 66762a8..96b93f8 100644 (file)
@@ -1,5 +1,6 @@
-uniform sampler2D PREFIX(tex_y);
-uniform sampler2D PREFIX(tex_cbcr);
+// Implicit uniforms:
+// uniform sampler2D PREFIX(tex_y);
+// uniform sampler2D PREFIX(tex_cbcr);
 
 vec4 FUNCNAME(vec2 tc) {
        // OpenGL's origin is bottom-left, but most graphics software assumes
index b346986..b7000a0 100644 (file)
@@ -123,6 +123,8 @@ private:
        unsigned width, height;
        const unsigned char *pixel_data;
        ResourcePool *resource_pool;
+
+       GLint uniform_tex_y, uniform_tex_cbcr;
 };
 
 }  // namespace movit
index 091880f..ed1f569 100644 (file)
@@ -39,6 +39,10 @@ YCbCrInput::YCbCrInput(const ImageFormat &image_format,
        heights[2] = height / ycbcr_format.chroma_subsampling_y;
 
        pixel_data[0] = pixel_data[1] = pixel_data[2] = NULL;
+
+       register_uniform_sampler2d("tex_y", &uniform_tex_y);
+       register_uniform_sampler2d("tex_cb", &uniform_tex_cb);
+       register_uniform_sampler2d("tex_cr", &uniform_tex_cr);
 }
 
 YCbCrInput::~YCbCrInput()
@@ -87,9 +91,9 @@ void YCbCrInput::set_gl_state(GLuint glsl_program_num, const string& prefix, uns
        check_error();
 
        // Bind samplers.
-       set_uniform_int(glsl_program_num, prefix, "tex_y", *sampler_num + 0);
-       set_uniform_int(glsl_program_num, prefix, "tex_cb", *sampler_num + 1);
-       set_uniform_int(glsl_program_num, prefix, "tex_cr", *sampler_num + 2);
+       uniform_tex_y = *sampler_num + 0;
+       uniform_tex_cb = *sampler_num + 1;
+       uniform_tex_cr = *sampler_num + 2;
 
        *sampler_num += 3;
 }
index bd6ff76..b84499d 100644 (file)
@@ -1,6 +1,7 @@
-uniform sampler2D PREFIX(tex_y);
-uniform sampler2D PREFIX(tex_cb);
-uniform sampler2D PREFIX(tex_cr);
+// Implicit uniforms:
+// uniform sampler2D PREFIX(tex_y);
+// uniform sampler2D PREFIX(tex_cb);
+// uniform sampler2D PREFIX(tex_cr);
 
 vec4 FUNCNAME(vec2 tc) {
        // OpenGL's origin is bottom-left, but most graphics software assumes
index 97ad526..7db5375 100644 (file)
@@ -79,6 +79,7 @@ private:
        ImageFormat image_format;
        YCbCrFormat ycbcr_format;
        GLuint pbos[3], texture_num[3];
+       GLint uniform_tex_y, uniform_tex_cb, uniform_tex_cr;
 
        unsigned width, height, widths[3], heights[3];
        const unsigned char *pixel_data[3];