1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "ip.rsh" 18 19 20 int height; 21 int width; 22 static int radius; 23 24 rs_allocation InPixel; 25 rs_allocation ScratchPixel1; 26 rs_allocation ScratchPixel2; 27 28 const int MAX_RADIUS = 25; 29 30 // Store our coefficients here 31 static float gaussian[MAX_RADIUS * 2 + 1]; 32 33 void setRadius(int rad) { 34 radius = rad; 35 // Compute gaussian weights for the blur 36 // e is the euler's number 37 float e = 2.718281828459045f; 38 float pi = 3.1415926535897932f; 39 // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 ) 40 // x is of the form [-radius .. 0 .. radius] 41 // and sigma varies with radius. 42 // Based on some experimental radius values and sigma's 43 // we approximately fit sigma = f(radius) as 44 // sigma = radius * 0.4 + 0.6 45 // The larger the radius gets, the more our gaussian blur 46 // will resemble a box blur since with large sigma 47 // the gaussian curve begins to lose its shape 48 float sigma = 0.4f * (float)radius + 0.6f; 49 50 // Now compute the coefficints 51 // We will store some redundant values to save some math during 52 // the blur calculations 53 // precompute some values 54 float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma); 55 float coeff2 = - 1.0f / (2.0f * sigma * sigma); 56 57 float normalizeFactor = 0.0f; 58 float floatR = 0.0f; 59 for (int r = -radius; r <= radius; r ++) { 60 floatR = (float)r; 61 gaussian[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2); 62 normalizeFactor += gaussian[r + radius]; 63 } 64 65 //Now we need to normalize the weights because all our coefficients need to add up to one 66 normalizeFactor = 1.0f / normalizeFactor; 67 for (int r = -radius; r <= radius; r ++) { 68 floatR = (float)r; 69 gaussian[r + radius] *= normalizeFactor; 70 } 71 } 72 73 float4 __attribute__((kernel)) copyIn(uchar4 in) { 74 return convert_float4(in); 75 } 76 77 uchar4 __attribute__((kernel)) vert(uint32_t x, uint32_t y) { 78 float3 blurredPixel = 0; 79 int gi = 0; 80 uchar4 out; 81 if ((y > radius) && (y < (height - radius))) { 82 for (int r = -radius; r <= radius; r ++) { 83 float4 i = rsGetElementAt_float4(ScratchPixel2, x, y + r); 84 blurredPixel += i.xyz * gaussian[gi++]; 85 } 86 } else { 87 for (int r = -radius; r <= radius; r ++) { 88 int validH = rsClamp((int)y + r, (int)0, (int)(height - 1)); 89 float4 i = rsGetElementAt_float4(ScratchPixel2, x, validH); 90 blurredPixel += i.xyz * gaussian[gi++]; 91 } 92 } 93 94 out.xyz = convert_uchar3(clamp(blurredPixel, 0.f, 255.f)); 95 out.w = 0xff; 96 return out; 97 } 98 99 float4 __attribute__((kernel)) horz(uint32_t x, uint32_t y) { 100 float4 blurredPixel = 0; 101 int gi = 0; 102 if ((x > radius) && (x < (width - radius))) { 103 for (int r = -radius; r <= radius; r ++) { 104 float4 i = rsGetElementAt_float4(ScratchPixel1, x + r, y); 105 blurredPixel += i * gaussian[gi++]; 106 } 107 } else { 108 for (int r = -radius; r <= radius; r ++) { 109 // Stepping left and right away from the pixel 110 int validX = rsClamp((int)x + r, (int)0, (int)(width - 1)); 111 float4 i = rsGetElementAt_float4(ScratchPixel1, validX, y); 112 blurredPixel += i * gaussian[gi++]; 113 } 114 } 115 116 return blurredPixel; 117 } 118 119