1/*
2 * Copyright (C) 2015 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
17package android.support.v8.renderscript;
18
19import android.util.Log;
20
21/**
22 * Intrinsic Histogram filter.
23 *
24 *
25 **/
26public class ScriptIntrinsicHistogram extends ScriptIntrinsic {
27    private Allocation mOut;
28    // API level for the intrinsic
29    private static final int INTRINSIC_API_LEVEL = 19;
30
31    protected ScriptIntrinsicHistogram(long id, RenderScript rs) {
32        super(id, rs);
33    }
34
35    /**
36     * Create an intrinsic for calculating the histogram of an uchar
37     * or uchar4 image.
38     *
39     * Supported elements types are
40     * {@link Element#U8_4}, {@link Element#U8_3},
41     * {@link Element#U8_2}, {@link Element#U8}
42     *
43     * @param rs The RenderScript context
44     * @param e Element type for inputs
45     *
46     * @return ScriptIntrinsicHistogram
47     */
48    public static ScriptIntrinsicHistogram create(RenderScript rs, Element e) {
49        if ((!e.isCompatible(Element.U8_4(rs))) &&
50            (!e.isCompatible(Element.U8_3(rs))) &&
51            (!e.isCompatible(Element.U8_2(rs))) &&
52            (!e.isCompatible(Element.U8(rs)))) {
53            throw new RSIllegalArgumentException("Unsuported element type.");
54        }
55        long id;
56        boolean mUseIncSupp = rs.isUseNative() &&
57                              android.os.Build.VERSION.SDK_INT < INTRINSIC_API_LEVEL;
58
59        id = rs.nScriptIntrinsicCreate(9, e.getID(rs), mUseIncSupp);
60
61        ScriptIntrinsicHistogram si = new ScriptIntrinsicHistogram(id, rs);
62        si.setIncSupp(mUseIncSupp);
63        return si;
64    }
65
66    /**
67     * Process an input buffer and place the histogram into the
68     * output allocation. The output allocation may be a narrower
69     * vector size than the input. In this case the vector size of
70     * the output is used to determine how many of the input
71     * channels are used in the computation. This is useful if you
72     * have an RGBA input buffer but only want the histogram for
73     * RGB.
74     *
75     * 1D and 2D input allocations are supported.
76     *
77     * @param ain The input image
78     */
79    public void forEach(Allocation ain) {
80        forEach(ain, null);
81    }
82
83    /**
84     * Process an input buffer and place the histogram into the
85     * output allocation. The output allocation may be a narrower
86     * vector size than the input. In this case the vector size of
87     * the output is used to determine how many of the input
88     * channels are used in the computation. This is useful if you
89     * have an RGBA input buffer but only want the histogram for
90     * RGB.
91     *
92     * 1D and 2D input allocations are supported.
93     *
94     * @param ain The input image
95     * @param opt LaunchOptions for clipping
96     */
97    public void forEach(Allocation ain, Script.LaunchOptions opt) {
98        if (ain.getType().getElement().getVectorSize() <
99            mOut.getType().getElement().getVectorSize()) {
100
101            throw new RSIllegalArgumentException(
102                "Input vector size must be >= output vector size.");
103        }
104        if (!ain.getType().getElement().isCompatible(Element.U8(mRS)) &&
105            !ain.getType().getElement().isCompatible(Element.U8_2(mRS)) &&
106            !ain.getType().getElement().isCompatible(Element.U8_3(mRS)) &&
107            !ain.getType().getElement().isCompatible(Element.U8_4(mRS))) {
108            throw new RSIllegalArgumentException("Input type must be U8, U8_1, U8_2 or U8_4.");
109        }
110
111        forEach(0, ain, null, null, opt);
112    }
113
114
115
116    /**
117     * Set the coefficients used for the RGBA to Luminocity
118     * calculation. The default is {0.299f, 0.587f, 0.114f, 0.f}.
119     *
120     * Coefficients must be >= 0 and sum to 1.0 or less.
121     *
122     * @param r Red coefficient
123     * @param g Green coefficient
124     * @param b Blue coefficient
125     * @param a Alpha coefficient
126     */
127    public void setDotCoefficients(float r, float g, float b, float a) {
128        if ((r < 0.f) || (g < 0.f) || (b < 0.f) || (a < 0.f)) {
129            throw new RSIllegalArgumentException("Coefficient may not be negative.");
130        }
131        if ((r + g + b + a) > 1.f) {
132            throw new RSIllegalArgumentException("Sum of coefficients must be 1.0 or less.");
133        }
134
135        FieldPacker fp = new FieldPacker(16);
136        fp.addF32(r);
137        fp.addF32(g);
138        fp.addF32(b);
139        fp.addF32(a);
140        setVar(0, fp);
141    }
142
143    /**
144     * Set the output of the histogram.  32 bit integer types are
145     * supported.
146     *
147     * @param aout The output allocation
148     */
149    public void setOutput(Allocation aout) {
150        mOut = aout;
151        if (mOut.getType().getElement() != Element.U32(mRS) &&
152            mOut.getType().getElement() != Element.U32_2(mRS) &&
153            mOut.getType().getElement() != Element.U32_3(mRS) &&
154            mOut.getType().getElement() != Element.U32_4(mRS) &&
155            mOut.getType().getElement() != Element.I32(mRS) &&
156            mOut.getType().getElement() != Element.I32_2(mRS) &&
157            mOut.getType().getElement() != Element.I32_3(mRS) &&
158            mOut.getType().getElement() != Element.I32_4(mRS)) {
159
160            throw new RSIllegalArgumentException("Output type must be U32 or I32.");
161        }
162        if ((mOut.getType().getX() != 256) ||
163            (mOut.getType().getY() != 0) ||
164            mOut.getType().hasMipmaps() ||
165            (mOut.getType().getYuv() != 0)) {
166
167            throw new RSIllegalArgumentException("Output must be 1D, 256 elements.");
168        }
169        setVar(1, aout);
170    }
171
172
173    /**
174     * Process an input buffer and place the histogram into the
175     * output allocation. The dot product of the input channel and
176     * the coefficients from 'setDotCoefficients' are used to
177     * calculate the output values.
178     *
179     * 1D and 2D input allocations are supported.
180     *
181     * @param ain The input image
182     */
183    public void forEach_Dot(Allocation ain) {
184        forEach_Dot(ain, null);
185    }
186
187    /**
188     * Process an input buffer and place the histogram into the
189     * output allocation. The dot product of the input channel and
190     * the coefficients from 'setDotCoefficients' are used to
191     * calculate the output values.
192     *
193     * 1D and 2D input allocations are supported.
194     *
195     * @param ain The input image
196     * @param opt LaunchOptions for clipping
197     */
198    public void forEach_Dot(Allocation ain, Script.LaunchOptions opt) {
199        if (mOut.getType().getElement().getVectorSize() != 1) {
200            throw new RSIllegalArgumentException("Output vector size must be one.");
201        }
202        if (!ain.getType().getElement().isCompatible(Element.U8(mRS)) &&
203            !ain.getType().getElement().isCompatible(Element.U8_2(mRS)) &&
204            !ain.getType().getElement().isCompatible(Element.U8_3(mRS)) &&
205            !ain.getType().getElement().isCompatible(Element.U8_4(mRS))) {
206            throw new RSIllegalArgumentException("Input type must be U8, U8_1, U8_2 or U8_4.");
207        }
208
209        forEach(1, ain, null, null, opt);
210    }
211
212
213
214    /**
215     * Get a KernelID for this intrinsic kernel.
216     *
217     * @return Script.KernelID The KernelID object.
218     */
219    public Script.KernelID getKernelID_Separate() {
220        return createKernelID(0, 3, null, null);
221    }
222
223    /**
224     * Get a FieldID for the input field of this intrinsic.
225     *
226     * @return Script.FieldID The FieldID object.
227     */
228    public Script.FieldID getFieldID_Input() {
229        return createFieldID(1, null);
230    }
231}
232
233