Index: skia/ext/convolver.cc |
diff --git a/skia/ext/convolver.cc b/skia/ext/convolver.cc |
index ee9d056fa436336338d92f8a3620d285c1d634cb..ab285dc4a39cfab3a639248d11622978f3f254a9 100644 |
--- a/skia/ext/convolver.cc |
+++ b/skia/ext/convolver.cc |
@@ -5,6 +5,7 @@ |
#include <algorithm> |
#include "skia/ext/convolver.h" |
+#include "third_party/skia/include/core/SkSize.h" |
#include "third_party/skia/include/core/SkTypes.h" |
#if defined(SIMD_SSE2) |
@@ -682,6 +683,7 @@ void ConvolutionFilter1D::AddFilter(int filter_offset, |
// cases it is beneficial to only store the central factors. |
// For a scaling to 1/4th in each dimension using a Lanczos-2 filter on |
// a 1080p image this optimization gives a ~10% speed improvement. |
+ int filter_size = filter_length; |
int first_non_zero = 0; |
while (first_non_zero < filter_length && filter_values[first_non_zero] == 0) |
first_non_zero++; |
@@ -710,6 +712,7 @@ void ConvolutionFilter1D::AddFilter(int filter_offset, |
filter_length); |
instance.offset = filter_offset; |
instance.length = filter_length; |
+ instance.filter_size = filter_size; |
filters_.push_back(instance); |
max_filter_ = std::max(max_filter_, filter_length); |
@@ -857,4 +860,114 @@ void BGRAConvolve2D(const unsigned char* source_data, |
} |
} |
+void SingleChannelConvolve1D_X(const unsigned char* source_data, |
+ int source_byte_row_stride, |
+ int input_channel_index, |
+ int input_channel_count, |
+ const ConvolutionFilter1D& filter, |
+ const SkISize& image_size, |
+ unsigned char* output, |
+ int output_byte_row_stride, |
+ int output_channel_index, |
+ int output_channel_count, |
+ bool absolute_values) { |
+ int filter_offset, filter_length, filter_size; |
+ // Very much unlike BGRAConvolve2D, here we expect to have the same filter |
+ // for all pixels. |
+ const ConvolutionFilter1D::Fixed* filter_values = |
+ filter.GetSingleFilter(&filter_size, &filter_offset, &filter_length); |
+ |
+ if (filter_values == NULL) |
+ return; |
+ |
+ int centrepoint = filter_length / 2; |
+ if (filter_size - filter_offset != 2 * filter_offset) { |
+ // This means the original filter was not symmetrical AND |
+ // got clipped from one side more than from the other. |
+ centrepoint = filter_size / 2 - filter_offset; |
+ } |
+ |
+ const unsigned char* source_data_row = source_data; |
+ unsigned char* output_row = output; |
+ |
+ for (int r = 0; r < image_size.height(); ++r) { |
+ unsigned char* target_byte = output_row + output_channel_index; |
+ for (int c = 0; c < image_size.width(); ++c) { |
+ int accval = 0; |
+ for (int i = 0; i < filter_length; ++i) { |
+ ConvolutionFilter1D::Fixed cur_filter = filter_values[i]; |
+ int pixel_index = c + i - centrepoint; |
Stephen White
2013/04/10 15:20:31
Perf: could probably hoist this out of the loop.
motek.
2013/04/11 16:18:38
I have reworked that from the perf angle.
|
+ // Handling of edges is always wrap-around. Clip to 0 / width. |
Stephen White
2013/04/10 15:20:31
Seems strange to wrap-around instead of clamp, but
motek.
2013/04/11 16:18:38
Padding would be most reasonable for this applicat
|
+ pixel_index = (pixel_index + image_size.width()) % image_size.width(); |
Stephen White
2013/04/10 15:20:31
Perf: could compute the margins in separate inner
motek.
2013/04/11 16:18:38
Done.
|
+ const unsigned char src_value = source_data_row[ |
+ pixel_index * input_channel_count + input_channel_index]; |
+ accval += cur_filter * src_value; |
+ } |
+ // Bring this value back in range. All of the filter scaling factors |
+ // are in fixed point with kShiftBits bits of fractional part. |
+ accval >>= ConvolutionFilter1D::kShiftBits; |
+ if (absolute_values) |
+ accval = std::abs(accval); |
+ *target_byte = ClampTo8(accval); |
+ target_byte += output_channel_count; |
+ } |
+ |
+ source_data_row += source_byte_row_stride; |
+ output_row += output_byte_row_stride; |
+ } |
+} |
+ |
+void SingleChannelConvolve1D_Y(const unsigned char* source_data, |
+ int source_byte_row_stride, |
+ int input_channel_index, |
+ int input_channel_count, |
+ const ConvolutionFilter1D& filter, |
+ const SkISize& image_size, |
+ unsigned char* output, |
+ int output_byte_row_stride, |
+ int output_channel_index, |
+ int output_channel_count, |
+ bool absolute_values) { |
+ int filter_offset, filter_length, filter_size; |
+ // Very much unlike BGRAConvolve2D, here we expect to have the same filter |
+ // for all pixels. |
+ const ConvolutionFilter1D::Fixed* filter_values = |
+ filter.GetSingleFilter(&filter_size, &filter_offset, &filter_length); |
+ |
+ if (filter_values == NULL) |
+ return; |
+ |
+ int centrepoint = filter_length / 2; |
+ if (filter_size - filter_offset != 2 * filter_offset) { |
+ // This means the original filter was not symmetrical AND |
+ // got clipped from one side more than from the other. |
+ centrepoint = filter_size / 2 - filter_offset; |
+ } |
+ |
+ for (int c = 0; c < image_size.width(); ++c) { |
+ for (int r = 0; r < image_size.height(); ++r) { |
+ unsigned char* target_byte = output + |
+ r * output_byte_row_stride + |
+ c * output_channel_count + |
+ output_channel_index; |
+ int accval = 0; |
+ for (int i = 0; i < filter_length; ++i) { |
+ ConvolutionFilter1D::Fixed cur_filter = filter_values[i]; |
+ int pixel_index = r + i - centrepoint; |
+ pixel_index = (pixel_index + image_size.height()) % image_size.height(); |
+ |
+ const unsigned char src_value = source_data[ |
+ pixel_index * source_byte_row_stride + |
+ c * input_channel_count + |
+ input_channel_index]; |
+ accval += cur_filter * src_value; |
+ } |
+ accval >>= ConvolutionFilter1D::kShiftBits; |
+ if (absolute_values) |
+ accval = std::abs(accval); |
+ *target_byte = ClampTo8(accval); |
+ } |
+ } |
+} |
+ |
} // namespace skia |