1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkConvolver.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,203 @@ 1.4 +// Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#ifndef SK_CONVOLVER_H 1.9 +#define SK_CONVOLVER_H 1.10 + 1.11 +#include "SkSize.h" 1.12 +#include "SkTypes.h" 1.13 +#include "SkTArray.h" 1.14 + 1.15 +// avoid confusion with Mac OS X's math library (Carbon) 1.16 +#if defined(__APPLE__) 1.17 +#undef FloatToConvolutionFixed 1.18 +#undef ConvolutionFixedToFloat 1.19 +#endif 1.20 + 1.21 +// Represents a filter in one dimension. Each output pixel has one entry in this 1.22 +// object for the filter values contributing to it. You build up the filter 1.23 +// list by calling AddFilter for each output pixel (in order). 1.24 +// 1.25 +// We do 2-dimensional convolution by first convolving each row by one 1.26 +// SkConvolutionFilter1D, then convolving each column by another one. 1.27 +// 1.28 +// Entries are stored in ConvolutionFixed point, shifted left by kShiftBits. 1.29 +class SkConvolutionFilter1D { 1.30 +public: 1.31 + typedef short ConvolutionFixed; 1.32 + 1.33 + // The number of bits that ConvolutionFixed point values are shifted by. 1.34 + enum { kShiftBits = 14 }; 1.35 + 1.36 + SK_API SkConvolutionFilter1D(); 1.37 + SK_API ~SkConvolutionFilter1D(); 1.38 + 1.39 + // Convert between floating point and our ConvolutionFixed point representation. 1.40 + static ConvolutionFixed FloatToFixed(float f) { 1.41 + return static_cast<ConvolutionFixed>(f * (1 << kShiftBits)); 1.42 + } 1.43 + static unsigned char FixedToChar(ConvolutionFixed x) { 1.44 + return static_cast<unsigned char>(x >> kShiftBits); 1.45 + } 1.46 + static float FixedToFloat(ConvolutionFixed x) { 1.47 + // The cast relies on ConvolutionFixed being a short, implying that on 1.48 + // the platforms we care about all (16) bits will fit into 1.49 + // the mantissa of a (32-bit) float. 1.50 + SK_COMPILE_ASSERT(sizeof(ConvolutionFixed) == 2, ConvolutionFixed_type_should_fit_in_float_mantissa); 1.51 + float raw = static_cast<float>(x); 1.52 + return ldexpf(raw, -kShiftBits); 1.53 + } 1.54 + 1.55 + // Returns the maximum pixel span of a filter. 1.56 + int maxFilter() const { return fMaxFilter; } 1.57 + 1.58 + // Returns the number of filters in this filter. This is the dimension of the 1.59 + // output image. 1.60 + int numValues() const { return static_cast<int>(fFilters.count()); } 1.61 + 1.62 + // Appends the given list of scaling values for generating a given output 1.63 + // pixel. |filterOffset| is the distance from the edge of the image to where 1.64 + // the scaling factors start. The scaling factors apply to the source pixels 1.65 + // starting from this position, and going for the next |filterLength| pixels. 1.66 + // 1.67 + // You will probably want to make sure your input is normalized (that is, 1.68 + // all entries in |filterValuesg| sub to one) to prevent affecting the overall 1.69 + // brighness of the image. 1.70 + // 1.71 + // The filterLength must be > 0. 1.72 + // 1.73 + // This version will automatically convert your input to ConvolutionFixed point. 1.74 + SK_API void AddFilter(int filterOffset, 1.75 + const float* filterValues, 1.76 + int filterLength); 1.77 + 1.78 + // Same as the above version, but the input is already ConvolutionFixed point. 1.79 + void AddFilter(int filterOffset, 1.80 + const ConvolutionFixed* filterValues, 1.81 + int filterLength); 1.82 + 1.83 + // Retrieves a filter for the given |valueOffset|, a position in the output 1.84 + // image in the direction we're convolving. The offset and length of the 1.85 + // filter values are put into the corresponding out arguments (see AddFilter 1.86 + // above for what these mean), and a pointer to the first scaling factor is 1.87 + // returned. There will be |filterLength| values in this array. 1.88 + inline const ConvolutionFixed* FilterForValue(int valueOffset, 1.89 + int* filterOffset, 1.90 + int* filterLength) const { 1.91 + const FilterInstance& filter = fFilters[valueOffset]; 1.92 + *filterOffset = filter.fOffset; 1.93 + *filterLength = filter.fTrimmedLength; 1.94 + if (filter.fTrimmedLength == 0) { 1.95 + return NULL; 1.96 + } 1.97 + return &fFilterValues[filter.fDataLocation]; 1.98 + } 1.99 + 1.100 + // Retrieves the filter for the offset 0, presumed to be the one and only. 1.101 + // The offset and length of the filter values are put into the corresponding 1.102 + // out arguments (see AddFilter). Note that |filterLegth| and 1.103 + // |specifiedFilterLength| may be different if leading/trailing zeros of the 1.104 + // original floating point form were clipped. 1.105 + // There will be |filterLength| values in the return array. 1.106 + // Returns NULL if the filter is 0-length (for instance when all floating 1.107 + // point values passed to AddFilter were clipped to 0). 1.108 + SK_API const ConvolutionFixed* GetSingleFilter(int* specifiedFilterLength, 1.109 + int* filterOffset, 1.110 + int* filterLength) const; 1.111 + 1.112 + // Add another value to the fFilterValues array -- useful for 1.113 + // SIMD padding which happens outside of this class. 1.114 + 1.115 + void addFilterValue( ConvolutionFixed val ) { 1.116 + fFilterValues.push_back( val ); 1.117 + } 1.118 +private: 1.119 + struct FilterInstance { 1.120 + // Offset within filterValues for this instance of the filter. 1.121 + int fDataLocation; 1.122 + 1.123 + // Distance from the left of the filter to the center. IN PIXELS 1.124 + int fOffset; 1.125 + 1.126 + // Number of values in this filter instance. 1.127 + int fTrimmedLength; 1.128 + 1.129 + // Filter length as specified. Note that this may be different from 1.130 + // 'trimmed_length' if leading/trailing zeros of the original floating 1.131 + // point form were clipped differently on each tail. 1.132 + int fLength; 1.133 + }; 1.134 + 1.135 + // Stores the information for each filter added to this class. 1.136 + SkTArray<FilterInstance> fFilters; 1.137 + 1.138 + // We store all the filter values in this flat list, indexed by 1.139 + // |FilterInstance.data_location| to avoid the mallocs required for storing 1.140 + // each one separately. 1.141 + SkTArray<ConvolutionFixed> fFilterValues; 1.142 + 1.143 + // The maximum size of any filter we've added. 1.144 + int fMaxFilter; 1.145 +}; 1.146 + 1.147 +typedef void (*SkConvolveVertically_pointer)( 1.148 + const SkConvolutionFilter1D::ConvolutionFixed* filterValues, 1.149 + int filterLength, 1.150 + unsigned char* const* sourceDataRows, 1.151 + int pixelWidth, 1.152 + unsigned char* outRow, 1.153 + bool hasAlpha); 1.154 +typedef void (*SkConvolve4RowsHorizontally_pointer)( 1.155 + const unsigned char* srcData[4], 1.156 + const SkConvolutionFilter1D& filter, 1.157 + unsigned char* outRow[4]); 1.158 +typedef void (*SkConvolveHorizontally_pointer)( 1.159 + const unsigned char* srcData, 1.160 + const SkConvolutionFilter1D& filter, 1.161 + unsigned char* outRow, 1.162 + bool hasAlpha); 1.163 +typedef void (*SkConvolveFilterPadding_pointer)( 1.164 + SkConvolutionFilter1D* filter); 1.165 + 1.166 +struct SkConvolutionProcs { 1.167 + // This is how many extra pixels may be read by the 1.168 + // conolve*horizontally functions. 1.169 + int fExtraHorizontalReads; 1.170 + SkConvolveVertically_pointer fConvolveVertically; 1.171 + SkConvolve4RowsHorizontally_pointer fConvolve4RowsHorizontally; 1.172 + SkConvolveHorizontally_pointer fConvolveHorizontally; 1.173 + SkConvolveFilterPadding_pointer fApplySIMDPadding; 1.174 +}; 1.175 + 1.176 + 1.177 + 1.178 +// Does a two-dimensional convolution on the given source image. 1.179 +// 1.180 +// It is assumed the source pixel offsets referenced in the input filters 1.181 +// reference only valid pixels, so the source image size is not required. Each 1.182 +// row of the source image starts |sourceByteRowStride| after the previous 1.183 +// one (this allows you to have rows with some padding at the end). 1.184 +// 1.185 +// The result will be put into the given output buffer. The destination image 1.186 +// size will be xfilter.numValues() * yfilter.numValues() pixels. It will be 1.187 +// in rows of exactly xfilter.numValues() * 4 bytes. 1.188 +// 1.189 +// |sourceHasAlpha| is a hint that allows us to avoid doing computations on 1.190 +// the alpha channel if the image is opaque. If you don't know, set this to 1.191 +// true and it will work properly, but setting this to false will be a few 1.192 +// percent faster if you know the image is opaque. 1.193 +// 1.194 +// The layout in memory is assumed to be 4-bytes per pixel in B-G-R-A order 1.195 +// (this is ARGB when loaded into 32-bit words on a little-endian machine). 1.196 +SK_API void BGRAConvolve2D(const unsigned char* sourceData, 1.197 + int sourceByteRowStride, 1.198 + bool sourceHasAlpha, 1.199 + const SkConvolutionFilter1D& xfilter, 1.200 + const SkConvolutionFilter1D& yfilter, 1.201 + int outputByteRowStride, 1.202 + unsigned char* output, 1.203 + const SkConvolutionProcs&, 1.204 + bool useSimdIfPossible); 1.205 + 1.206 +#endif // SK_CONVOLVER_H