OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef SK_CONVOLVER_H | |
6 #define SK_CONVOLVER_H | |
7 | |
8 #include "SkSize.h" | |
9 #include "SkTypes.h" | |
10 #include "SkTArray.h" | |
11 | |
12 // avoid confusion with Mac OS X's math library (Carbon) | |
13 #if defined(__APPLE__) | |
14 #undef FloatToFixed | |
15 #undef FixedToFloat | |
16 #endif | |
17 | |
18 // Represents a filter in one dimension. Each output pixel has one entry in this | |
19 // object for the filter values contributing to it. You build up the filter | |
20 // list by calling AddFilter for each output pixel (in order). | |
21 // | |
22 // We do 2-dimensional convolution by first convolving each row by one | |
23 // SkConvolutionFilter1D, then convolving each column by another one. | |
24 // | |
25 // Entries are stored in fixed point, shifted left by kShiftBits. | |
26 class SkConvolutionFilter1D { | |
27 public: | |
28 typedef short Fixed; | |
reed1
2013/07/19 17:47:23
nit: possibly confusing to use that name for 2.14,
| |
29 | |
30 // The number of bits that fixed point values are shifted by. | |
31 enum { kShiftBits = 14 }; | |
32 | |
33 SK_API SkConvolutionFilter1D(); | |
34 SK_API ~SkConvolutionFilter1D(); | |
35 | |
36 // Convert between floating point and our fixed point representation. | |
37 static Fixed FloatToFixed(float f) { | |
38 return static_cast<Fixed>(f * (1 << kShiftBits)); | |
39 } | |
40 static unsigned char FixedToChar(Fixed x) { | |
41 return static_cast<unsigned char>(x >> kShiftBits); | |
42 } | |
43 static float FixedToFloat(Fixed x) { | |
44 // The cast relies on Fixed being a short, implying that on | |
45 // the platforms we care about all (16) bits will fit into | |
46 // the mantissa of a (32-bit) float. | |
47 SK_COMPILE_ASSERT(sizeof(Fixed) == 2, fixed_type_should_fit_in_float_man tissa); | |
48 float raw = static_cast<float>(x); | |
49 return ldexpf(raw, -kShiftBits); | |
50 } | |
51 | |
52 // Returns the maximum pixel span of a filter. | |
53 int maxFilter() const { return fMaxFilter; } | |
54 | |
55 // Returns the number of filters in this filter. This is the dimension of th e | |
56 // output image. | |
57 int numValues() const { return static_cast<int>(fFilters.count()); } | |
58 | |
59 // Appends the given list of scaling values for generating a given output | |
60 // pixel. |filterOffset| is the distance from the edge of the image to where | |
61 // the scaling factors start. The scaling factors apply to the source pixels | |
62 // starting from this position, and going for the next |filterLength| pixels . | |
63 // | |
64 // You will probably want to make sure your input is normalized (that is, | |
65 // all entries in |filterValuesg| sub to one) to prevent affecting the overa ll | |
66 // brighness of the image. | |
67 // | |
68 // The filterLength must be > 0. | |
69 // | |
70 // This version will automatically convert your input to fixed point. | |
71 SK_API void AddFilter(int filterOffset, | |
72 const float* filterValues, | |
73 int filterLength); | |
74 | |
75 // Same as the above version, but the input is already fixed point. | |
76 void AddFilter(int filterOffset, | |
77 const Fixed* filterValues, | |
78 int filterLength); | |
79 | |
80 // Retrieves a filter for the given |valueOffset|, a position in the output | |
81 // image in the direction we're convolving. The offset and length of the | |
82 // filter values are put into the corresponding out arguments (see AddFilter | |
83 // above for what these mean), and a pointer to the first scaling factor is | |
84 // returned. There will be |filterLength| values in this array. | |
85 inline const Fixed* FilterForValue(int valueOffset, | |
86 int* filterOffset, | |
87 int* filterLength) const { | |
88 const FilterInstance& filter = fFilters[valueOffset]; | |
89 *filterOffset = filter.fOffset; | |
90 *filterLength = filter.fTrimmedLength; | |
91 if (filter.fTrimmedLength == 0) { | |
92 return NULL; | |
93 } | |
94 return &fFilterValues[filter.fDataLocation]; | |
95 } | |
96 | |
97 // Retrieves the filter for the offset 0, presumed to be the one and only. | |
98 // The offset and length of the filter values are put into the corresponding | |
99 // out arguments (see AddFilter). Note that |filterLegth| and | |
100 // |specifiedFilterLength| may be different if leading/trailing zeros of the | |
101 // original floating point form were clipped. | |
102 // There will be |filterLength| values in the return array. | |
103 // Returns NULL if the filter is 0-length (for instance when all floating | |
104 // point values passed to AddFilter were clipped to 0). | |
105 SK_API const Fixed* GetSingleFilter(int* specifiedFilterLength, | |
106 int* filterOffset, | |
107 int* filterLength) const; | |
108 | |
109 // Add another value to the fFilterValues array -- useful for | |
110 // SIMD padding which happens outside of this class. | |
111 | |
112 void addFilterValue( Fixed val ) { | |
113 fFilterValues.push_back( val ); | |
114 } | |
115 private: | |
116 struct FilterInstance { | |
117 // Offset within filterValues for this instance of the filter. | |
118 int fDataLocation; | |
119 | |
120 // Distance from the left of the filter to the center. IN PIXELS | |
121 int fOffset; | |
122 | |
123 // Number of values in this filter instance. | |
124 int fTrimmedLength; | |
125 | |
126 // Filter length as specified. Note that this may be different from | |
127 // 'trimmed_length' if leading/trailing zeros of the original floating | |
128 // point form were clipped differently on each tail. | |
129 int fLength; | |
130 }; | |
131 | |
132 // Stores the information for each filter added to this class. | |
133 SkTArray<FilterInstance> fFilters; | |
134 | |
135 // We store all the filter values in this flat list, indexed by | |
136 // |FilterInstance.data_location| to avoid the mallocs required for storing | |
137 // each one separately. | |
138 SkTArray<Fixed> fFilterValues; | |
139 | |
140 // The maximum size of any filter we've added. | |
141 int fMaxFilter; | |
142 }; | |
143 | |
144 typedef void (*SkConvolveVertically_pointer)( | |
145 const SkConvolutionFilter1D::Fixed* filterValues, | |
146 int filterLength, | |
147 unsigned char* const* sourceDataRows, | |
148 int pixelWidth, | |
149 unsigned char* outRow, | |
150 bool hasAlpha); | |
151 typedef void (*SkConvolve4RowsHorizontally_pointer)( | |
152 const unsigned char* srcData[4], | |
153 const SkConvolutionFilter1D& filter, | |
154 unsigned char* outRow[4]); | |
155 typedef void (*SkConvolveHorizontally_pointer)( | |
156 const unsigned char* srcData, | |
157 const SkConvolutionFilter1D& filter, | |
158 unsigned char* outRow, | |
159 bool hasAlpha); | |
160 typedef void (*SkConvolveFilterPadding_pointer)( | |
161 SkConvolutionFilter1D *filter); | |
162 | |
163 struct SkConvolutionProcs { | |
164 // This is how many extra pixels may be read by the | |
165 // conolve*horizontally functions. | |
166 int fExtraHorizontalReads; | |
167 SkConvolveVertically_pointer fConvolveVertically; | |
168 SkConvolve4RowsHorizontally_pointer fConvolve4RowsHorizontally; | |
169 SkConvolveHorizontally_pointer fConvolveHorizontally; | |
170 SkConvolveFilterPadding_pointer fApplySIMDPadding; | |
171 }; | |
172 | |
173 | |
174 | |
175 // Does a two-dimensional convolution on the given source image. | |
176 // | |
177 // It is assumed the source pixel offsets referenced in the input filters | |
178 // reference only valid pixels, so the source image size is not required. Each | |
179 // row of the source image starts |sourceByteRowStride| after the previous | |
180 // one (this allows you to have rows with some padding at the end). | |
181 // | |
182 // The result will be put into the given output buffer. The destination image | |
183 // size will be xfilter.numValues() * yfilter.numValues() pixels. It will be | |
184 // in rows of exactly xfilter.numValues() * 4 bytes. | |
185 // | |
186 // |sourceHasAlpha| is a hint that allows us to avoid doing computations on | |
187 // the alpha channel if the image is opaque. If you don't know, set this to | |
188 // true and it will work properly, but setting this to false will be a few | |
189 // percent faster if you know the image is opaque. | |
190 // | |
191 // The layout in memory is assumed to be 4-bytes per pixel in B-G-R-A order | |
192 // (this is ARGB when loaded into 32-bit words on a little-endian machine). | |
193 SK_API void BGRAConvolve2D(const unsigned char* sourceData, | |
194 int sourceByteRowStride, | |
195 bool sourceHasAlpha, | |
196 const SkConvolutionFilter1D& xfilter, | |
197 const SkConvolutionFilter1D& yfilter, | |
198 int outputByteRowStride, | |
199 unsigned char* output, | |
200 SkConvolutionProcs *convolveProcs, | |
201 bool useSimdIfPossible); | |
202 | |
203 #endif // SK_CONVOLVER_H | |
OLD | NEW |