]> git.sesse.net Git - movit/blobdiff - resample_effect.cpp
Fix some small whitespace errors in SingleResamplePassEffect.
[movit] / resample_effect.cpp
index 30c40c4145fdd73903a7ce485d8ca75f7b28c783..690f15a90e6622ed9a1c53194251491622eed855 100644 (file)
@@ -9,6 +9,7 @@
 #include <math.h>
 #include <stdio.h>
 #include <algorithm>
+#include <mutex>
 #include <Eigen/Sparse>
 #include <Eigen/SparseQR>
 #include <Eigen/OrderingMethods>
@@ -72,7 +73,7 @@ float lanczos_weight(float x)
 // You need to call lanczos_table_init_done before the first call to
 // lanczos_weight_cached.
 #define LANCZOS_TABLE_SIZE 2048
-bool lanczos_table_init_done = false;
+static once_flag lanczos_table_init_done;
 float lanczos_table[LANCZOS_TABLE_SIZE + 2];
 
 void init_lanczos_table()
@@ -80,7 +81,6 @@ void init_lanczos_table()
        for (unsigned i = 0; i < LANCZOS_TABLE_SIZE + 2; ++i) {
                lanczos_table[i] = lanczos_weight(float(i) * (LANCZOS_RADIUS / LANCZOS_TABLE_SIZE));
        }
-       lanczos_table_init_done = true;
 }
 
 float lanczos_weight_cached(float x)
