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