convolver.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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. #ifndef SKIA_EXT_CONVOLVER_H_
  5. #define SKIA_EXT_CONVOLVER_H_
  6. #include <stdint.h>
  7. #include <cmath>
  8. #include <vector>
  9. #include "build/build_config.h"
  10. #include "third_party/skia/include/core/SkSize.h"
  11. #include "third_party/skia/include/core/SkTypes.h"
  12. // We can build SSE2 optimized versions for all x86 CPUs
  13. // except when building for the IOS emulator.
  14. #if defined(ARCH_CPU_X86_FAMILY) && !BUILDFLAG(IS_IOS)
  15. #define SIMD_SSE2 1
  16. #define SIMD_PADDING 8 // 8 * int16_t
  17. #endif
  18. #if defined (ARCH_CPU_MIPS_FAMILY) && \
  19. defined(__mips_dsp) && (__mips_dsp_rev >= 2)
  20. #define SIMD_MIPS_DSPR2 1
  21. #endif
  22. #if defined(ARCH_CPU_ARM_FAMILY) && \
  23. (defined(__ARM_NEON__) || defined(__ARM_NEON))
  24. #define SIMD_NEON 1
  25. #endif
  26. // avoid confusion with Mac OS X's math library (Carbon)
  27. #if defined(__APPLE__)
  28. #undef FloatToFixed
  29. #undef FixedToFloat
  30. #endif
  31. namespace skia {
  32. // Represents a filter in one dimension. Each output pixel has one entry in this
  33. // object for the filter values contributing to it. You build up the filter
  34. // list by calling AddFilter for each output pixel (in order).
  35. //
  36. // We do 2-dimensional convolution by first convolving each row by one
  37. // ConvolutionFilter1D, then convolving each column by another one.
  38. //
  39. // Entries are stored in fixed point, shifted left by kShiftBits.
  40. class ConvolutionFilter1D {
  41. public:
  42. typedef short Fixed;
  43. // The number of bits that fixed point values are shifted by.
  44. enum { kShiftBits = 14 };
  45. SK_API ConvolutionFilter1D();
  46. SK_API ~ConvolutionFilter1D();
  47. // Convert between floating point and our fixed point representation.
  48. static Fixed FloatToFixed(float f) {
  49. return static_cast<Fixed>(f * (1 << kShiftBits));
  50. }
  51. static unsigned char FixedToChar(Fixed x) {
  52. return static_cast<unsigned char>(x >> kShiftBits);
  53. }
  54. static float FixedToFloat(Fixed x) {
  55. // The cast relies on Fixed being a short, implying that on
  56. // the platforms we care about all (16) bits will fit into
  57. // the mantissa of a (32-bit) float.
  58. static_assert(sizeof(Fixed) == 2,
  59. "fixed type should fit in float mantissa");
  60. float raw = static_cast<float>(x);
  61. return ldexpf(raw, -kShiftBits);
  62. }
  63. // Returns the maximum pixel span of a filter.
  64. int max_filter() const { return max_filter_; }
  65. // Returns the number of filters in this filter. This is the dimension of the
  66. // output image.
  67. int num_values() const { return static_cast<int>(filters_.size()); }
  68. // Appends the given list of scaling values for generating a given output
  69. // pixel. |filter_offset| is the distance from the edge of the image to where
  70. // the scaling factors start. The scaling factors apply to the source pixels
  71. // starting from this position, and going for the next |filter_length| pixels.
  72. //
  73. // You will probably want to make sure your input is normalized (that is,
  74. // all entries in |filter_values| sub to one) to prevent affecting the overall
  75. // brighness of the image.
  76. //
  77. // The filter_length must be > 0.
  78. //
  79. // This version will automatically convert your input to fixed point.
  80. SK_API void AddFilter(int filter_offset,
  81. const float* filter_values,
  82. int filter_length);
  83. // Same as the above version, but the input is already fixed point.
  84. void AddFilter(int filter_offset,
  85. const Fixed* filter_values,
  86. int filter_length);
  87. // Retrieves a filter for the given |value_offset|, a position in the output
  88. // image in the direction we're convolving. The offset and length of the
  89. // filter values are put into the corresponding out arguments (see AddFilter
  90. // above for what these mean), and a pointer to the first scaling factor is
  91. // returned. There will be |filter_length| values in this array.
  92. inline const Fixed* FilterForValue(int value_offset,
  93. int* filter_offset,
  94. int* filter_length) const {
  95. const FilterInstance& filter = filters_[value_offset];
  96. *filter_offset = filter.offset;
  97. *filter_length = filter.trimmed_length;
  98. if (filter.trimmed_length == 0) {
  99. return NULL;
  100. }
  101. return &filter_values_[filter.data_location];
  102. }
  103. // Retrieves the filter for the offset 0, presumed to be the one and only.
  104. // The offset and length of the filter values are put into the corresponding
  105. // out arguments (see AddFilter). Note that |filter_legth| and
  106. // |specified_filter_length| may be different if leading/trailing zeros of the
  107. // original floating point form were clipped.
  108. // There will be |filter_length| values in the return array.
  109. // Returns NULL if the filter is 0-length (for instance when all floating
  110. // point values passed to AddFilter were clipped to 0).
  111. SK_API const Fixed* GetSingleFilter(int* specified_filter_length,
  112. int* filter_offset,
  113. int* filter_length) const;
  114. inline void PaddingForSIMD() {
  115. // Padding |padding_count| of more dummy coefficients after the coefficients
  116. // of last filter to prevent SIMD instructions which load 8 or 16 bytes
  117. // together to access invalid memory areas. We are not trying to align the
  118. // coefficients right now due to the opaqueness of <vector> implementation.
  119. // This has to be done after all |AddFilter| calls.
  120. #ifdef SIMD_PADDING
  121. for (int i = 0; i < SIMD_PADDING; ++i)
  122. filter_values_.push_back(static_cast<Fixed>(0));
  123. #endif
  124. }
  125. private:
  126. struct FilterInstance {
  127. // Offset within filter_values for this instance of the filter.
  128. int data_location;
  129. // Distance from the left of the filter to the center. IN PIXELS
  130. int offset;
  131. // Number of values in this filter instance.
  132. int trimmed_length;
  133. // Filter length as specified. Note that this may be different from
  134. // 'trimmed_length' if leading/trailing zeros of the original floating
  135. // point form were clipped differently on each tail.
  136. int length;
  137. };
  138. // Stores the information for each filter added to this class.
  139. std::vector<FilterInstance> filters_;
  140. // We store all the filter values in this flat list, indexed by
  141. // |FilterInstance.data_location| to avoid the mallocs required for storing
  142. // each one separately.
  143. std::vector<Fixed> filter_values_;
  144. // The maximum size of any filter we've added.
  145. int max_filter_;
  146. };
  147. // Does a two-dimensional convolution on the given source image.
  148. //
  149. // It is assumed the source pixel offsets referenced in the input filters
  150. // reference only valid pixels, so the source image size is not required. Each
  151. // row of the source image starts |source_byte_row_stride| after the previous
  152. // one (this allows you to have rows with some padding at the end).
  153. //
  154. // The result will be put into the given output buffer. The destination image
  155. // size will be xfilter.num_values() * yfilter.num_values() pixels. It will be
  156. // in rows of exactly xfilter.num_values() * 4 bytes.
  157. //
  158. // |source_has_alpha| is a hint that allows us to avoid doing computations on
  159. // the alpha channel if the image is opaque. If you don't know, set this to
  160. // true and it will work properly, but setting this to false will be a few
  161. // percent faster if you know the image is opaque.
  162. //
  163. // The layout in memory is assumed to be 4-bytes per pixel in B-G-R-A order
  164. // (this is ARGB when loaded into 32-bit words on a little-endian machine).
  165. SK_API void BGRAConvolve2D(const unsigned char* source_data,
  166. int source_byte_row_stride,
  167. bool source_has_alpha,
  168. const ConvolutionFilter1D& xfilter,
  169. const ConvolutionFilter1D& yfilter,
  170. int output_byte_row_stride,
  171. unsigned char* output,
  172. bool use_simd_if_possible);
  173. // Does a 1D convolution of the given source image along the X dimension on
  174. // a single channel of the bitmap.
  175. //
  176. // The function uses the same convolution kernel for each pixel. That kernel
  177. // must be added to |filter| at offset 0. This is a most straightforward
  178. // implementation of convolution, intended chiefly for development purposes.
  179. SK_API void SingleChannelConvolveX1D(const unsigned char* source_data,
  180. int source_byte_row_stride,
  181. int input_channel_index,
  182. int input_channel_count,
  183. const ConvolutionFilter1D& filter,
  184. const SkISize& image_size,
  185. unsigned char* output,
  186. int output_byte_row_stride,
  187. int output_channel_index,
  188. int output_channel_count,
  189. bool absolute_values);
  190. // Does a 1D convolution of the given source image along the Y dimension on
  191. // a single channel of the bitmap.
  192. SK_API void SingleChannelConvolveY1D(const unsigned char* source_data,
  193. int source_byte_row_stride,
  194. int input_channel_index,
  195. int input_channel_count,
  196. const ConvolutionFilter1D& filter,
  197. const SkISize& image_size,
  198. unsigned char* output,
  199. int output_byte_row_stride,
  200. int output_channel_index,
  201. int output_channel_count,
  202. bool absolute_values);
  203. // Set up the |filter| instance with a gaussian kernel. |kernel_sigma| is the
  204. // parameter of gaussian. If |derivative| is true, the kernel will be that of
  205. // the first derivative. Intended for use with the two routines above.
  206. SK_API void SetUpGaussianConvolutionKernel(ConvolutionFilter1D* filter,
  207. float kernel_sigma,
  208. bool derivative);
  209. } // namespace skia
  210. #endif // SKIA_EXT_CONVOLVER_H_