Index: skia/ext/convolver.cc |
=================================================================== |
--- skia/ext/convolver.cc (revision 72357) |
+++ skia/ext/convolver.cc (working copy) |
@@ -1,4 +1,4 @@ |
-// Copyright (c) 2009 The Chromium Authors. All rights reserved. |
+// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
@@ -233,32 +233,54 @@ |
void ConvolutionFilter1D::AddFilter(int filter_offset, |
const float* filter_values, |
int filter_length) { |
- FilterInstance instance; |
- instance.data_location = static_cast<int>(filter_values_.size()); |
- instance.offset = filter_offset; |
- instance.length = filter_length; |
- filters_.push_back(instance); |
- |
SkASSERT(filter_length > 0); |
- for (int i = 0; i < filter_length; i++) |
- filter_values_.push_back(FloatToFixed(filter_values[i])); |
- max_filter_ = std::max(max_filter_, filter_length); |
+ std::vector<Fixed> fixed_values; |
+ fixed_values.reserve(filter_length); |
+ |
+ for (int i = 0; i < filter_length; ++i) |
+ fixed_values.push_back(FloatToFixed(filter_values[i])); |
+ |
+ AddFilter(filter_offset, &fixed_values[0], filter_length); |
} |
void ConvolutionFilter1D::AddFilter(int filter_offset, |
const Fixed* filter_values, |
int filter_length) { |
+ // It is common for leading/trailing filter values to be zeros. In such |
+ // 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 first_non_zero = 0; |
+ while (first_non_zero < filter_length && filter_values[first_non_zero] == 0) |
+ first_non_zero++; |
+ |
+ if (first_non_zero < filter_length) { |
+ // Here we have at least one non-zero factor. |
+ int last_non_zero = filter_length - 1; |
+ while (last_non_zero >= 0 && filter_values[last_non_zero] == 0) |
+ last_non_zero--; |
+ |
+ filter_offset += first_non_zero; |
+ filter_length = last_non_zero + 1 - first_non_zero; |
+ SkASSERT(filter_length > 0); |
+ |
+ for (int i = first_non_zero; i <= last_non_zero; i++) |
+ filter_values_.push_back(filter_values[i]); |
+ } else { |
+ // Here all the factors were zeroes. |
+ filter_length = 0; |
+ } |
+ |
FilterInstance instance; |
- instance.data_location = static_cast<int>(filter_values_.size()); |
+ |
+ // We pushed filter_length elements onto filter_values_ |
+ instance.data_location = (static_cast<int>(filter_values_.size()) - |
+ filter_length); |
instance.offset = filter_offset; |
instance.length = filter_length; |
filters_.push_back(instance); |
- SkASSERT(filter_length > 0); |
- for (int i = 0; i < filter_length; i++) |
- filter_values_.push_back(filter_values[i]); |
- |
max_filter_ = std::max(max_filter_, filter_length); |
} |
@@ -269,6 +291,7 @@ |
bool source_has_alpha, |
const ConvolutionFilter1D& filter_x, |
const ConvolutionFilter1D& filter_y, |
+ int output_byte_row_stride, |
unsigned char* output) { |
int max_y_filter_size = filter_y.max_filter(); |
@@ -292,7 +315,7 @@ |
// Loop over every possible output row, processing just enough horizontal |
// convolutions to run each subsequent vertical convolution. |
- int output_row_byte_width = filter_x.num_values() * 4; |
+ SkASSERT(output_byte_row_stride >= filter_x.num_values() * 4); |
int num_output_rows = filter_y.num_values(); |
for (int out_y = 0; out_y < num_output_rows; out_y++) { |
filter_values = filter_y.FilterForValue(out_y, |
@@ -313,7 +336,7 @@ |
} |
// Compute where in the output image this row of final data will go. |
- unsigned char* cur_output_row = &output[out_y * output_row_byte_width]; |
+ unsigned char* cur_output_row = &output[out_y * output_byte_row_stride]; |
// Get the list of rows that the circular buffer has, in order. |
int first_row_in_circular_buffer; |
@@ -338,4 +361,3 @@ |
} |
} // namespace skia |
- |