1572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams/* 2572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams * Copyright (C) 2013 The Android Open Source Project 3572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams * 4572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams * Licensed under the Apache License, Version 2.0 (the "License"); 5572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams * you may not use this file except in compliance with the License. 6572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams * You may obtain a copy of the License at 7572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams * 8572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams * http://www.apache.org/licenses/LICENSE-2.0 9572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams * 10572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams * Unless required by applicable law or agreed to in writing, software 11572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams * distributed under the License is distributed on an "AS IS" BASIS, 12572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams * See the License for the specific language governing permissions and 14572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams * limitations under the License. 15572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams */ 16572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams 17572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams#include "ip.rsh" 18ab84c3968abce348c212bc9d466c534bc2a03cd6Jason Sams#pragma rs_fp_relaxed 19572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams 20572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsint height; 21572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsint width; 22572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic int radius; 23572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams 24572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsrs_allocation InPixel; 25572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsrs_allocation ScratchPixel1; 26572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsrs_allocation ScratchPixel2; 27572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams 28572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsconst int MAX_RADIUS = 25; 29572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams 30572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams// Store our coefficients here 31572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsstatic float gaussian[MAX_RADIUS * 2 + 1]; 32572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams 33572a5031a5d8602db0bec0b253428a034bd4dd59Jason Samsvoid setRadius(int rad) { 34572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams radius = rad; 35572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams // Compute gaussian weights for the blur 36572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams // e is the euler's number 37572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams float e = 2.718281828459045f; 38572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams float pi = 3.1415926535897932f; 39572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 ) 40572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams // x is of the form [-radius .. 0 .. radius] 41572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams // and sigma varies with radius. 42572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams // Based on some experimental radius values and sigma's 43572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams // we approximately fit sigma = f(radius) as 44572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams // sigma = radius * 0.4 + 0.6 45572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams // The larger the radius gets, the more our gaussian blur 46572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams // will resemble a box blur since with large sigma 47572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams // the gaussian curve begins to lose its shape 48572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams float sigma = 0.4f * (float)radius + 0.6f; 49572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams 50572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams // Now compute the coefficints 51572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams // We will store some redundant values to save some math during 52572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams // the blur calculations 53572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams // precompute some values 54572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma); 55572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams float coeff2 = - 1.0f / (2.0f * sigma * sigma); 56572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams 57572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams float normalizeFactor = 0.0f; 58572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams float floatR = 0.0f; 59572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams for (int r = -radius; r <= radius; r ++) { 60572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams floatR = (float)r; 61572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams gaussian[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2); 62572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams normalizeFactor += gaussian[r + radius]; 63572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams } 64572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams 65572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams //Now we need to normalize the weights because all our coefficients need to add up to one 66572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams normalizeFactor = 1.0f / normalizeFactor; 67572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams for (int r = -radius; r <= radius; r ++) { 68572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams floatR = (float)r; 69572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams gaussian[r + radius] *= normalizeFactor; 70572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams } 71572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams} 72572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams 73025b5f82971c431eb22df3c9d0f00b3cbe426bdbChris Wailesfloat4 RS_KERNEL copyIn(uchar4 in) { 74572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams return convert_float4(in); 75572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams} 76572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams 77025b5f82971c431eb22df3c9d0f00b3cbe426bdbChris Wailesuchar4 RS_KERNEL vert(uint32_t x, uint32_t y) { 78572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams float3 blurredPixel = 0; 79572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams int gi = 0; 80572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams uchar4 out; 81572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams if ((y > radius) && (y < (height - radius))) { 82572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams for (int r = -radius; r <= radius; r ++) { 83572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams float4 i = rsGetElementAt_float4(ScratchPixel2, x, y + r); 84572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams blurredPixel += i.xyz * gaussian[gi++]; 85572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams } 86572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams } else { 87572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams for (int r = -radius; r <= radius; r ++) { 88de235208fd6bcaa29c95404d990f7b5e212435f9Jean-Luc Brouillet int validH = clamp((int)y + r, (int)0, (int)(height - 1)); 89572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams float4 i = rsGetElementAt_float4(ScratchPixel2, x, validH); 90572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams blurredPixel += i.xyz * gaussian[gi++]; 91572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams } 92572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams } 93572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams 94572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams out.xyz = convert_uchar3(clamp(blurredPixel, 0.f, 255.f)); 95572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams out.w = 0xff; 96572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams return out; 97572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams} 98572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams 99025b5f82971c431eb22df3c9d0f00b3cbe426bdbChris Wailesfloat4 RS_KERNEL horz(uint32_t x, uint32_t y) { 100572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams float4 blurredPixel = 0; 101572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams int gi = 0; 102572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams if ((x > radius) && (x < (width - radius))) { 103572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams for (int r = -radius; r <= radius; r ++) { 104572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams float4 i = rsGetElementAt_float4(ScratchPixel1, x + r, y); 105572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams blurredPixel += i * gaussian[gi++]; 106572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams } 107572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams } else { 108572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams for (int r = -radius; r <= radius; r ++) { 109572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams // Stepping left and right away from the pixel 110de235208fd6bcaa29c95404d990f7b5e212435f9Jean-Luc Brouillet int validX = clamp((int)x + r, (int)0, (int)(width - 1)); 111572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams float4 i = rsGetElementAt_float4(ScratchPixel1, validX, y); 112572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams blurredPixel += i * gaussian[gi++]; 113572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams } 114572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams } 115572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams 116572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams return blurredPixel; 117572a5031a5d8602db0bec0b253428a034bd4dd59Jason Sams} 118