/* ** ** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #include #include #include #include #include #include #include "clz.h" #define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) namespace android { #if BYTE_ORDER == LITTLE_ENDIAN inline uint32_t BLUR_RGBA_TO_HOST(uint32_t v) { return v; } inline uint32_t BLUR_HOST_TO_RGBA(uint32_t v) { return v; } #else inline uint32_t BLUR_RGBA_TO_HOST(uint32_t v) { return (v<<24) | (v>>24) | ((v<<8)&0xff0000) | ((v>>8)&0xff00); } inline uint32_t BLUR_HOST_TO_RGBA(uint32_t v) { return (v<<24) | (v>>24) | ((v<<8)&0xff0000) | ((v>>8)&0xff00); } #endif const int BLUR_DITHER_BITS = 6; // dither weights stored on 6 bits const int BLUR_DITHER_ORDER_SHIFT= 3; const int BLUR_DITHER_ORDER = (1< struct BlurColor565 { typedef uint16_t type; int r, g, b; inline BlurColor565() { } inline BlurColor565(uint16_t v) { r = v >> 11; g = (v >> 5) & 0x3E; b = v & 0x1F; } inline void clear() { r=g=b=0; } inline uint16_t to(int shift, int last, int dither) const { int R = r; int G = g; int B = b; if (UNLIKELY(last)) { if (FACTOR>0) { int L = (R+G+B)>>1; R += (((L>>1) - R) * FACTOR) >> 8; G += (((L ) - G) * FACTOR) >> 8; B += (((L>>1) - B) * FACTOR) >> 8; } R += (dither << shift) >> BLUR_DITHER_BITS; G += (dither << shift) >> BLUR_DITHER_BITS; B += (dither << shift) >> BLUR_DITHER_BITS; } R >>= shift; G >>= shift; B >>= shift; return (R<<11) | (G<<5) | B; } inline BlurColor565& operator += (const BlurColor565& rhs) { r += rhs.r; g += rhs.g; b += rhs.b; return *this; } inline BlurColor565& operator -= (const BlurColor565& rhs) { r -= rhs.r; g -= rhs.g; b -= rhs.b; return *this; } }; struct BlurGray565 { typedef uint16_t type; int l; inline BlurGray565() { } inline BlurGray565(uint16_t v) { int r = v >> 11; int g = (v >> 5) & 0x3F; int b = v & 0x1F; l = (r + g + b + 1)>>1; } inline void clear() { l=0; } inline uint16_t to(int shift, int last, int dither) const { int L = l; if (UNLIKELY(last)) { L += (dither << shift) >> BLUR_DITHER_BITS; } L >>= shift; return ((L>>1)<<11) | (L<<5) | (L>>1); } inline BlurGray565& operator += (const BlurGray565& rhs) { l += rhs.l; return *this; } inline BlurGray565& operator -= (const BlurGray565& rhs) { l -= rhs.l; return *this; } }; struct BlurGray8888 { typedef uint32_t type; int l, a; inline BlurGray8888() { } inline BlurGray8888(uint32_t v) { v = BLUR_RGBA_TO_HOST(v); int r = v & 0xFF; int g = (v >> 8) & 0xFF; int b = (v >> 16) & 0xFF; a = v >> 24; l = r + g + g + b; } inline void clear() { l=a=0; } inline uint32_t to(int shift, int last, int dither) const { int L = l; int A = a; if (UNLIKELY(last)) { L += (dither << (shift+2)) >> BLUR_DITHER_BITS; A += (dither << shift) >> BLUR_DITHER_BITS; } L >>= (shift+2); A >>= shift; return BLUR_HOST_TO_RGBA((A<<24) | (L<<16) | (L<<8) | L); } inline BlurGray8888& operator += (const BlurGray8888& rhs) { l += rhs.l; a += rhs.a; return *this; } inline BlurGray8888& operator -= (const BlurGray8888& rhs) { l -= rhs.l; a -= rhs.a; return *this; } }; template static status_t blurFilter( GGLSurface const* dst, GGLSurface const* src, int kernelSizeUser, int repeat) { typedef typename PIXEL::type TYPE; const int shift = 31 - clz(kernelSizeUser); const int areaShift = shift*2; const int kernelSize = 1<width; const int h = src->height; const uint8_t* ditherMatrix = gDitherMatrix; // we need a temporary buffer to store one line of blurred columns // as well as kernelSize lines of source pixels organized as a ring buffer. void* const temporary_buffer = malloc( (w + kernelSize) * sizeof(PIXEL) + (src->stride * kernelSize) * sizeof(TYPE)); if (!temporary_buffer) return NO_MEMORY; PIXEL* const sums = (PIXEL*)temporary_buffer; TYPE* const scratch = (TYPE*)(sums + w + kernelSize); // Apply the blur 'repeat' times, this is used to approximate // gaussian blurs. 3 times gives good results. for (int k=0 ; kstride*kernelHalfSize, src->data, src->stride*kernelHalfSize*sizeof(TYPE)); // sum half of each column, because we assume the first half is // zeros (black/transparent). for (int y=0 ; ydata + y*src->stride; for (int x=0 ; xdata + y*dst->stride; // compute the dither matrix line uint8_t const * ditherY = ditherMatrix + (y & BLUR_DITHER_MASK)*BLUR_DITHER_ORDER; // Horizontal blur pass on the columns sums int count, dither, x=0; PIXEL const * out= sums; PIXEL const * in = sums; current.clear(); count = kernelHalfSize; do { current += *in; in++; } while (--count); count = kernelHalfSize; do { current += *in; dither = *(ditherY + ((x++)&BLUR_DITHER_MASK)); *fb++ = current.to(areaShift, k==repeat-1, dither); in++; } while (--count); count = w-kernelSize; do { current += *in; current -= *out; dither = *(ditherY + ((x++)&BLUR_DITHER_MASK)); *fb++ = current.to(areaShift, k==repeat-1, dither); in++, out++; } while (--count); count = kernelHalfSize; do { current -= *out; dither = *(ditherY + ((x++)&BLUR_DITHER_MASK)); *fb++ = current.to(areaShift, k==repeat-1, dither); out++; } while (--count); // vertical blur pass, subtract the oldest line from each columns // and add a new line. Subtract or add zeros at the top // and bottom edges. TYPE* const tail = scratch + (y & mask) * src->stride; if (y >= kernelHalfSize) { for (int x=0 ; xdata + (y+kernelHalfSize)*src->stride, src->stride*sizeof(TYPE)); for (int x=0 ; x >( GGLSurface const* dst, GGLSurface const* src, int kernelSizeUser, int repeat); status_t blurFilter( GGLSurface const* image, int kernelSizeUser, int repeat) { return blurFilter< BlurColor565<0x80> >(image, image, kernelSizeUser, repeat); } } // namespace android //err = blur< BlurColor565<0x80> >(dst, src, kernelSizeUser, repeat); //err = blur(dst, src, kernelSizeUser, repeat); //err = blur(dst, src, kernelSizeUser, repeat);