Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(364)

Side by Side Diff: skia/ext/convolver.cc

Issue 5575010: Integration of most changes from the GoogleTV project around the convolver/sc... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Latest rounds of changes to address Brett's comments Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « skia/ext/convolver.h ('k') | skia/ext/convolver_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <algorithm> 5 #include <algorithm>
6 6
7 #include "skia/ext/convolver.h" 7 #include "skia/ext/convolver.h"
8 #include "third_party/skia/include/core/SkTypes.h" 8 #include "third_party/skia/include/core/SkTypes.h"
9 9
10 namespace skia { 10 namespace skia {
11 11
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 ConvolutionFilter1D::ConvolutionFilter1D() 226 ConvolutionFilter1D::ConvolutionFilter1D()
227 : max_filter_(0) { 227 : max_filter_(0) {
228 } 228 }
229 229
230 ConvolutionFilter1D::~ConvolutionFilter1D() { 230 ConvolutionFilter1D::~ConvolutionFilter1D() {
231 } 231 }
232 232
233 void ConvolutionFilter1D::AddFilter(int filter_offset, 233 void ConvolutionFilter1D::AddFilter(int filter_offset,
234 const float* filter_values, 234 const float* filter_values,
235 int filter_length) { 235 int filter_length) {
236 FilterInstance instance; 236 SkASSERT(filter_length > 0);
237 instance.data_location = static_cast<int>(filter_values_.size());
238 instance.offset = filter_offset;
239 instance.length = filter_length;
240 filters_.push_back(instance);
241 237
242 SkASSERT(filter_length > 0); 238 std::vector<Fixed> fixed_values;
243 for (int i = 0; i < filter_length; i++) 239 fixed_values.reserve(filter_length);
244 filter_values_.push_back(FloatToFixed(filter_values[i]));
245 240
246 max_filter_ = std::max(max_filter_, filter_length); 241 for (int i = 0; i < filter_length; ++i)
242 fixed_values.push_back(FloatToFixed(filter_values[i]));
243
244 AddFilter(filter_offset, &fixed_values[0], filter_length);
247 } 245 }
248 246
249 void ConvolutionFilter1D::AddFilter(int filter_offset, 247 void ConvolutionFilter1D::AddFilter(int filter_offset,
250 const Fixed* filter_values, 248 const Fixed* filter_values,
251 int filter_length) { 249 int filter_length) {
250 // It is common for leading/trailing filter values to be zeros. In such
251 // cases it is beneficial to only store the central factors.
252 // For a scaling to 1/4th in each dimension using a Lanczos-2 filter on
253 // a 1080p image this optimization gives a ~10% speed improvement.
254 int first_non_zero = 0;
255 while (first_non_zero < filter_length && filter_values[first_non_zero] == 0)
256 first_non_zero++;
257
258 if (first_non_zero < filter_length) {
259 // Here we have at least one non-zero factor.
260 int last_non_zero = filter_length - 1;
261 while (last_non_zero >= 0 && filter_values[last_non_zero] == 0)
262 last_non_zero--;
263
264 filter_offset += first_non_zero;
265 filter_length = last_non_zero + 1 - first_non_zero;
266 SkASSERT(filter_length > 0);
267
268 for (int i = first_non_zero; i <= last_non_zero; i++)
269 filter_values_.push_back(filter_values[i]);
270 } else {
271 // Here all the factors were zeroes.
272 filter_length = 0;
273 }
274
252 FilterInstance instance; 275 FilterInstance instance;
253 instance.data_location = static_cast<int>(filter_values_.size()); 276
277 // We pushed filter_length elements onto filter_values_
278 instance.data_location = (static_cast<int>(filter_values_.size()) -
279 filter_length);
254 instance.offset = filter_offset; 280 instance.offset = filter_offset;
255 instance.length = filter_length; 281 instance.length = filter_length;
256 filters_.push_back(instance); 282 filters_.push_back(instance);
257 283
258 SkASSERT(filter_length > 0);
259 for (int i = 0; i < filter_length; i++)
260 filter_values_.push_back(filter_values[i]);
261
262 max_filter_ = std::max(max_filter_, filter_length); 284 max_filter_ = std::max(max_filter_, filter_length);
263 } 285 }
264 286
265 // BGRAConvolve2D ------------------------------------------------------------- 287 // BGRAConvolve2D -------------------------------------------------------------
266 288
267 void BGRAConvolve2D(const unsigned char* source_data, 289 void BGRAConvolve2D(const unsigned char* source_data,
268 int source_byte_row_stride, 290 int source_byte_row_stride,
269 bool source_has_alpha, 291 bool source_has_alpha,
270 const ConvolutionFilter1D& filter_x, 292 const ConvolutionFilter1D& filter_x,
271 const ConvolutionFilter1D& filter_y, 293 const ConvolutionFilter1D& filter_y,
294 int output_byte_row_stride,
272 unsigned char* output) { 295 unsigned char* output) {
273 int max_y_filter_size = filter_y.max_filter(); 296 int max_y_filter_size = filter_y.max_filter();
274 297
275 // The next row in the input that we will generate a horizontally 298 // The next row in the input that we will generate a horizontally
276 // convolved row for. If the filter doesn't start at the beginning of the 299 // convolved row for. If the filter doesn't start at the beginning of the
277 // image (this is the case when we are only resizing a subset), then we 300 // image (this is the case when we are only resizing a subset), then we
278 // don't want to generate any output rows before that. Compute the starting 301 // don't want to generate any output rows before that. Compute the starting
279 // row for convolution as the first pixel for the first vertical filter. 302 // row for convolution as the first pixel for the first vertical filter.
280 int filter_offset, filter_length; 303 int filter_offset, filter_length;
281 const ConvolutionFilter1D::Fixed* filter_values = 304 const ConvolutionFilter1D::Fixed* filter_values =
282 filter_y.FilterForValue(0, &filter_offset, &filter_length); 305 filter_y.FilterForValue(0, &filter_offset, &filter_length);
283 int next_x_row = filter_offset; 306 int next_x_row = filter_offset;
284 307
285 // We loop over each row in the input doing a horizontal convolution. This 308 // We loop over each row in the input doing a horizontal convolution. This
286 // will result in a horizontally convolved image. We write the results into 309 // will result in a horizontally convolved image. We write the results into
287 // a circular buffer of convolved rows and do vertical convolution as rows 310 // a circular buffer of convolved rows and do vertical convolution as rows
288 // are available. This prevents us from having to store the entire 311 // are available. This prevents us from having to store the entire
289 // intermediate image and helps cache coherency. 312 // intermediate image and helps cache coherency.
290 CircularRowBuffer row_buffer(filter_x.num_values(), max_y_filter_size, 313 CircularRowBuffer row_buffer(filter_x.num_values(), max_y_filter_size,
291 filter_offset); 314 filter_offset);
292 315
293 // Loop over every possible output row, processing just enough horizontal 316 // Loop over every possible output row, processing just enough horizontal
294 // convolutions to run each subsequent vertical convolution. 317 // convolutions to run each subsequent vertical convolution.
295 int output_row_byte_width = filter_x.num_values() * 4; 318 SkASSERT(output_byte_row_stride >= filter_x.num_values() * 4);
296 int num_output_rows = filter_y.num_values(); 319 int num_output_rows = filter_y.num_values();
297 for (int out_y = 0; out_y < num_output_rows; out_y++) { 320 for (int out_y = 0; out_y < num_output_rows; out_y++) {
298 filter_values = filter_y.FilterForValue(out_y, 321 filter_values = filter_y.FilterForValue(out_y,
299 &filter_offset, &filter_length); 322 &filter_offset, &filter_length);
300 323
301 // Generate output rows until we have enough to run the current filter. 324 // Generate output rows until we have enough to run the current filter.
302 while (next_x_row < filter_offset + filter_length) { 325 while (next_x_row < filter_offset + filter_length) {
303 if (source_has_alpha) { 326 if (source_has_alpha) {
304 ConvolveHorizontally<true>( 327 ConvolveHorizontally<true>(
305 &source_data[next_x_row * source_byte_row_stride], 328 &source_data[next_x_row * source_byte_row_stride],
306 filter_x, row_buffer.AdvanceRow()); 329 filter_x, row_buffer.AdvanceRow());
307 } else { 330 } else {
308 ConvolveHorizontally<false>( 331 ConvolveHorizontally<false>(
309 &source_data[next_x_row * source_byte_row_stride], 332 &source_data[next_x_row * source_byte_row_stride],
310 filter_x, row_buffer.AdvanceRow()); 333 filter_x, row_buffer.AdvanceRow());
311 } 334 }
312 next_x_row++; 335 next_x_row++;
313 } 336 }
314 337
315 // Compute where in the output image this row of final data will go. 338 // Compute where in the output image this row of final data will go.
316 unsigned char* cur_output_row = &output[out_y * output_row_byte_width]; 339 unsigned char* cur_output_row = &output[out_y * output_byte_row_stride];
317 340
318 // Get the list of rows that the circular buffer has, in order. 341 // Get the list of rows that the circular buffer has, in order.
319 int first_row_in_circular_buffer; 342 int first_row_in_circular_buffer;
320 unsigned char* const* rows_to_convolve = 343 unsigned char* const* rows_to_convolve =
321 row_buffer.GetRowAddresses(&first_row_in_circular_buffer); 344 row_buffer.GetRowAddresses(&first_row_in_circular_buffer);
322 345
323 // Now compute the start of the subset of those rows that the filter 346 // Now compute the start of the subset of those rows that the filter
324 // needs. 347 // needs.
325 unsigned char* const* first_row_for_filter = 348 unsigned char* const* first_row_for_filter =
326 &rows_to_convolve[filter_offset - first_row_in_circular_buffer]; 349 &rows_to_convolve[filter_offset - first_row_in_circular_buffer];
327 350
328 if (source_has_alpha) { 351 if (source_has_alpha) {
329 ConvolveVertically<true>(filter_values, filter_length, 352 ConvolveVertically<true>(filter_values, filter_length,
330 first_row_for_filter, 353 first_row_for_filter,
331 filter_x.num_values(), cur_output_row); 354 filter_x.num_values(), cur_output_row);
332 } else { 355 } else {
333 ConvolveVertically<false>(filter_values, filter_length, 356 ConvolveVertically<false>(filter_values, filter_length,
334 first_row_for_filter, 357 first_row_for_filter,
335 filter_x.num_values(), cur_output_row); 358 filter_x.num_values(), cur_output_row);
336 } 359 }
337 } 360 }
338 } 361 }
339 362
340 } // namespace skia 363 } // namespace skia
341
OLDNEW
« no previous file with comments | « skia/ext/convolver.h ('k') | skia/ext/convolver_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698