Floating point rounding causes stbir__calculate_sample_range_upsample to sometimes think it needs one more scanline than it really does. This patch adds one extra entry to the ringbuffer to avoid the problem.

master
Jorge Rodriguez ago%!(EXTRA string=8 years)
parent 59a5a155b4
commit 638267b6d5
  1. 44
      stb_image_resize.h

@ -533,10 +533,11 @@ typedef struct
int horizontal_num_contributors;
int vertical_num_contributors;
int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)
int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)
int ring_buffer_num_entries; // Total number of entries in the ring buffer.
int ring_buffer_first_scanline;
int ring_buffer_last_scanline;
int ring_buffer_begin_index;
int ring_buffer_begin_index; // first_scanline is at this index in the ring buffer
float* ring_buffer;
float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds.
@ -1411,6 +1412,8 @@ static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n)
int ring_buffer_index;
float* ring_buffer;
stbir_info->ring_buffer_last_scanline = n;
if (stbir_info->ring_buffer_begin_index < 0)
{
ring_buffer_index = stbir_info->ring_buffer_begin_index = 0;
@ -1418,15 +1421,13 @@ static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n)
}
else
{
ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline) + 1) % stbir_info->vertical_filter_pixel_width;
ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries;
STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index);
}
ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float));
memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes);
stbir_info->ring_buffer_last_scanline = n;
return ring_buffer;
}
@ -1678,9 +1679,9 @@ static void stbir__decode_and_resample_downsample(stbir__info* stbir_info, int n
}
// Get the specified scan line from the ring buffer.
static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_size, int ring_buffer_length)
static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_num_entries, int ring_buffer_length)
{
int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_size;
int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries;
return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length);
}
@ -1865,7 +1866,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
int alpha_channel = stbir_info->alpha_channel;
int type = stbir_info->type;
int colorspace = stbir_info->colorspace;
int kernel_pixel_width = stbir_info->vertical_filter_pixel_width;
int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
void* output_data = stbir_info->output_data;
float* encode_buffer = stbir_info->encode_buffer;
int decode = STBIR__DECODE(type, colorspace);
@ -1900,7 +1901,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
for (k = n0; k <= n1; k++)
{
int coefficient_index = coefficient_counter++;
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x)
{
@ -1913,7 +1914,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
for (k = n0; k <= n1; k++)
{
int coefficient_index = coefficient_counter++;
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x)
{
@ -1927,7 +1928,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
for (k = n0; k <= n1; k++)
{
int coefficient_index = coefficient_counter++;
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x)
{
@ -1942,7 +1943,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
for (k = n0; k <= n1; k++)
{
int coefficient_index = coefficient_counter++;
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x)
{
@ -1958,7 +1959,7 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
for (k = n0; k <= n1; k++)
{
int coefficient_index = coefficient_counter++;
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
for (x = 0; x < output_w; ++x)
{
@ -1981,7 +1982,7 @@ static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n,
stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
float* vertical_coefficients = stbir_info->vertical_coefficients;
int channels = stbir_info->channels;
int kernel_pixel_width = stbir_info->vertical_filter_pixel_width;
int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
void* output_data = stbir_info->output_data;
float* horizontal_buffer = stbir_info->horizontal_buffer;
int coefficient_width = stbir_info->vertical_coefficient_width;
@ -2005,7 +2006,7 @@ static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n,
int coefficient_group = coefficient_width * contributor;
float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, kernel_pixel_width, ring_buffer_length);
float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
switch (channels) {
case 1:
@ -2071,7 +2072,7 @@ static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out);
STBIR_ASSERT(in_last_scanline - in_first_scanline <= stbir_info->vertical_filter_pixel_width);
STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
if (stbir_info->ring_buffer_begin_index >= 0)
{
@ -2090,7 +2091,7 @@ static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
else
{
stbir_info->ring_buffer_first_scanline++;
stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->vertical_filter_pixel_width;
stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
}
}
}
@ -2148,7 +2149,7 @@ static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessar
else
{
stbir_info->ring_buffer_first_scanline++;
stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->vertical_filter_pixel_width;
stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
}
}
}
@ -2172,7 +2173,7 @@ static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in);
STBIR_ASSERT(out_last_scanline - out_first_scanline <= stbir_info->vertical_filter_pixel_width);
STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
if (out_last_scanline < 0 || out_first_scanline >= output_h)
continue;
@ -2246,13 +2247,16 @@ static stbir_uint32 stbir__calculate_memory(stbir__info *info)
info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w);
info->vertical_num_contributors = stbir__get_contributors(info->vertical_scale , info->vertical_filter , info->input_h, info->output_h);
// One extra entry because floating point precision problems sometimes cause an extra to be necessary.
info->ring_buffer_num_entries = filter_height + 1;
info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors);
info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float);
info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors);
info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float);
info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float);
info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float);
info->ring_buffer_size = info->output_w * info->channels * filter_height * sizeof(float);
info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries * sizeof(float);
info->encode_buffer_size = info->output_w * info->channels * sizeof(float);
STBIR_ASSERT(info->horizontal_filter != 0);

Loading…
Cancel
Save