1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 * or implied. See the License for the specific language governing permissions and limitations under
12 * the License.
13 */
14
15package com.android.rs.test;
16
17import android.content.Context;
18import android.renderscript.Allocation;
19import android.renderscript.Element;
20import android.renderscript.RenderScript;
21import android.renderscript.ScriptGroup;
22import android.renderscript.Type;
23import android.util.Log;
24
25public class UT_script_group2_gatherscatter extends UnitTest {
26    private static final int ARRAY_SIZE = 256;
27
28    private static final String TAG = "ScriptGroup2 (GatherScatter)";
29
30    int[] mArray;
31
32    protected UT_script_group2_gatherscatter(RSTestCore rstc, Context ctx) {
33        super(rstc, TAG, ctx);
34    }
35
36    public void initializeGlobals(RenderScript RS, ScriptC_addup s) {
37        mArray = new int[ARRAY_SIZE * 4];
38
39        for (int i = 0; i < ARRAY_SIZE; i++) {
40            mArray[i * 4] = i * 7;
41            mArray[i * 4 + 1] = i * 7 + 1;
42            mArray[i * 4 + 2] = i * 7 + 2;
43            mArray[i * 4 + 3] = i * 7 + 3;
44        }
45    }
46
47    // This test tests ScriptGroup2 API for handling gather scatter operations
48    // on global allocations that are passed across kernels in a script group.
49    // The test sums up all elements in the input int4 array of size ARRAY_SIZE.
50    // To do so, it adds up the second half of the array to its first half using
51    // kernel function add() in addsup.rs, and then repeatedly applies the same
52    // kernel function to the shrinking result arrays until the result is a
53    // single int4 value.
54    // These steps are created as a script group by repeatedly adding the
55    // same kernel function, with the input of one kernel being the output of
56    // the previous added kernel function.
57    // Since the kernel function relies on rsGetElementAt to access the counterpart
58    // of the current element in the second half of the array, the compiler cannot
59    // fuse it with the other kernel that it dependes on.
60    // This test verifies an ScriptGroup2 implementation correctly handles such
61    // a case.
62    public void run() {
63        RenderScript pRS = RenderScript.create(mCtx);
64        ScriptC_addup s = new ScriptC_addup(pRS);
65        pRS.setMessageHandler(mRsMessage);
66        initializeGlobals(pRS, s);
67
68        Allocation input = Allocation.createSized(pRS, Element.I32_4(pRS), ARRAY_SIZE);
69        input.copyFrom(mArray);
70
71        ScriptGroup.Builder2 builder = new ScriptGroup.Builder2(pRS);
72
73        ScriptGroup.Input unbound = builder.addInput();
74
75        ScriptGroup.Closure c = null;
76        ScriptGroup.Future f = null;
77        int stride;
78        for (stride = ARRAY_SIZE / 2; stride >= 1; stride >>= 1) {
79            ScriptGroup.Binding binding;
80            if (f == null) {
81                binding = new ScriptGroup.Binding(s.getFieldID_a_in(), unbound);
82            } else {
83                binding = new ScriptGroup.Binding(s.getFieldID_a_in(), f);
84            }
85            c = builder.addKernel(s.getKernelID_add(),
86                    Type.createX(pRS, Element.I32_4(pRS), stride),
87                    new ScriptGroup.Binding(s.getFieldID_reduction_stride(), stride),
88                    binding);
89            f = c.getReturn();
90        }
91
92        ScriptGroup group = builder.create("Summation", c.getReturn());
93
94        if (c == null) {
95            return;
96        }
97
98        int[] a = new int[4];
99        ((Allocation) group.execute(input)[0]).copyTo(a);
100
101        pRS.finish();
102
103        group.destroy();
104        input.destroy();
105        s.destroy();
106        pRS.destroy();
107
108        boolean failed = false;
109        for (int i = 0; i < 4; i++) {
110            if (failed == false &&
111                    a[i] != ARRAY_SIZE * (ARRAY_SIZE - 1) * 7 / 2 + i * ARRAY_SIZE) {
112                Log.e(TAG, "a[" + i + "]=" + a[i] + ", should be " +
113                        (ARRAY_SIZE * (ARRAY_SIZE - 1) * 7 / 2 + i * ARRAY_SIZE));
114                failed = true;
115            }
116        }
117        if (failed) {
118            failTest();
119            return;
120        }
121        passTest();
122    }
123}
124