From 05cc14034e5ba3803148e76d7fd6088f2bacb1d5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Mon, 9 Aug 2010 22:27:13 +0200 Subject: OpenMP-enabled matrix convolution (bzr r9508.1.53) --- src/display/nr-filter-convolve-matrix.cpp | 228 ++++++++++-------------------- 1 file changed, 71 insertions(+), 157 deletions(-) (limited to 'src') diff --git a/src/display/nr-filter-convolve-matrix.cpp b/src/display/nr-filter-convolve-matrix.cpp index 6647c6273..44e3c2290 100644 --- a/src/display/nr-filter-convolve-matrix.cpp +++ b/src/display/nr-filter-convolve-matrix.cpp @@ -31,163 +31,73 @@ FilterPrimitive * FilterConvolveMatrix::create() { FilterConvolveMatrix::~FilterConvolveMatrix() {} -template -static inline void convolve2D_XY(unsigned int const x, unsigned int const y, guint32 *const out_data, guint32 const *const in_data, unsigned int const width, unsigned int const height, double const *const kernel, unsigned int const orderX, unsigned int const orderY, unsigned int const targetX, unsigned int const targetY, double const bias) { - double result_R = 0; - double result_G = 0; - double result_B = 0; - double result_A = 0; - - unsigned int iBegin = Y_LOWER ? targetY-y : 0; // Note that to prevent signed/unsigned problems this requires that y<=targetY (which is true) - unsigned int iEnd = Y_UPPER ? height+targetY-y : orderY; // And this requires that y<=height+targetY (which is trivially true), in addition it should be true that height+targetY-y<=orderY (or equivalently y>=height+targetY-orderY, which is true) - unsigned int jBegin = X_LOWER ? targetX-x : 0; - unsigned int jEnd = X_UPPER ? width+targetX-x : orderX; - - for (unsigned int i=iBegin; i> 24; - } else { - ao = CLAMP_D_TO_U8(result_A + 255*bias); - } - - guint32 ro = CLAMP_D_TO_U8_ALPHA(result_R + ao*bias, ao); // CLAMP includes rounding! - guint32 go = CLAMP_D_TO_U8_ALPHA(result_G + ao*bias, ao); - guint32 bo = CLAMP_D_TO_U8_ALPHA(result_B + ao*bias, ao); - - ASSEMBLE_ARGB32(result, ao,ro,go,bo) - - out_data[out_index] = result; -} - -template -static inline void convolve2D_Y(unsigned int const y, guint32 *const out_data, guint32 const *const in_data, unsigned int const width, unsigned int const height, double const *const kernel, unsigned int const orderX, unsigned int const orderY, unsigned int const targetX, unsigned int const targetY, double const bias) { - // See convolve2D below for rationale. - - unsigned int const lowerEnd = std::min(targetX,width); - unsigned int const upperBegin = width - std::min(width,orderX - 1u - targetX); - unsigned int const midXBegin = std::min(lowerEnd,upperBegin); - unsigned int const midXEnd = std::max(lowerEnd,upperBegin); - - for (unsigned int x=0; x(x, y, out_data, in_data, width, height, kernel, orderX, orderY, targetX, targetY, bias); - } - if (lowerEnd==upperBegin) { - // Do nothing, empty mid section - } else if (lowerEnd(x, y, out_data, in_data, width, height, kernel, orderX, orderY, targetX, targetY, bias); - } - } else { - // In the middle both bounds have to be adjusted - for (unsigned int x=midXBegin; x(x, y, out_data, in_data, width, height, kernel, orderX, orderY, targetX, targetY, bias); - } - } - for (unsigned int x=midXEnd; x(x, y, out_data, in_data, width, height, kernel, orderX, orderY, targetX, targetY, bias); - } -} - -template -static void convolve2D(guint32 *const out_data, guint32 const *const in_data, unsigned int const width, unsigned int const height, double const *const kernel, unsigned int const orderX, unsigned int const orderY, unsigned int const targetX, unsigned int const targetY, double const _bias) { - double const bias = _bias; - - // For the middle section it should hold that (for all i such that 0<=i=height+targetY-orderY+1 i's upper bound needs to be adjusted. - - unsigned int const lowerEnd = std::min(targetY,height); - unsigned int const upperBegin = height - std::min(height,orderY - 1u - targetY); - unsigned int const midYBegin = std::min(lowerEnd,upperBegin); - unsigned int const midYEnd = std::max(lowerEnd,upperBegin); - - for (unsigned int y=0; y(y, out_data, in_data, width, height, kernel, orderX, orderY, targetX, targetY, bias); - } - if (lowerEnd==upperBegin) { - // Do nothing, empty mid section - } else if (lowerEnd(y, out_data, in_data, width, height, kernel, orderX, orderY, targetX, targetY, bias); - } - } else { - // In the middle both bounds have to be adjusted - for (unsigned int y=midYBegin; y(y, out_data, in_data, width, height, kernel, orderX, orderY, targetX, targetY, bias); - } - } - for (unsigned int y=midYEnd; y(y, out_data, in_data, width, height, kernel, orderX, orderY, targetX, targetY, bias); - } -} - -/* -struct ConvolveMatrix { - ConvolveMatrix(guint32 *px, int yskip, int targetX, int targetY, int orderX, int orderY, - double divisor, double bias, PixelAccessor::EdgeMode emode, - std::vector const &kernel) - : _kernel(kernel.size()) -// , _in(in, emode) - , _tx(targetX), _ty(targetY) - , _oX(orderX), _oY(orderY) - , _yskip(yskip) +enum PreserveAlphaMode { + PRESERVE_ALPHA, + NO_PRESERVE_ALPHA +}; + +template +struct ConvolveMatrix : public SurfaceSynth { + ConvolveMatrix(cairo_surface_t *s, int targetX, int targetY, int orderX, int orderY, + double divisor, double bias, std::vector const &kernel) + : SurfaceSynth(s) + , _kernel(kernel.size()) + , _targetX(targetX) + , _targetY(targetY) + , _orderX(orderX) + , _orderY(orderY) , _bias(bias) { - for (unsigned i = 0; i < kernel.size(); ++i) { + for (unsigned i = 0; i < _kernel.size(); ++i) { _kernel[i] = kernel[i] / divisor; } - } - - guint32 operator()(int x, int y) { - int start_x = x - _tX; - int start_y = y - _tY; - - double ro = 0, go = 0, bo = 0, ao = 0; - - for (int i = 0; i < _oY; ++i) { - for (int j = 0; j < _oX; ++j) { - guint32 in = pixelAt(start_x + j, start_y + i); - EXTRACT_ARGB(in, a,r,g,b) - - unsigned kidx = i*_oY + j; - double k = kernel[] - - ro += r * + // the matrix is given rotated 180 degrees + // which corresponds to reverse element order + std::reverse(_kernel.begin(), _kernel.end()); + } + + guint32 operator()(int x, int y) const { + int startx = std::max(0, x - _targetX); + int starty = std::max(0, y - _targetY); + int endx = std::min(_w, startx + _orderX); + int endy = std::min(_h, starty + _orderY); + int limitx = endx - startx; + int limity = endy - starty; + double suma = 0.0, sumr = 0.0, sumg = 0.0, sumb = 0.0; + + for (int i = 0; i < limity; ++i) { + for (int j = 0; j < limitx; ++j) { + guint32 px = pixelAt(startx + j, starty + i); + double coeff = _kernel[i * _orderX + j]; + EXTRACT_ARGB32(px, a,r,g,b) + + sumr += r * coeff; + sumg += g * coeff; + sumb += b * coeff; + if (preserve_alpha == NO_PRESERVE_ALPHA) { + suma += a * coeff; + } } } - - } + if (preserve_alpha == PRESERVE_ALPHA) { + suma = alphaAt(x, y); + } else { + suma += _bias * 255; + } -private: - inline guint32 pixelAt(int x, int y) { - return *(_px + y * _yskip + x); + guint32 ao = pxclamp(round(suma), 0, 255); + guint32 ro = pxclamp(round(sumr + ao * _bias), 0, ao); + guint32 go = pxclamp(round(sumg + ao * _bias), 0, ao); + guint32 bo = pxclamp(round(sumb + ao * _bias), 0, ao); + ASSEMBLE_ARGB32(pxout, ao,ro,go,bo); + return pxout; } +private: std::vector _kernel; - guint32 *_px; - // PixelAccessor _in; + int _targetX, _targetY, _orderX, _orderY; double _bias; - int _tX, _tY, _oX, _oY, _yskip; -}; */ +}; void FilterConvolveMatrix::render_cairo(FilterSlot &slot) { @@ -205,7 +115,7 @@ void FilterConvolveMatrix::render_cairo(FilterSlot &slot) return; } if (kernelMatrix.size()!=(unsigned int)(orderX*orderY)) { - g_warning("kernelMatrix does not have orderX*orderY elements!"); + //g_warning("kernelMatrix does not have orderX*orderY elements!"); return; } @@ -228,24 +138,28 @@ void FilterConvolveMatrix::render_cairo(FilterSlot &slot) edge_warning = true; } - guint32 *in_data = reinterpret_cast(cairo_image_surface_get_data(input)); - guint32 *out_data = reinterpret_cast(cairo_image_surface_get_data(out)); + //guint32 *in_data = reinterpret_cast(cairo_image_surface_get_data(input)); + //guint32 *out_data = reinterpret_cast(cairo_image_surface_get_data(out)); - int width = cairo_image_surface_get_width(input); - int height = cairo_image_surface_get_height(input); + //int width = cairo_image_surface_get_width(input); + //int height = cairo_image_surface_get_height(input); // Set up predivided kernel matrix - std::vector kernel(kernelMatrix); + /*std::vector kernel(kernelMatrix); for(size_t i=0; i(out_data, in_data, width, height, &kernel.front(), orderX, orderY, - targetX, targetY, bias); + //convolve2D(out_data, in_data, width, height, &kernel.front(), orderX, orderY, + // targetX, targetY, bias); + ink_cairo_surface_synthesize(out, ConvolveMatrix(input, + targetX, targetY, orderX, orderY, divisor, bias, kernelMatrix)); } else { - convolve2D(out_data, in_data, width, height, &kernel.front(), orderX, orderY, - targetX, targetY, bias); + //convolve2D(out_data, in_data, width, height, &kernel.front(), orderX, orderY, + // targetX, targetY, bias); + ink_cairo_surface_synthesize(out, ConvolveMatrix(input, + targetX, targetY, orderX, orderY, divisor, bias, kernelMatrix)); } slot.set(_output, out); -- cgit v1.2.3