From 9c12e38b7cd88a77ef297d080b7c41e6bd6326fb Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sun, 13 Sep 2015 17:44:58 +0200 Subject: [PATCH] Rework uniform setting. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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. --- blur_effect.cpp | 24 ++-- blur_effect.frag | 3 +- blur_effect.h | 2 + complex_modulate_effect.cpp | 5 +- complex_modulate_effect.frag | 3 +- complex_modulate_effect.h | 1 + deconvolution_sharpen_effect.cpp | 22 ++-- deconvolution_sharpen_effect.frag | 3 +- deconvolution_sharpen_effect.h | 3 + dither_effect.cpp | 14 ++- dither_effect.frag | 7 +- dither_effect.h | 3 + effect.cpp | 157 ++++++++++++++++--------- effect.h | 65 ++++++++++- effect_chain.cpp | 183 +++++++++++++++++++++++++++++- effect_chain.h | 14 +++ effect_util.h | 2 + fft_input.cpp | 3 +- fft_input.h | 1 + fft_pass_effect.cpp | 6 +- fft_pass_effect.frag | 5 +- fft_pass_effect.h | 2 + flat_input.cpp | 3 +- flat_input.frag | 3 +- flat_input.h | 1 + gamma_compression_effect.cpp | 49 ++++---- gamma_compression_effect.frag | 7 +- gamma_compression_effect.h | 1 + gamma_expansion_effect.cpp | 49 ++++---- gamma_expansion_effect.frag | 7 +- gamma_expansion_effect.h | 1 + lift_gamma_gain_effect.cpp | 8 +- lift_gamma_gain_effect.frag | 6 +- lift_gamma_gain_effect.h | 1 + luma_mix_effect.cpp | 6 +- luma_mix_effect.frag | 5 +- luma_mix_effect.h | 2 + padding_effect.cpp | 38 +++---- padding_effect.frag | 13 ++- padding_effect.h | 3 + resample_effect.cpp | 25 ++-- resample_effect.frag | 17 +-- resample_effect.h | 5 + slice_effect.cpp | 20 ++-- slice_effect.frag | 9 +- slice_effect.h | 3 + version.h | 2 +- vignette_effect.cpp | 17 +-- vignette_effect.frag | 10 +- vignette_effect.h | 4 +- white_balance_effect.cpp | 4 +- white_balance_effect.frag | 3 +- white_balance_effect.h | 3 + ycbcr_422interleaved_input.cpp | 7 +- ycbcr_422interleaved_input.frag | 5 +- ycbcr_422interleaved_input.h | 2 + ycbcr_input.cpp | 10 +- ycbcr_input.frag | 7 +- ycbcr_input.h | 1 + 59 files changed, 641 insertions(+), 244 deletions(-) diff --git a/blur_effect.cpp b/blur_effect.cpp index 29e46b0..2084768 100644 --- a/blur_effect.cpp +++ b/blur_effect.cpp @@ -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() diff --git a/blur_effect.frag b/blur_effect.frag index 8a7a4a6..f8497b3 100644 --- a/blur_effect.frag +++ b/blur_effect.frag @@ -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); diff --git a/blur_effect.h b/blur_effect.h index eb35790..8ad3da9 100644 --- a/blur_effect.h +++ b/blur_effect.h @@ -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 diff --git a/complex_modulate_effect.cpp b/complex_modulate_effect.cpp index 9483f6b..6b50823 100644 --- a/complex_modulate_effect.cpp +++ b/complex_modulate_effect.cpp @@ -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); diff --git a/complex_modulate_effect.frag b/complex_modulate_effect.frag index 46de5da..d07a729 100644 --- a/complex_modulate_effect.frag +++ b/complex_modulate_effect.frag @@ -1,4 +1,5 @@ -uniform vec2 PREFIX(num_repeats); +// Implicit uniforms: +// uniform vec2 PREFIX(num_repeats); vec4 FUNCNAME(vec2 tc) { vec4 pixel = INPUT1(tc); diff --git a/complex_modulate_effect.h b/complex_modulate_effect.h index e2bf50d..335c900 100644 --- a/complex_modulate_effect.h +++ b/complex_modulate_effect.h @@ -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 diff --git a/deconvolution_sharpen_effect.cpp b/deconvolution_sharpen_effect.cpp index c4ad5cd..2db15dc 100644 --- a/deconvolution_sharpen_effect.cpp +++ b/deconvolution_sharpen_effect.cpp @@ -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 diff --git a/deconvolution_sharpen_effect.frag b/deconvolution_sharpen_effect.frag index 75f249a..e9c560d 100644 --- a/deconvolution_sharpen_effect.frag +++ b/deconvolution_sharpen_effect.frag @@ -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: diff --git a/deconvolution_sharpen_effect.h b/deconvolution_sharpen_effect.h index 1f68071..c2ccbcb 100644 --- a/deconvolution_sharpen_effect.h +++ b/deconvolution_sharpen_effect.h @@ -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(); }; diff --git a/dither_effect.cpp b/dither_effect.cpp index 41ea9b4..574d70a 100644 --- a/dither_effect.cpp +++ b/dither_effect.cpp @@ -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 diff --git a/dither_effect.frag b/dither_effect.frag index 3b6b892..b12ecd7 100644 --- a/dither_effect.frag +++ b/dither_effect.frag @@ -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); diff --git a/dither_effect.h b/dither_effect.h index e580586..921a1ef 100644 --- a/dither_effect.h +++ b/dither_effect.h @@ -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 diff --git a/effect.cpp b/effect.cpp index fb66514..df73eea 100644 --- a/effect.cpp +++ b/effect.cpp @@ -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::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::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::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::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 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::const_iterator it = params_float.begin(); - it != params_float.end(); - ++it) { - set_uniform_float(glsl_program_num, prefix, it->first, *it->second); - } - for (map::const_iterator it = params_vec2.begin(); - it != params_vec2.end(); - ++it) { - set_uniform_vec2(glsl_program_num, prefix, it->first, it->second); - } - for (map::const_iterator it = params_vec3.begin(); - it != params_vec3.end(); - ++it) { - set_uniform_vec3(glsl_program_num, prefix, it->first, it->second); - } - for (map::const_iterator it = params_vec4.begin(); - it != params_vec4.end(); - ++it) { - set_uniform_vec4(glsl_program_num, prefix, it->first, it->second); - } + Uniform 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 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 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 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 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 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 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 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 uniform; + uniform.name = key; + uniform.value = matrix; + uniform.num_values = 1; + uniform.location = -1; + uniforms_mat3.push_back(uniform); +} } // namespace movit diff --git a/effect.h b/effect.h index 56c34d9..9d81a56 100644 --- a/effect.h +++ b/effect.h @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include "defs.h" @@ -50,6 +52,16 @@ struct RGBATuple { float r, g, b, a; }; +// Represents a registered uniform. +template +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 params_int; std::map params_float; std::map params_vec2; std::map params_vec3; std::map params_vec4; + + // Picked out by EffectChain during finalization. + std::vector > uniforms_bool; + std::vector > uniforms_int; + std::vector > uniforms_sampler2d; + std::vector > uniforms_float; + std::vector > uniforms_vec2; + std::vector > uniforms_vec3; + std::vector > uniforms_vec4; + std::vector > uniforms_vec2_array; + std::vector > uniforms_vec4_array; + std::vector > uniforms_mat3; + friend class EffectChain; }; } // namespace movit diff --git a/effect_chain.cpp b/effect_chain.cpp index e1ae832..6e297df 100644 --- a/effect_chain.cpp +++ b/effect_chain.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #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 &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 &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 &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 &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 &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 &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 &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, mapuniforms_bool.size(); ++i) { + const Uniform &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 &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 &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 &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 &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 &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 &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); diff --git a/effect_chain.h b/effect_chain.h index d1ab0a2..ee4c7ba 100644 --- a/effect_chain.h +++ b/effect_chain.h @@ -27,7 +27,9 @@ #include #include #include +#include +#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 effect_ids; + // Uniforms for this phase; combined from all the effects. + std::vector > uniforms_bool; + std::vector > uniforms_int; + std::vector > uniforms_float; + std::vector > uniforms_vec2; + std::vector > uniforms_vec3; + std::vector > uniforms_vec4; + std::vector > 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 *output_textures, std::set *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); diff --git a/effect_util.h b/effect_util.h index a1588ef..1a8f04a 100644 --- a/effect_util.h +++ b/effect_util.h @@ -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); diff --git a/fft_input.cpp b/fft_input.cpp index c88a7c4..b37d520 100644 --- a/fft_input.cpp +++ b/fft_input.cpp @@ -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; } diff --git a/fft_input.h b/fft_input.h index a75414c..472a218 100644 --- a/fft_input.h +++ b/fft_input.h @@ -75,6 +75,7 @@ private: unsigned convolve_width, convolve_height; const float *pixel_data; ResourcePool *resource_pool; + GLint uniform_tex; }; } // namespace movit diff --git a/fft_pass_effect.cpp b/fft_pass_effect.cpp index 48e2677..434ce22 100644 --- a/fft_pass_effect.cpp +++ b/fft_pass_effect.cpp @@ -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() diff --git a/fft_pass_effect.frag b/fft_pass_effect.frag index eb26f33..9750e8b 100644 --- a/fft_pass_effect.frag +++ b/fft_pass_effect.frag @@ -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 diff --git a/fft_pass_effect.h b/fft_pass_effect.h index 561bc6d..53428bd 100644 --- a/fft_pass_effect.h +++ b/fft_pass_effect.h @@ -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; diff --git a/flat_input.cpp b/flat_input.cpp index f6ae827..1795902 100644 --- a/flat_input.cpp +++ b/flat_input.cpp @@ -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; } diff --git a/flat_input.frag b/flat_input.frag index 855d4fb..78d4edd 100644 --- a/flat_input.frag +++ b/flat_input.frag @@ -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 diff --git a/flat_input.h b/flat_input.h index 25b9091..495a36c 100644 --- a/flat_input.h +++ b/flat_input.h @@ -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 diff --git a/gamma_compression_effect.cpp b/gamma_compression_effect.cpp index 079f849..b0f6372 100644 --- a/gamma_compression_effect.cpp +++ b/gamma_compression_effect.cpp @@ -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; } } diff --git a/gamma_compression_effect.frag b/gamma_compression_effect.frag index e1e786c..2d84f32 100644 --- a/gamma_compression_effect.frag +++ b/gamma_compression_effect.frag @@ -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); diff --git a/gamma_compression_effect.h b/gamma_compression_effect.h index 52a8654..08fa194 100644 --- a/gamma_compression_effect.h +++ b/gamma_compression_effect.h @@ -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 diff --git a/gamma_expansion_effect.cpp b/gamma_expansion_effect.cpp index 9543790..15e0bff 100644 --- a/gamma_expansion_effect.cpp +++ b/gamma_expansion_effect.cpp @@ -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; } } diff --git a/gamma_expansion_effect.frag b/gamma_expansion_effect.frag index 359b026..051d2fa 100644 --- a/gamma_expansion_effect.frag +++ b/gamma_expansion_effect.frag @@ -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); diff --git a/gamma_expansion_effect.h b/gamma_expansion_effect.h index 1025695..20a5a76 100644 --- a/gamma_expansion_effect.h +++ b/gamma_expansion_effect.h @@ -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 diff --git a/lift_gamma_gain_effect.cpp b/lift_gamma_gain_effect.cpp index 60cd7df..ac8ccb6 100644 --- a/lift_gamma_gain_effect.cpp +++ b/lift_gamma_gain_effect.cpp @@ -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 diff --git a/lift_gamma_gain_effect.frag b/lift_gamma_gain_effect.frag index 9047d64..7342d75 100644 --- a/lift_gamma_gain_effect.frag +++ b/lift_gamma_gain_effect.frag @@ -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); diff --git a/lift_gamma_gain_effect.h b/lift_gamma_gain_effect.h index 9183c58..7967448 100644 --- a/lift_gamma_gain_effect.h +++ b/lift_gamma_gain_effect.h @@ -39,6 +39,7 @@ public: private: RGBTriplet lift, gamma, gain; + RGBTriplet uniform_gain_pow_inv_gamma, uniform_inv_gamma22; }; } // namespace movit diff --git a/luma_mix_effect.cpp b/luma_mix_effect.cpp index 92c599e..6d5af73 100644 --- a/luma_mix_effect.cpp +++ b/luma_mix_effect.cpp @@ -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 diff --git a/luma_mix_effect.frag b/luma_mix_effect.frag index c8a05c1..e721a88 100644 --- a/luma_mix_effect.frag +++ b/luma_mix_effect.frag @@ -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); diff --git a/luma_mix_effect.h b/luma_mix_effect.h index c4b2476..3ff81bf 100644 --- a/luma_mix_effect.h +++ b/luma_mix_effect.h @@ -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 diff --git a/padding_effect.cpp b/padding_effect.cpp index 5ca976c..d96d104 100644 --- a/padding_effect.cpp +++ b/padding_effect.cpp @@ -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 diff --git a/padding_effect.frag b/padding_effect.frag index 32ae840..80b9633 100644 --- a/padding_effect.frag +++ b/padding_effect.frag @@ -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); diff --git a/padding_effect.h b/padding_effect.h index 16ed179..d922944 100644 --- a/padding_effect.h +++ b/padding_effect.h @@ -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 { diff --git a/resample_effect.cpp b/resample_effect.cpp index 0ec611a..4dd3ea8 100644 --- a/resample_effect.cpp +++ b/resample_effect.cpp @@ -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. diff --git a/resample_effect.frag b/resample_effect.frag index f54a8be..015bc98 100644 --- a/resample_effect.frag +++ b/resample_effect.frag @@ -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. diff --git a/resample_effect.h b/resample_effect.h index 73dfc21..b06b09b 100644 --- a/resample_effect.h +++ b/resample_effect.h @@ -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; diff --git a/slice_effect.cpp b/slice_effect.cpp index 50504fe..66fed51 100644 --- a/slice_effect.cpp +++ b/slice_effect.cpp @@ -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. diff --git a/slice_effect.frag b/slice_effect.frag index e77c9fa..e9c2c37 100644 --- a/slice_effect.frag +++ b/slice_effect.frag @@ -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, diff --git a/slice_effect.h b/slice_effect.h index ccca527..ef96ddd 100644 --- a/slice_effect.h +++ b/slice_effect.h @@ -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 diff --git a/version.h b/version.h index a4b3683..616c4be 100644 --- 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) diff --git a/vignette_effect.cpp b/vignette_effect.cpp index d8b4f9b..088406b 100644 --- a/vignette_effect.cpp +++ b/vignette_effect.cpp @@ -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 *)¢er); 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 diff --git a/vignette_effect.frag b/vignette_effect.frag index 60d4b33..e8d185f 100644 --- a/vignette_effect.frag +++ b/vignette_effect.frag @@ -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); diff --git a/vignette_effect.h b/vignette_effect.h index 582e676..926a5be 100644 --- a/vignette_effect.h +++ b/vignette_effect.h @@ -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 diff --git a/white_balance_effect.cpp b/white_balance_effect.cpp index 69759ad..07c95ca 100644 --- a/white_balance_effect.cpp +++ b/white_balance_effect.cpp @@ -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(xyz_to_lms_matrix).inverse() * lms_scale.asDiagonal() * Map(xyz_to_lms_matrix) * rgb_to_xyz_matrix; - set_uniform_mat3(glsl_program_num, prefix, "correction_matrix", corr_matrix); } } // namespace movit diff --git a/white_balance_effect.frag b/white_balance_effect.frag index 926e0de..2d196a4 100644 --- a/white_balance_effect.frag +++ b/white_balance_effect.frag @@ -1,4 +1,5 @@ -uniform mat3 PREFIX(correction_matrix); +// Implicit uniforms: +// uniform mat3 PREFIX(correction_matrix); vec4 FUNCNAME(vec2 tc) { vec4 ret = INPUT(tc); diff --git a/white_balance_effect.h b/white_balance_effect.h index 342426b..2370847 100644 --- a/white_balance_effect.h +++ b/white_balance_effect.h @@ -5,6 +5,7 @@ #include #include +#include #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 diff --git a/ycbcr_422interleaved_input.cpp b/ycbcr_422interleaved_input.cpp index b634289..c345f8d 100644 --- a/ycbcr_422interleaved_input.cpp +++ b/ycbcr_422interleaved_input.cpp @@ -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; } diff --git a/ycbcr_422interleaved_input.frag b/ycbcr_422interleaved_input.frag index 66762a8..96b93f8 100644 --- a/ycbcr_422interleaved_input.frag +++ b/ycbcr_422interleaved_input.frag @@ -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 diff --git a/ycbcr_422interleaved_input.h b/ycbcr_422interleaved_input.h index b346986..b7000a0 100644 --- a/ycbcr_422interleaved_input.h +++ b/ycbcr_422interleaved_input.h @@ -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 diff --git a/ycbcr_input.cpp b/ycbcr_input.cpp index 091880f..ed1f569 100644 --- a/ycbcr_input.cpp +++ b/ycbcr_input.cpp @@ -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; } diff --git a/ycbcr_input.frag b/ycbcr_input.frag index bd6ff76..b84499d 100644 --- a/ycbcr_input.frag +++ b/ycbcr_input.frag @@ -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 diff --git a/ycbcr_input.h b/ycbcr_input.h index 97ad526..7db5375 100644 --- a/ycbcr_input.h +++ b/ycbcr_input.h @@ -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]; -- 2.39.5