From: Steinar H. Gunderson Date: Sat, 21 Feb 2015 14:52:54 +0000 (+0100) Subject: Make combine_two_samples() into a template instead of having manual rounding checks. X-Git-Tag: 1.1.3~12 X-Git-Url: https://git.sesse.net/?p=movit;a=commitdiff_plain;h=185ced44b129739c9b5438da691e71d664d6443a Make combine_two_samples() into a template instead of having manual rounding checks. --- diff --git a/blur_effect.cpp b/blur_effect.cpp index 6e5e843..29e46b0 100644 --- a/blur_effect.cpp +++ b/blur_effect.cpp @@ -199,7 +199,7 @@ void SingleBlurPassEffect::set_gl_state(GLuint glsl_program_num, const string &p float pos1 = base_pos / (float)size; float pos2 = (base_pos + 1) / (float)size; float pos, total_weight; - combine_two_samples(w1, w2, pos1, pos2, size, COMBINE_DO_NOT_ROUND, &pos, &total_weight, NULL); + combine_two_samples(w1, w2, pos1, pos2, size, &pos, &total_weight, NULL); samples[2 * i + 0] = pos; samples[2 * i + 1] = total_weight; diff --git a/resample_effect.cpp b/resample_effect.cpp index 3ccb2fd..9838cd4 100644 --- a/resample_effect.cpp +++ b/resample_effect.cpp @@ -55,13 +55,15 @@ unsigned gcd(unsigned a, unsigned b) return a; } -unsigned combine_samples(Tap *src, Tap *dst, unsigned src_size, unsigned num_src_samples, unsigned max_samples_saved) +template +unsigned combine_samples(Tap *src, Tap *dst, unsigned src_size, unsigned num_src_samples, unsigned max_samples_saved) { unsigned num_samples_saved = 0; 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) { - dst[j] = src[i]; + dst[j].weight = convert_float(src[i].weight); + dst[j].pos = convert_float(src[i].pos); } if (i == num_src_samples - 1) { @@ -85,8 +87,9 @@ unsigned combine_samples(Tap *src, Tap *dst, unsigned src_size, un float pos2 = src[i + 1].pos; assert(pos2 > pos1); - float pos, total_weight, sum_sq_error; - combine_two_samples(w1, w2, pos1, pos2, src_size, COMBINE_ROUND_TO_FP16, &pos, &total_weight, &sum_sq_error); + fp16_int_t pos, total_weight; + float sum_sq_error; + combine_two_samples(w1, w2, pos1, pos2, src_size, &pos, &total_weight, &sum_sq_error); // If the interpolation error is larger than that of about sqrt(2) of // a level at 8-bit precision, don't combine. (You'd think 1.0 was enough, @@ -403,16 +406,14 @@ void SingleResamplePassEffect::update_texture(GLuint glsl_program_num, const str // The greedy strategy for combining samples is optimal. src_bilinear_samples = 0; for (unsigned y = 0; y < dst_samples; ++y) { - unsigned num_samples_saved = combine_samples(weights + y * src_samples, NULL, src_size, src_samples, UINT_MAX); + unsigned num_samples_saved = combine_samples(weights + y * src_samples, NULL, src_size, src_samples, UINT_MAX); src_bilinear_samples = max(src_bilinear_samples, src_samples - num_samples_saved); } // Now that we know the right width, actually combine the samples. - Tap *bilinear_weights = new Tap[dst_samples * src_bilinear_samples]; - Tap *bilinear_weights_fp16 = new Tap[dst_samples * src_bilinear_samples]; + Tap *bilinear_weights = new Tap[dst_samples * src_bilinear_samples]; for (unsigned y = 0; y < dst_samples; ++y) { - Tap *bilinear_weights_ptr = bilinear_weights + y * src_bilinear_samples; - Tap *bilinear_weights_fp16_ptr = bilinear_weights_fp16 + y * src_bilinear_samples; + Tap *bilinear_weights_ptr = bilinear_weights + y * src_bilinear_samples; unsigned num_samples_saved = combine_samples( weights + y * src_samples, bilinear_weights_ptr, @@ -421,22 +422,16 @@ void SingleResamplePassEffect::update_texture(GLuint glsl_program_num, const str src_samples - src_bilinear_samples); assert(int(src_samples) - int(num_samples_saved) == src_bilinear_samples); - // Convert to fp16. - for (int i = 0; i < src_bilinear_samples; ++i) { - bilinear_weights_fp16_ptr[i].weight = fp64_to_fp16(bilinear_weights_ptr[i].weight); - bilinear_weights_fp16_ptr[i].pos = fp64_to_fp16(bilinear_weights_ptr[i].pos); - } - // Normalize so that the sum becomes one. Note that we do it twice; // this sometimes helps a tiny little bit when we have many samples. for (int normalize_pass = 0; normalize_pass < 2; ++normalize_pass) { double sum = 0.0; for (int i = 0; i < src_bilinear_samples; ++i) { - sum += fp16_to_fp64(bilinear_weights_fp16_ptr[i].weight); + sum += fp16_to_fp64(bilinear_weights_ptr[i].weight); } for (int i = 0; i < src_bilinear_samples; ++i) { - bilinear_weights_fp16_ptr[i].weight = fp64_to_fp16( - fp16_to_fp64(bilinear_weights_fp16_ptr[i].weight) / sum); + bilinear_weights_ptr[i].weight = fp64_to_fp16( + fp16_to_fp64(bilinear_weights_ptr[i].weight) / sum); } } } @@ -452,12 +447,11 @@ void SingleResamplePassEffect::update_texture(GLuint glsl_program_num, const str check_error(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); check_error(); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16F, src_bilinear_samples, dst_samples, 0, GL_RG, GL_HALF_FLOAT, bilinear_weights_fp16); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16F, src_bilinear_samples, dst_samples, 0, GL_RG, GL_HALF_FLOAT, bilinear_weights); check_error(); delete[] weights; delete[] bilinear_weights; - delete[] bilinear_weights_fp16; } void SingleResamplePassEffect::set_gl_state(GLuint glsl_program_num, const string &prefix, unsigned *sampler_num) diff --git a/util.cpp b/util.cpp index 7fbc67a..b12ee80 100644 --- a/util.cpp +++ b/util.cpp @@ -158,8 +158,9 @@ string output_glsl_mat3(const string &name, const Eigen::Matrix3d &m) return buf; } -void combine_two_samples(float w1, float w2, float pos1, float pos2, unsigned size, CombineRoundingBehavior rounding_behavior, - float *offset, float *total_weight, float *sum_sq_error) +template +void combine_two_samples(float w1, float w2, float pos1, float pos2, unsigned size, + DestFloat *offset, DestFloat *total_weight, float *sum_sq_error) { assert(movit_initialized); assert(w1 * w2 >= 0.0f); // Should not have differing signs. @@ -170,14 +171,9 @@ void combine_two_samples(float w1, float w2, float pos1, float pos2, unsigned si z = w2 / (w1 + w2); } - *offset = pos1 + z * (pos2 - pos1); - if (rounding_behavior == COMBINE_ROUND_TO_FP16) { - // Round to fp16. Note that this might take z outside the 0..1 range. - *offset = fp16_to_fp64(fp64_to_fp16(*offset)); - z = (*offset - pos1) / (pos2 - pos1); - } else { - assert(rounding_behavior == COMBINE_DO_NOT_ROUND); - } + // Round to the desired precision. Note that this might take z outside the 0..1 range. + *offset = from_fp64(pos1 + z * (pos2 - pos1)); + z = (to_fp64(*offset) - pos1) / (pos2 - pos1); // Round to the minimum number of bits we have measured earlier. // The card will do this for us anyway, but if we know what the real z @@ -208,6 +204,15 @@ void combine_two_samples(float w1, float w2, float pos1, float pos2, unsigned si } } +// Explicit instantiations. +template +void combine_two_samples(float w1, float w2, float pos1, float pos2, unsigned size, + float *offset, float *total_weight, float *sum_sq_error); + +template +void combine_two_samples(float w1, float w2, float pos1, float pos2, unsigned size, + fp16_int_t *offset, fp16_int_t *total_weight, float *sum_sq_error); + GLuint fill_vertex_attribute(GLuint glsl_program_num, const string &attribute_name, GLint size, GLenum type, GLsizeiptr data_size, const GLvoid *data) { int attrib = glGetAttribLocation(glsl_program_num, attribute_name.c_str()); diff --git a/util.h b/util.h index a89d3a2..e4474d3 100644 --- a/util.h +++ b/util.h @@ -62,8 +62,9 @@ enum CombineRoundingBehavior { // is COMBINE_ROUND_TO_FP16, the coordinate is assumed to be stored as a // rounded fp16 value. This enables more precise calculation of total_weight // and sum_sq_error. -void combine_two_samples(float w1, float w2, float pos1, float pos2, unsigned size, CombineRoundingBehavior rounding_behavior, - float *offset, float *total_weight, float *sum_sq_error); +template +void combine_two_samples(float w1, float w2, float pos1, float pos2, unsigned size, + DestFloat *offset, DestFloat *total_weight, float *sum_sq_error); // Create a VBO with the given data, and bind it to the vertex attribute // with name . Returns the VBO number.