@@ -129,7 +129,7 @@ unsigned combine_samples(const Tap<float> *src, Tap<DestFloat> *dst, float num_s
 
        for (unsigned i = 0, j = 0; i < num_src_samples; ++i, ++j) {
                // Copy the sample directly; it will be overwritten later if we can combine.
-               if (dst != NULL) {
+               if (dst != nullptr) {
                        dst[j].weight = convert_float<float, DestFloat>(src[i].weight);
                        dst[j].pos = convert_float<float, DestFloat>(src[i].pos);
                }
@@ -169,7 +169,7 @@ unsigned combine_samples(const Tap<float> *src, Tap<DestFloat> *dst, float num_s
                }
 
                // OK, we can combine this and the next sample.
-               if (dst != NULL) {
+               if (dst != nullptr) {
                        dst[j].weight = total_weight;
                        dst[j].pos = pos;
                }
@@ -215,7 +215,7 @@ unsigned combine_many_samples(const Tap<float> *weights, unsigned src_size, unsi
 
        unsigned max_samples_saved = UINT_MAX;
        for (unsigned y = 0; y < dst_samples && max_samples_saved > 0; ++y) {
-               unsigned num_samples_saved = combine_samples<DestFloat>(weights + y * src_samples, NULL, num_subtexels, inv_num_subtexels, src_samples, max_samples_saved, pos1_pos2_diff, inv_pos1_pos2_diff);
+               unsigned num_samples_saved = combine_samples<DestFloat>(weights + y * src_samples, nullptr, num_subtexels, inv_num_subtexels, src_samples, max_samples_saved, pos1_pos2_diff, inv_pos1_pos2_diff);
                max_samples_saved = min(max_samples_saved, num_samples_saved);
        }
 
@@ -310,18 +310,24 @@ ResampleEffect::ResampleEffect()
        register_int("height", &output_height);
 
        // The first blur pass will forward resolution information to us.
-       hpass = new SingleResamplePassEffect(this);
+       hpass_owner.reset(new SingleResamplePassEffect(this));
+       hpass = hpass_owner.get();
        CHECK(hpass->set_int("direction", SingleResamplePassEffect::HORIZONTAL));
-       vpass = new SingleResamplePassEffect(NULL);
+       vpass_owner.reset(new SingleResamplePassEffect(this));
+       vpass = vpass_owner.get();
        CHECK(vpass->set_int("direction", SingleResamplePassEffect::VERTICAL));
 
        update_size();
 }
 
+ResampleEffect::~ResampleEffect()
+{
+}
+
 void ResampleEffect::rewrite_graph(EffectChain *graph, Node *self)
 {
-       Node *hpass_node = graph->add_node(hpass);
-       Node *vpass_node = graph->add_node(vpass);
+       Node *hpass_node = graph->add_node(hpass_owner.release());
+       Node *vpass_node = graph->add_node(vpass_owner.release());
        graph->connect_nodes(hpass_node, vpass_node);
        graph->replace_receiver(self, hpass_node);
        graph->replace_sender(self, vpass_node);
@@ -429,8 +435,8 @@ bool ResampleEffect::set_float(const string &key, float value) {
 SingleResamplePassEffect::SingleResamplePassEffect(ResampleEffect *parent)
        : parent(parent),
          direction(HORIZONTAL),
-         input_width(1280),
-         input_height(720),
+         input_width(1280),
+         input_height(720),
          offset(0.0),
          zoom(1.0),
          last_input_width(-1),
@@ -438,8 +444,7 @@ SingleResamplePassEffect::SingleResamplePassEffect(ResampleEffect *parent)
          last_output_width(-1),
          last_output_height(-1),
          last_offset(0.0 / 0.0),  // NaN.
-         last_zoom(0.0 / 0.0),  // NaN.
-         last_texture_width(-1), last_texture_height(-1)
+         last_zoom(0.0 / 0.0)  // NaN.
 {
        register_int("direction", (int *)&direction);
        register_int("input_width", &input_width);
@@ -456,18 +461,11 @@ SingleResamplePassEffect::SingleResamplePassEffect(ResampleEffect *parent)
        register_uniform_float("sample_x_offset", &uniform_sample_x_offset);
        register_uniform_float("whole_pixel_offset", &uniform_whole_pixel_offset);
 
-       glGenTextures(1, &texnum);
-
-       if (!lanczos_table_init_done) {
-               // Could in theory race between two threads if we are unlucky,
-               // but that is harmless, since they'll write the same data.
-               init_lanczos_table();
-       }
+       call_once(lanczos_table_init_done, init_lanczos_table);
 }
 
 SingleResamplePassEffect::~SingleResamplePassEffect()
 {
-       glDeleteTextures(1, &texnum);
 }
 
 string SingleResamplePassEffect::output_fragment_shader()
@@ -512,17 +510,8 @@ void SingleResamplePassEffect::update_texture(GLuint glsl_program_num, const str
        // Encode as a two-component texture. Note the GL_REPEAT.
        glActiveTexture(GL_TEXTURE0 + *sampler_num);
        check_error();
-       glBindTexture(GL_TEXTURE_2D, texnum);
+       glBindTexture(GL_TEXTURE_2D, tex.get_texnum());
        check_error();
-       if (last_texture_width == -1) {
-               // Need to set this state the first time.
-               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-               check_error();
-               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-               check_error();
-               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-               check_error();
-       }
 
        GLenum type, internal_format;
        void *pixels;
@@ -537,27 +526,13 @@ void SingleResamplePassEffect::update_texture(GLuint glsl_program_num, const str
                pixels = weights.bilinear_weights_fp16.get();
        }
 
-       if (int(weights.src_bilinear_samples) == last_texture_width &&
-           int(weights.dst_samples) == last_texture_height &&
-           internal_format == last_texture_internal_format) {
-               // Texture dimensions and type are unchanged; it is more efficient
-               // to just update it rather than making an entirely new texture.
-               glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, weights.src_bilinear_samples, weights.dst_samples, GL_RG, type, pixels);
-       } else {
-               glTexImage2D(GL_TEXTURE_2D, 0, internal_format, weights.src_bilinear_samples, weights.dst_samples, 0, GL_RG, type, pixels);
-               last_texture_width = weights.src_bilinear_samples;
-               last_texture_height = weights.dst_samples;
-               last_texture_internal_format = internal_format;
-       }
-       check_error();
+       tex.update(weights.src_bilinear_samples, weights.dst_samples, internal_format, GL_RG, type, pixels);
 }
 
 ScalingWeights calculate_scaling_weights(unsigned src_size, unsigned dst_size, float zoom, float offset)
 {
-       if (!lanczos_table_init_done) {
-               // Only needed if run from outside ResampleEffect.
-               init_lanczos_table();
-       }
+       // Only needed if run from outside ResampleEffect.
+       call_once(lanczos_table_init_done, init_lanczos_table);
 
        // For many resamplings (e.g. 640 -> 1280), we will end up with the same
        // set of samples over and over again in a loop. Thus, we can compute only
@@ -658,7 +633,7 @@ ScalingWeights calculate_scaling_weights(unsigned src_size, unsigned dst_size, f
        const float max_error = 2.0f / (255.0f * 255.0f);
        unique_ptr<Tap<fp16_int_t>[]> bilinear_weights_fp16;
        int src_bilinear_samples = combine_many_samples(weights.get(), src_size, src_samples, dst_samples, &bilinear_weights_fp16);
-       unique_ptr<Tap<float>[]> bilinear_weights_fp32 = NULL;
+       unique_ptr<Tap<float>[]> bilinear_weights_fp32 = nullptr;
        double max_sum_sq_error_fp16 = 0.0;
        for (unsigned y = 0; y < dst_samples; ++y) {
                double sum_sq_error_fp16 = compute_sum_sq_error(
@@ -711,7 +686,7 @@ void SingleResamplePassEffect::set_gl_state(GLuint glsl_program_num, const strin
 
        glActiveTexture(GL_TEXTURE0 + *sampler_num);
        check_error();
-       glBindTexture(GL_TEXTURE_2D, texnum);
+       glBindTexture(GL_TEXTURE_2D, tex.get_texnum());
        check_error();
 
        uniform_sample_tex = *sampler_num;
@@ -741,4 +716,44 @@ void SingleResamplePassEffect::set_gl_state(GLuint glsl_program_num, const strin
        }
 }
 
+Support2DTexture::Support2DTexture()
+{
+       glGenTextures(1, &texnum);
+       check_error();
+       glBindTexture(GL_TEXTURE_2D, texnum);
+       check_error();
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+       check_error();
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+       check_error();
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+       check_error();
+}
+
+Support2DTexture::~Support2DTexture()
+{
+       glDeleteTextures(1, &texnum);
+       check_error();
+}
+
+void Support2DTexture::update(GLint width, GLint height, GLenum internal_format, GLenum format, GLenum type, const GLvoid * data)
+{
+       glBindTexture(GL_TEXTURE_2D, texnum);
+       check_error();
+       if (width == last_texture_width &&
+           height == last_texture_height &&
+           internal_format == last_texture_internal_format) {
+               // Texture dimensions and type are unchanged; it is more efficient
+               // to just update it rather than making an entirely new texture.
+               glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data);
+               check_error();
+       } else {
+               glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, type, data);
+               check_error();
+               last_texture_width = width;
+               last_texture_height = height;
+               last_texture_internal_format = internal_format;
+       }
+}
+
 }  // namespace movit