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