1 /*
2  * Copyright (C) 2011 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 
17 package android.renderscript.cts;
18 
19 import android.renderscript.RenderScript;
20 import android.renderscript.Allocation;
21 import android.renderscript.Element;
22 import android.renderscript.RSRuntimeException;
23 import android.util.Log;
24 
25 /**
26  * Base RenderScript test class. This class provides a message handler and a
27  * convenient way to wait for compute scripts to complete their execution.
28  */
29 public class RSBaseCompute extends RSBase {
30     RenderScript mRS;
31     protected int INPUTSIZE = 512;
32 
33     @Override
setUp()34     protected void setUp() throws Exception {
35         super.setUp();
36         mRS = RenderScript.create(mCtx);
37         mRS.setMessageHandler(mRsMessage);
38     }
39 
40     @Override
tearDown()41     protected void tearDown() throws Exception {
42         super.tearDown();
43     }
44 
checkArray(float[] ref, float[] out, int height, int refStride, int outStride, float ulpCount)45     public void checkArray(float[] ref, float[] out, int height, int refStride,
46              int outStride, float ulpCount) {
47         int minStride = refStride > outStride ? outStride : refStride;
48         for (int i = 0; i < height; i++) {
49             for (int j = 0; j < minStride; j++) {
50                 int refIdx = i * refStride + j;
51                 int outIdx = i * outStride + j;
52                 float ulp = Math.ulp(ref[refIdx]) * ulpCount;
53                 assertEquals("Incorrect value @ idx = " + i + " |",
54                         ref[refIdx],
55                         out[outIdx],
56                         ulp);
57             }
58         }
59     }
60 
checkArray(int[] ref, int[] out, int height, int refStride, int outStride)61     public void checkArray(int[] ref, int[] out, int height, int refStride,
62              int outStride) {
63         int minStride = refStride > outStride ? outStride : refStride;
64         for (int i = 0; i < height; i++) {
65             for (int j = 0; j < minStride; j++) {
66                 int refIdx = i * refStride + j;
67                 int outIdx = i * outStride + j;
68                 assertEquals("Incorrect value @ idx = " + i + " |",
69                         ref[refIdx],
70                         out[outIdx]);
71             }
72         }
73     }
74 
75     // TODO Is there a better way to do this
getElement(RenderScript rs, Element.DataType dataType, int size)76     protected Element getElement(RenderScript rs, Element.DataType dataType, int size) {
77         Element element = null;
78         if (size == 1) {
79             if (dataType == Element.DataType.FLOAT_64) {
80                 element = Element.F64(rs);
81             } else if (dataType == Element.DataType.FLOAT_32) {
82                 element = Element.F32(rs);
83             } else if (dataType == Element.DataType.FLOAT_16) {
84                 element = Element.F16(rs);
85             } else if (dataType == Element.DataType.SIGNED_64) {
86                 element = Element.I64(rs);
87             } else if (dataType == Element.DataType.UNSIGNED_64) {
88                 element = Element.U64(rs);
89             } else if (dataType == Element.DataType.SIGNED_32) {
90                 element = Element.I32(rs);
91             } else if (dataType == Element.DataType.UNSIGNED_32) {
92                 element = Element.U32(rs);
93             } else if (dataType == Element.DataType.SIGNED_16) {
94                 element = Element.I16(rs);
95             } else if (dataType == Element.DataType.UNSIGNED_16) {
96                 element = Element.U16(rs);
97             } else if (dataType == Element.DataType.SIGNED_8) {
98                 element = Element.I8(rs);
99             } else if (dataType == Element.DataType.UNSIGNED_8) {
100                 element = Element.U8(rs);
101             } else {
102                 android.util.Log.e("RenderscriptCTS", "Don't know how to create allocation of type" +
103                         dataType.toString());
104             }
105         } else {
106             element = Element.createVector(rs, dataType, size);
107         }
108         return element;
109     }
110 
createRandomAllocation(RenderScript rs, Element.DataType dataType, int size, long seed, boolean includeExtremes)111     protected Allocation createRandomAllocation(RenderScript rs, Element.DataType dataType,
112             int size, long seed, boolean includeExtremes) {
113         Element element = getElement(rs, dataType, size);
114         Allocation alloc = Allocation.createSized(rs, element, INPUTSIZE);
115         int width = (size == 3) ? 4 : size;
116         if (dataType == Element.DataType.FLOAT_64) {
117             double[] inArray = new double[INPUTSIZE * width];
118             // TODO The ranges for float is too small.  We need to accept a wider range of values.
119             double min = -4.0 * Math.PI;
120             double max = 4.0 * Math.PI;
121             RSUtils.genRandomDoubles(seed, min, max, inArray, includeExtremes);
122             alloc.copy1DRangeFrom(0, INPUTSIZE, inArray);
123         } else if (dataType == Element.DataType.FLOAT_32) {
124             float[] inArray = new float[INPUTSIZE * width];
125             // TODO The ranges for float is too small.  We need to accept a wider range of values.
126             float min = -4.0f * (float) Math.PI;
127             float max = 4.0f * (float) Math.PI;
128             RSUtils.genRandomFloats(seed, min, max, inArray, includeExtremes);
129             alloc.copy1DRangeFrom(0, INPUTSIZE, inArray);
130         } else if (dataType == Element.DataType.FLOAT_16) {
131             short[] inArray = new short[INPUTSIZE * width];
132             double min = -4.0 * Math.PI;
133             double max = 4.0 * Math.PI;
134             RSUtils.genRandomFloat16s(seed, min, max, inArray, includeExtremes);
135             alloc.copyFrom(inArray);
136         } else if (dataType == Element.DataType.SIGNED_64) {
137             long[] inArray = new long[INPUTSIZE * width];
138             RSUtils.genRandomLongs(seed, inArray, true, 63);
139             alloc.copy1DRangeFrom(0, INPUTSIZE, inArray);
140         } else if (dataType == Element.DataType.UNSIGNED_64) {
141             long[] inArray = new long[INPUTSIZE * width];
142             RSUtils.genRandomLongs(seed, inArray, false, 64);
143             alloc.copy1DRangeFrom(0, INPUTSIZE, inArray);
144         } else if (dataType == Element.DataType.SIGNED_32) {
145             int[] inArray = new int[INPUTSIZE * width];
146             RSUtils.genRandomInts(seed, inArray, true, 31);
147             alloc.copy1DRangeFrom(0, INPUTSIZE, inArray);
148         } else if (dataType == Element.DataType.UNSIGNED_32) {
149             int[] inArray = new int[INPUTSIZE * width];
150             RSUtils.genRandomInts(seed, inArray, false, 32);
151             alloc.copy1DRangeFrom(0, INPUTSIZE, inArray);
152         } else if (dataType == Element.DataType.SIGNED_16) {
153             short[] inArray = new short[INPUTSIZE * width];
154             RSUtils.genRandomShorts(seed, inArray, true, 15);
155             alloc.copy1DRangeFrom(0, INPUTSIZE, inArray);
156         } else if (dataType == Element.DataType.UNSIGNED_16) {
157             short[] inArray = new short[INPUTSIZE * width];
158             RSUtils.genRandomShorts(seed, inArray, false, 16);
159             alloc.copy1DRangeFrom(0, INPUTSIZE, inArray);
160         } else if (dataType == Element.DataType.SIGNED_8) {
161             byte[] inArray = new byte[INPUTSIZE * width];
162             RSUtils.genRandomBytes(seed, inArray, true, 7);
163             alloc.copy1DRangeFrom(0, INPUTSIZE, inArray);
164         } else if (dataType == Element.DataType.UNSIGNED_8) {
165             byte[] inArray = new byte[INPUTSIZE * width];
166             RSUtils.genRandomBytes(seed, inArray, true, 8);
167             alloc.copy1DRangeFrom(0, INPUTSIZE, inArray);
168         } else {
169             android.util.Log.e("RenderscriptCTS", "Don't know how to create allocation of type" +
170                     dataType.toString());
171         }
172         return alloc;
173     }
174 
createRandomFloatAllocation(RenderScript rs, Element.DataType dataType, int size, long seed, double minValue, double maxValue)175     protected Allocation createRandomFloatAllocation(RenderScript rs, Element.DataType dataType,
176             int size, long seed, double minValue, double maxValue) {
177         Element element = getElement(rs, dataType, size);
178         Allocation alloc = Allocation.createSized(rs, element, INPUTSIZE);
179         int width = (size == 3) ? 4 : size;
180         if (dataType == Element.DataType.FLOAT_64) {
181             double[] inArray = new double[INPUTSIZE * width];
182             RSUtils.genRandomDoubles(seed, minValue, maxValue, inArray, false);
183             alloc.copy1DRangeFrom(0, INPUTSIZE, inArray);
184         } else if (dataType == Element.DataType.FLOAT_32) {
185             float[] inArray = new float[INPUTSIZE * width];
186             RSUtils.genRandomFloats(seed, (float) minValue, (float) maxValue, inArray, false);
187             alloc.copy1DRangeFrom(0, INPUTSIZE, inArray);
188         } else if (dataType == Element.DataType.FLOAT_16) {
189             short[] inArray = new short[INPUTSIZE * width];
190             RSUtils.genRandomFloat16s(seed, minValue, maxValue, inArray, false);
191             alloc.copy1DRangeFrom(0, INPUTSIZE, inArray);
192         } else {
193             android.util.Log.e("RenderscriptCTS",
194                                "Don't know how to create a random float allocation for " +
195                                            dataType.toString());
196         }
197         return alloc;
198     }
199 
createRandomIntegerAllocation(RenderScript rs, Element.DataType dataType, int size, long seed, boolean signed, int numberOfBits)200     protected Allocation createRandomIntegerAllocation(RenderScript rs, Element.DataType dataType,
201             int size, long seed, boolean signed, int numberOfBits) {
202         Element element = getElement(rs, dataType, size);
203         Allocation alloc = Allocation.createSized(rs, element, INPUTSIZE);
204         int width = (size == 3) ? 4 : size;
205         if (dataType == Element.DataType.SIGNED_64 ||
206                 dataType == Element.DataType.UNSIGNED_64) {
207             long[] inArray = new long[INPUTSIZE * width];
208             RSUtils.genRandomLongs(seed, inArray, signed, numberOfBits);
209             alloc.copy1DRangeFrom(0, INPUTSIZE, inArray);
210         } else
211         if (dataType == Element.DataType.SIGNED_32 ||
212                 dataType == Element.DataType.UNSIGNED_32) {
213             int[] inArray = new int[INPUTSIZE * width];
214             RSUtils.genRandomInts(seed, inArray, signed, numberOfBits);
215             alloc.copy1DRangeFrom(0, INPUTSIZE, inArray);
216         } else if (dataType == Element.DataType.SIGNED_16 ||
217                 dataType == Element.DataType.UNSIGNED_16) {
218             short[] inArray = new short[INPUTSIZE * width];
219             RSUtils.genRandomShorts(seed, inArray, signed, numberOfBits);
220             alloc.copy1DRangeFrom(0, INPUTSIZE, inArray);
221         } else if (dataType == Element.DataType.SIGNED_8 ||
222                 dataType == Element.DataType.UNSIGNED_8) {
223             byte[] inArray = new byte[INPUTSIZE * width];
224             RSUtils.genRandomBytes(seed, inArray, signed, numberOfBits);
225             alloc.copy1DRangeFrom(0, INPUTSIZE, inArray);
226         } else {
227             android.util.Log.e("RenderscriptCTS",
228                                "Don't know how to create an integer allocation of type" +
229                                            dataType.toString());
230         }
231         return alloc;
232     }
233 
enforceOrdering( Allocation minAlloc, Allocation maxAlloc)234     protected <T> void enforceOrdering(/*RenderScript rs,*/ Allocation minAlloc, Allocation maxAlloc) {
235         Element element = minAlloc.getElement();
236         int stride = element.getVectorSize();
237         if (stride == 3) {
238             stride = 4;
239         }
240         int size = INPUTSIZE * stride;
241         Element.DataType dataType = element.getDataType();
242         if (dataType == Element.DataType.FLOAT_64) {
243             double[] minArray = new double[size];
244             double[] maxArray = new double[size];
245             minAlloc.copyTo(minArray);
246             maxAlloc.copyTo(maxArray);
247             for (int i = 0; i < size; i++) {
248                 if (minArray[i] > maxArray[i]) {
249                     double temp = minArray[i];
250                     minArray[i] = maxArray[i];
251                     maxArray[i] = temp;
252                 }
253             }
254             minAlloc.copyFrom(minArray);
255             maxAlloc.copyFrom(maxArray);
256         } else
257         if (dataType == Element.DataType.FLOAT_32) {
258             float[] minArray = new float[size];
259             float[] maxArray = new float[size];
260             minAlloc.copyTo(minArray);
261             maxAlloc.copyTo(maxArray);
262             for (int i = 0; i < size; i++) {
263                 if (minArray[i] > maxArray[i]) {
264                     float temp = minArray[i];
265                     minArray[i] = maxArray[i];
266                     maxArray[i] = temp;
267                 }
268             }
269             minAlloc.copyFrom(minArray);
270             maxAlloc.copyFrom(maxArray);
271         } else if (dataType == Element.DataType.FLOAT_16) {
272             short[] minArray = new short[size];
273             short[] maxArray = new short[size];
274             minAlloc.copyTo(minArray);
275             maxAlloc.copyTo(maxArray);
276             for (int i = 0; i < size; i++) {
277                 double minValue = Float16Utils.convertFloat16ToDouble(minArray[i]);
278                 double maxValue = Float16Utils.convertFloat16ToDouble(maxArray[i]);
279                 if (minValue > maxValue) {
280                     short temp = minArray[i];
281                     minArray[i] = maxArray[i];
282                     maxArray[i] = temp;
283                 }
284             }
285             minAlloc.copyFrom(minArray);
286             maxAlloc.copyFrom(maxArray);
287         } else if (dataType == Element.DataType.SIGNED_64) {
288             long[] minArray = new long[size];
289             long[] maxArray = new long[size];
290             minAlloc.copyTo(minArray);
291             maxAlloc.copyTo(maxArray);
292             for (int i = 0; i < size; i++) {
293                 if (minArray[i] > maxArray[i]) {
294                     long temp = minArray[i];
295                     minArray[i] = maxArray[i];
296                     maxArray[i] = temp;
297                 }
298             }
299             minAlloc.copyFrom(minArray);
300             maxAlloc.copyFrom(maxArray);
301         } else if (dataType == Element.DataType.UNSIGNED_64) {
302             long[] minArray = new long[size];
303             long[] maxArray = new long[size];
304             minAlloc.copyTo(minArray);
305             maxAlloc.copyTo(maxArray);
306             for (int i = 0; i < size; i++) {
307                 if (RSUtils.compareUnsignedLong(minArray[i], maxArray[i]) > 0) {
308                     long temp = minArray[i];
309                     minArray[i] = maxArray[i];
310                     maxArray[i] = temp;
311                 }
312             }
313             minAlloc.copyFrom(minArray);
314             maxAlloc.copyFrom(maxArray);
315         } else if (dataType == Element.DataType.SIGNED_32) {
316             int[] minArray = new int[size];
317             int[] maxArray = new int[size];
318             minAlloc.copyTo(minArray);
319             maxAlloc.copyTo(maxArray);
320             for (int i = 0; i < size; i++) {
321                 if (minArray[i] > maxArray[i]) {
322                     int temp = minArray[i];
323                     minArray[i] = maxArray[i];
324                     maxArray[i] = temp;
325                 }
326             }
327             minAlloc.copyFrom(minArray);
328             maxAlloc.copyFrom(maxArray);
329         } else if (dataType == Element.DataType.UNSIGNED_32) {
330             int[] minArray = new int[size];
331             int[] maxArray = new int[size];
332             minAlloc.copyTo(minArray);
333             maxAlloc.copyTo(maxArray);
334             for (int i = 0; i < size; i++) {
335                 long min = minArray[i] &0xffffffffl;
336                 long max = maxArray[i] &0xffffffffl;
337                 if (min > max) {
338                     minArray[i] = (int) max;
339                     maxArray[i] = (int) min;
340                 }
341             }
342             minAlloc.copyFrom(minArray);
343             maxAlloc.copyFrom(maxArray);
344         } else if (dataType == Element.DataType.SIGNED_16) {
345             short[] minArray = new short[size];
346             short[] maxArray = new short[size];
347             minAlloc.copyTo(minArray);
348             maxAlloc.copyTo(maxArray);
349             for (int i = 0; i < size; i++) {
350                 if (minArray[i] > maxArray[i]) {
351                     short temp = minArray[i];
352                     minArray[i] = maxArray[i];
353                     maxArray[i] = temp;
354                 }
355             }
356             minAlloc.copyFrom(minArray);
357             maxAlloc.copyFrom(maxArray);
358         } else if (dataType == Element.DataType.UNSIGNED_16) {
359             short[] minArray = new short[size];
360             short[] maxArray = new short[size];
361             minAlloc.copyTo(minArray);
362             maxAlloc.copyTo(maxArray);
363             for (int i = 0; i < size; i++) {
364                 int min = minArray[i] &0xffff;
365                 int max = maxArray[i] &0xffff;
366                 if (min > max) {
367                     minArray[i] = (short) max;
368                     maxArray[i] = (short) min;
369                 }
370             }
371             minAlloc.copyFrom(minArray);
372             maxAlloc.copyFrom(maxArray);
373         } else if (dataType == Element.DataType.SIGNED_8) {
374             byte[] minArray = new byte[size];
375             byte[] maxArray = new byte[size];
376             minAlloc.copyTo(minArray);
377             maxAlloc.copyTo(maxArray);
378             for (int i = 0; i < size; i++) {
379                 if (minArray[i] > maxArray[i]) {
380                     byte temp = minArray[i];
381                     minArray[i] = maxArray[i];
382                     maxArray[i] = temp;
383                 }
384             }
385             minAlloc.copyFrom(minArray);
386             maxAlloc.copyFrom(maxArray);
387         } else if (dataType == Element.DataType.UNSIGNED_8) {
388             byte[] minArray = new byte[size];
389             byte[] maxArray = new byte[size];
390             minAlloc.copyTo(minArray);
391             maxAlloc.copyTo(maxArray);
392             for (int i = 0; i < size; i++) {
393                 int min = minArray[i] &0xff;
394                 int max = maxArray[i] &0xff;
395                 if (min > max) {
396                     minArray[i] = (byte) max;
397                     maxArray[i] = (byte) min;
398                 }
399             }
400             minAlloc.copyFrom(minArray);
401             maxAlloc.copyFrom(maxArray);
402         } else {
403             android.util.Log.e("RenderscriptCTS", "Ordering not supported for " +
404                     dataType.toString());
405         }
406     }
407 
forEach(int testId, Allocation mIn, Allocation mOut)408     public void forEach(int testId, Allocation mIn, Allocation mOut) throws RSRuntimeException {
409         // Intentionally empty... subclass will likely define only one, but not both
410     }
411 
forEach(int testId, Allocation mIn)412     public void forEach(int testId, Allocation mIn) throws RSRuntimeException {
413         // Intentionally empty... subclass will likely define only one, but not both
414     }
415 
appendVariableToMessage(StringBuilder message, int value)416     protected void appendVariableToMessage(StringBuilder message, int value) {
417         message.append(String.format("%d {%x}", value, value));
418     }
419 
appendVariableToMessage(StringBuilder message, float value)420     protected void appendVariableToMessage(StringBuilder message, float value) {
421         message.append(String.format("%14.8g {%8x} %15a", value,
422                         Float.floatToRawIntBits(value), value));
423     }
424 
appendVariableToMessage(StringBuilder message, double value)425     protected void appendVariableToMessage(StringBuilder message, double value) {
426         message.append(String.format("%24.8g {%16x} %31a", value,
427                         Double.doubleToRawLongBits(value), value));
428     }
429 
appendVariableToMessage(StringBuilder message, Target.Floaty value)430     protected void appendVariableToMessage(StringBuilder message, Target.Floaty value) {
431         message.append(value.toString());
432     }
433 }
434