| /* |
| * Copyright (C) 2011-2012 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.renderscript.cts; |
| |
| import android.graphics.Bitmap; |
| import android.renderscript.Allocation; |
| import android.renderscript.AllocationAdapter; |
| import android.renderscript.Allocation.MipmapControl; |
| import android.renderscript.Element; |
| import android.renderscript.RSIllegalArgumentException; |
| import android.renderscript.RSInvalidStateException; |
| import android.renderscript.Type; |
| import android.renderscript.Type.Builder; |
| |
| import android.renderscript.ScriptIntrinsicColorMatrix; |
| import android.renderscript.ScriptIntrinsicConvolve3x3; |
| import android.renderscript.ScriptGroup; |
| import android.renderscript.Matrix4f; |
| import android.util.Log; |
| |
| public class ScriptGroupTest extends RSBaseCompute { |
| |
| private static final String TAG = "ScriptGroupTest"; |
| private static final int ARRAY_SIZE = 256; |
| static int bDimX = 48; |
| static int bDimY = 8; |
| |
| public void testScriptGroupSingleKernel() { |
| ScriptGroup group; |
| |
| Type connect = new Type.Builder(mRS, Element.U8_4(mRS)).setX(bDimX).setY(bDimY).create(); |
| |
| ScriptIntrinsicColorMatrix mColorMatrix; |
| |
| mColorMatrix = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS)); |
| |
| Allocation a1_copy, a2_copy; |
| a1_copy = Allocation.createTyped(mRS, connect); |
| a2_copy = Allocation.createTyped(mRS, connect); |
| |
| Matrix4f m = new Matrix4f(); |
| m.set(1, 0, 0.2f); |
| m.set(1, 1, 0.9f); |
| m.set(1, 2, 0.2f); |
| mColorMatrix.setColorMatrix(m); |
| |
| ScriptGroup.Builder b = new ScriptGroup.Builder(mRS); |
| b.addKernel(mColorMatrix.getKernelID()); |
| group = b.create(); |
| |
| group.setInput(mColorMatrix.getKernelID(), a1_copy); |
| group.setOutput(mColorMatrix.getKernelID(), a2_copy); |
| |
| group.execute(); |
| } |
| |
| public void testScriptGroupDisconnectedKernel() { |
| ScriptGroup group; |
| |
| Type connect = new Type.Builder(mRS, Element.U8_4(mRS)).setX(bDimX).setY(bDimY).create(); |
| |
| ScriptIntrinsicColorMatrix mColorMatrix, mColorMatrix2; |
| |
| mColorMatrix = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS)); |
| mColorMatrix2 = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS)); |
| |
| Allocation a1_copy, a2_copy; |
| |
| a1_copy = Allocation.createTyped(mRS, connect); |
| a2_copy = Allocation.createTyped(mRS, connect); |
| |
| Matrix4f m = new Matrix4f(); |
| m.set(1, 0, 0.2f); |
| m.set(1, 1, 0.9f); |
| m.set(1, 2, 0.2f); |
| mColorMatrix.setColorMatrix(m); |
| mColorMatrix2.setColorMatrix(m); |
| |
| ScriptGroup.Builder b = new ScriptGroup.Builder(mRS); |
| b.addKernel(mColorMatrix.getKernelID()); |
| b.addKernel(mColorMatrix2.getKernelID()); |
| try { |
| group = b.create(); |
| fail("should throw RSInvalidStateException."); |
| } catch (RSInvalidStateException e) { |
| |
| } |
| } |
| |
| |
| public void testScriptGroupFieldConnection() { |
| ScriptGroup group; |
| |
| Type connect = new Type.Builder(mRS, Element.U8_4(mRS)).setX(bDimX).setY(bDimY).create(); |
| |
| ScriptIntrinsicConvolve3x3 mConvolve3x3; |
| ScriptIntrinsicColorMatrix mColorMatrix; |
| |
| mConvolve3x3 = ScriptIntrinsicConvolve3x3.create(mRS, Element.U8_4(mRS)); |
| mColorMatrix = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS)); |
| |
| Allocation a1_copy, a2_copy; |
| a1_copy = Allocation.createTyped(mRS, connect); |
| a2_copy = Allocation.createTyped(mRS, connect); |
| |
| float f[] = new float[9]; |
| f[0] = 0.f; f[1] = -1.f; f[2] = 0.f; |
| f[3] = -1.f; f[4] = 5.f; f[5] = -1.f; |
| f[6] = 0.f; f[7] = -1.f; f[8] = 0.f; |
| |
| mConvolve3x3.setCoefficients(f); |
| |
| Matrix4f m = new Matrix4f(); |
| m.set(1, 0, 0.2f); |
| m.set(1, 1, 0.9f); |
| m.set(1, 2, 0.2f); |
| mColorMatrix.setColorMatrix(m); |
| |
| ScriptGroup.Builder b = new ScriptGroup.Builder(mRS); |
| b.addKernel(mColorMatrix.getKernelID()); |
| b.addKernel(mConvolve3x3.getKernelID()); |
| b.addConnection(connect, mColorMatrix.getKernelID(), mConvolve3x3.getFieldID_Input()); |
| group = b.create(); |
| |
| group.setInput(mColorMatrix.getKernelID(), a1_copy); |
| group.setOutput(mConvolve3x3.getKernelID(), a2_copy); |
| |
| group.execute(); |
| |
| } |
| |
| public void testScriptGroupDisconnectedDAG() { |
| ScriptGroup group; |
| |
| Type connect = new Type.Builder(mRS, Element.U8_4(mRS)).setX(bDimX).setY(bDimY).create(); |
| |
| ScriptIntrinsicConvolve3x3 mConvolve3x3, mConvolve3x32; |
| ScriptIntrinsicColorMatrix mColorMatrix, mColorMatrix2; |
| |
| mConvolve3x3 = ScriptIntrinsicConvolve3x3.create(mRS, Element.U8_4(mRS)); |
| mConvolve3x32 = ScriptIntrinsicConvolve3x3.create(mRS, Element.U8_4(mRS)); |
| mColorMatrix = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS)); |
| mColorMatrix2 = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS)); |
| |
| Allocation a1_copy, a2_copy; |
| a1_copy = Allocation.createTyped(mRS, connect); |
| a2_copy = Allocation.createTyped(mRS, connect); |
| |
| float f[] = new float[9]; |
| f[0] = 0.f; f[1] = -1.f; f[2] = 0.f; |
| f[3] = -1.f; f[4] = 5.f; f[5] = -1.f; |
| f[6] = 0.f; f[7] = -1.f; f[8] = 0.f; |
| |
| mConvolve3x3.setCoefficients(f); |
| mConvolve3x32.setCoefficients(f); |
| |
| Matrix4f m = new Matrix4f(); |
| m.set(1, 0, 0.2f); |
| m.set(1, 1, 0.9f); |
| m.set(1, 2, 0.2f); |
| mColorMatrix.setColorMatrix(m); |
| mColorMatrix2.setColorMatrix(m); |
| |
| ScriptGroup.Builder b = new ScriptGroup.Builder(mRS); |
| b.addKernel(mColorMatrix.getKernelID()); |
| b.addKernel(mColorMatrix2.getKernelID()); |
| b.addKernel(mConvolve3x3.getKernelID()); |
| b.addKernel(mConvolve3x32.getKernelID()); |
| b.addConnection(connect, mColorMatrix.getKernelID(), mConvolve3x3.getFieldID_Input()); |
| b.addConnection(connect, mColorMatrix2.getKernelID(), mConvolve3x32.getFieldID_Input()); |
| try { |
| group = b.create(); |
| fail("RSInvalidStateException expected"); |
| } catch (RSInvalidStateException e) { |
| |
| } |
| |
| } |
| |
| public void testScriptGroupTorture() { |
| ScriptGroup group; |
| |
| int[] result = new int[1]; |
| |
| bDimX = 1; |
| |
| Type connect = new Type.Builder(mRS, Element.I32(mRS)).setX(bDimX).create(); |
| Type compareType = new Type.Builder(mRS, Element.I32(mRS)).create(); |
| |
| ScriptC_scriptgroup node1, node2, node3, node4, node5, compare; |
| node1 = new ScriptC_scriptgroup(mRS); |
| node2 = new ScriptC_scriptgroup(mRS); |
| node3 = new ScriptC_scriptgroup(mRS); |
| node4 = new ScriptC_scriptgroup(mRS); |
| node5 = new ScriptC_scriptgroup(mRS); |
| |
| compare = new ScriptC_scriptgroup(mRS); |
| |
| Allocation in1, in2, out, resultAlloc; |
| in1 = Allocation.createTyped(mRS, connect); |
| in2 = Allocation.createTyped(mRS, connect); |
| |
| out = Allocation.createTyped(mRS, connect); |
| resultAlloc = Allocation.createTyped(mRS, compareType); |
| |
| node1.set_memset_toValue(1); |
| node1.forEach_memset(in1); |
| node1.set_memset_toValue(2); |
| node1.forEach_memset(in2); |
| |
| node1.set_arith_operation(2); |
| node2.set_arith_operation(1); |
| node3.set_arith_operation(0); |
| node4.set_arith_operation(0); |
| node5.set_arith_operation(1); |
| |
| node3.set_arith_use_rs_allocation(1); |
| node4.set_arith_use_rs_allocation(1); |
| |
| node1.set_arith_value(5); |
| node2.set_arith_value(3); |
| node5.set_arith_value(7); |
| |
| ScriptGroup.Builder b = new ScriptGroup.Builder(mRS); |
| b.addKernel(node1.getKernelID_arith()); |
| b.addKernel(node2.getKernelID_arith()); |
| b.addKernel(node3.getKernelID_arith()); |
| b.addKernel(node4.getKernelID_arith()); |
| b.addKernel(node5.getKernelID_arith()); |
| |
| b.addConnection(connect, node1.getKernelID_arith(), node2.getKernelID_arith()); |
| b.addConnection(connect, node1.getKernelID_arith(), node3.getFieldID_arith_rs_input()); |
| b.addConnection(connect, node2.getKernelID_arith(), node4.getFieldID_arith_rs_input()); |
| b.addConnection(connect, node3.getKernelID_arith(), node4.getKernelID_arith()); |
| b.addConnection(connect, node4.getKernelID_arith(), node5.getKernelID_arith()); |
| |
| group = b.create(); |
| group.setInput(node1.getKernelID_arith(), in1); |
| group.setInput(node3.getKernelID_arith(), in2); |
| |
| group.setOutput(node5.getKernelID_arith(), out); |
| |
| group.execute(); |
| |
| mRS.finish(); |
| |
| compare.set_compare_value(2); |
| compare.forEach_compare(out); |
| compare.forEach_getCompareResult(resultAlloc); |
| resultAlloc.copyTo(result); |
| assertTrue(result[0] == 2); |
| } |
| |
| /** |
| * Tests a case where a shared global variable is updated by the first kernel in a group, |
| * but then read by a subsequent kernel. |
| * |
| * The test ensures that we don't accidentally apply any fusion optimizations to the kernel |
| * pair, since there is a potential dependency that crosses the kernel cell boundary. |
| */ |
| public void testScriptGroupSharedGlobal() { |
| Type i32 = new Type.Builder(mRS, Element.I32(mRS)).setX(1).create(); |
| Type u32 = new Type.Builder(mRS, Element.U32(mRS)).setX(2).create(); |
| |
| Allocation aFailed = Allocation.createTyped(mRS, i32); |
| Allocation aSharedInt = Allocation.createTyped(mRS, i32); |
| |
| ScriptC_group1 mG1 = new ScriptC_group1(mRS); |
| ScriptC_group2 mG2 = new ScriptC_group2(mRS); |
| |
| mG1.set_aSharedInt(aSharedInt); |
| mG2.set_aSharedInt(aSharedInt); |
| mG2.set_aFailed(aFailed); |
| |
| int [] Failed = new int [1]; |
| Failed[0] = 0; |
| aFailed.copyFrom(Failed); |
| |
| ScriptGroup.Builder b = new ScriptGroup.Builder(mRS); |
| |
| // Writes to aSharedInt[x] in the kernel. |
| b.addKernel(mG1.getKernelID_setSharedInt()); |
| // Reads aSharedInt[1] to verify it is -5. |
| b.addKernel(mG2.getKernelID_getSharedInt()); |
| // If we fuse mG1/mG2, we won't see the update to the aSharedInt[1] during mG2 for x == 0. |
| // The update is only visible if we correctly identify the dependency and execute all of |
| // mG1 before starting on mG2. |
| b.addConnection(u32, mG1.getKernelID_setSharedInt(), mG2.getKernelID_getSharedInt()); |
| ScriptGroup group = b.create(); |
| group.execute(); |
| |
| mG2.invoke_verify(); |
| aFailed.copyTo(Failed); |
| if (Failed[0] != 0) { |
| FoundError = true; |
| } |
| |
| checkForErrors(); |
| } |
| |
| /** |
| * Tests that kernel-to-kernel dependency via input/output is handled correctly |
| */ |
| public void testBuilder2PointWiseKernelToKernelDependency() { |
| ScriptC_increment s_inc = new ScriptC_increment(mRS); |
| ScriptC_double s_double = new ScriptC_double(mRS); |
| mRS.setMessageHandler(mRsMessage); |
| |
| int[] array = new int[ARRAY_SIZE * 4]; |
| |
| for (int i = 0; i < ARRAY_SIZE * 4; i++) { |
| array[i] = i; |
| } |
| |
| Allocation input = Allocation.createSized(mRS, Element.I32_4(mRS), ARRAY_SIZE); |
| input.copyFrom(array); |
| |
| ScriptGroup.Builder2 builder = new ScriptGroup.Builder2(mRS); |
| |
| ScriptGroup.Input unbound = builder.addInput(); |
| |
| Type connectType = Type.createX(mRS, Element.I32_4(mRS), ARRAY_SIZE); |
| |
| ScriptGroup.Closure c0 = |
| builder.addKernel(s_inc.getKernelID_increment(), |
| connectType, |
| unbound); |
| |
| ScriptGroup.Closure c1 = |
| builder.addKernel(s_double.getKernelID_doubleKernel(), |
| connectType, |
| c0.getReturn()); |
| |
| ScriptGroup group = builder.create("IncAndDbl", c1.getReturn()); |
| |
| int[] a = new int[ARRAY_SIZE * 4]; |
| ((Allocation)group.execute(input)[0]).copyTo(a); |
| |
| mRS.finish(); |
| |
| boolean failed = false; |
| for (int i = 0; i < ARRAY_SIZE * 4; i++) { |
| if (a[i] != (i+1) * 2) { |
| Log.e(TAG, "a["+i+"]="+a[i]+", should be "+ ((i+1) * 2)); |
| failed = true; |
| } |
| } |
| |
| assertTrue(!failed); |
| } |
| |
| /** |
| * Tests that kernel-to-kernel dependency via global allocations is handled correctly |
| */ |
| public void testBuilder2GatherScatterAcrossKernelsViaGlobals() { |
| ScriptC_reduction s = new ScriptC_reduction(mRS); |
| |
| int[] array = new int[ARRAY_SIZE * 4]; |
| |
| for (int i = 0; i < ARRAY_SIZE; i++) { |
| array[i*4] = i * 7; |
| array[i*4 + 1] = i * 7; |
| array[i*4 + 2] = i * 7; |
| array[i*4 + 3] = i * 7; |
| } |
| |
| Allocation input = Allocation.createSized(mRS, Element.I32_4(mRS), ARRAY_SIZE); |
| input.copyFrom(array); |
| |
| ScriptGroup.Builder2 builder = new ScriptGroup.Builder2(mRS); |
| |
| ScriptGroup.Input unbound = builder.addInput(); |
| |
| ScriptGroup.Closure c = null; |
| ScriptGroup.Binding b2 = new ScriptGroup.Binding(s.getFieldID_a(), unbound); |
| for (int stride = ARRAY_SIZE / 2; stride >= 1; stride >>= 1) { |
| ScriptGroup.Binding b1 = new ScriptGroup.Binding(s.getFieldID_reduction_stride(), |
| stride); |
| c = builder.addKernel(s.getKernelID_add(), |
| Type.createX(mRS, Element.I32_4(mRS), stride), |
| b1, b2); |
| b2 = new ScriptGroup.Binding(s.getFieldID_a(), c.getReturn()); |
| } |
| |
| if (c == null) { |
| return; |
| } |
| |
| ScriptGroup group = builder.create("Summation", c.getReturn()); |
| |
| int[] a = new int[4]; |
| ((Allocation)group.execute(input)[0]).copyTo(a); |
| |
| mRS.finish(); |
| |
| boolean failed = false; |
| for (int i = 0; i < 4; i++) { |
| if (failed == false && a[i] != ARRAY_SIZE * (ARRAY_SIZE - 1) * 7 / 2) { |
| Log.e(TAG, |
| "a["+i+"]="+a[i]+", should be "+ (ARRAY_SIZE * (ARRAY_SIZE - 1) * 7 / 2)); |
| failed = true; |
| } |
| } |
| |
| assertTrue(!failed); |
| } |
| |
| /** |
| * Tests that the kernel output to a global can be used as a future |
| */ |
| public void testBuilder2KernelOutputToGlobal() { |
| ScriptC_reduction s = new ScriptC_reduction(mRS); |
| |
| int[] array = new int[ARRAY_SIZE * 4]; |
| |
| for (int i = 0; i < ARRAY_SIZE; i++) { |
| array[i*4] = i; |
| array[i*4 + 1] = i; |
| array[i*4 + 2] = i; |
| array[i*4 + 3] = i; |
| } |
| |
| Allocation input = Allocation.createSized(mRS, Element.I32_4(mRS), ARRAY_SIZE); |
| input.copyFrom(array); |
| Allocation input1 = Allocation.createSized(mRS, Element.I32_4(mRS), ARRAY_SIZE); |
| |
| ScriptGroup.Builder2 builder = new ScriptGroup.Builder2(mRS); |
| |
| ScriptGroup.Input unbound = builder.addInput(); |
| |
| ScriptGroup.Closure c = null; |
| ScriptGroup.Binding b2 = new ScriptGroup.Binding(s.getFieldID_a(), unbound); |
| for (int stride = ARRAY_SIZE / 2; stride >= 1; stride >>= 1) { |
| ScriptGroup.Binding b1 = new ScriptGroup.Binding(s.getFieldID_reduction_stride(), |
| stride); |
| c = builder.addKernel(s.getKernelID_add2(), |
| Type.createX(mRS, Element.I32_4(mRS), stride), |
| b1, b2); |
| b2 = new ScriptGroup.Binding(s.getFieldID_a(), |
| c.getGlobal(s.getFieldID_a())); |
| } |
| |
| if (c == null) { |
| return; |
| } |
| |
| ScriptGroup group = builder.create("SummationGlobal", c.getGlobal(s.getFieldID_a())); |
| |
| int[] a = new int[4 * ARRAY_SIZE]; |
| ((Allocation)group.execute(input, input1)[0]).copyTo(a); |
| |
| mRS.finish(); |
| |
| boolean failed = false; |
| for (int i = 0; i < 4; i++) { |
| if (failed == false && a[i] != ARRAY_SIZE * (ARRAY_SIZE - 1) / 2) { |
| Log.e(TAG, |
| "a["+i+"]="+a[i]+", should be "+ (ARRAY_SIZE * (ARRAY_SIZE - 1) / 2)); |
| failed = true; |
| } |
| } |
| |
| assertTrue(!failed); |
| } |
| |
| /** |
| * Tests that invoke-to-kernel dependency is handled correctly |
| */ |
| public void testBuilder2InvokeToKernelDependency() { |
| ScriptC_matrix s = new ScriptC_matrix(mRS); |
| |
| float[] array = new float[ARRAY_SIZE * 4]; |
| |
| for (int i = 0; i < ARRAY_SIZE; i++) { |
| array[i * 4] = i * 4 * 7; |
| array[i * 4 + 1] = (i * 4 + 1) * 7; |
| array[i * 4 + 2] = (i * 4 + 2) * 7; |
| array[i * 4 + 3] = (i * 4 + 3) * 7; |
| } |
| |
| Allocation input = Allocation.createSized(mRS, Element.F32_4(mRS), ARRAY_SIZE); |
| input.copyFrom(array); |
| |
| ScriptGroup.Builder2 builder = new ScriptGroup.Builder2(mRS); |
| |
| ScriptGroup.Input unbound = builder.addInput(); |
| |
| Matrix4f mat = new Matrix4f(); |
| |
| mat.set(0, 0, 0.0f); |
| mat.set(0, 1, 0.0f); |
| mat.set(0, 2, 0.0f); |
| mat.set(0, 3, 1.0f); |
| |
| mat.set(1, 0, 1.0f); |
| mat.set(1, 1, 0.0f); |
| mat.set(1, 2, 0.0f); |
| mat.set(1, 3, 0.0f); |
| |
| mat.set(2, 0, 0.0f); |
| mat.set(2, 1, 1.0f); |
| mat.set(2, 2, 0.0f); |
| mat.set(2, 3, 0.0f); |
| |
| mat.set(3, 0, 0.0f); |
| mat.set(3, 1, 0.0f); |
| mat.set(3, 2, 1.0f); |
| mat.set(3, 3, 0.0f); |
| |
| ScriptGroup.Closure c1 = |
| builder.addInvoke(s.getInvokeID_setMatrix(), mat); |
| |
| ScriptGroup.Closure c2 = |
| builder.addKernel(s.getKernelID_multiply(), |
| Type.createX(mRS, Element.F32_4(mRS), ARRAY_SIZE), |
| unbound); |
| |
| ScriptGroup group = builder.create("Multiply", c2.getReturn()); |
| |
| float[] a = new float[ARRAY_SIZE * 4]; |
| ((Allocation)group.execute(input)[0]).copyTo(a); |
| |
| mRS.finish(); |
| |
| boolean failed = false; |
| for (int i = 0; i < ARRAY_SIZE; i++) { |
| for (int j = 0; j < 4; j++) { |
| float expected = (i*4+((j+1)%4))*7; |
| if (failed == false && a[i * 4 + j] != expected) { |
| Log.e(TAG, "a["+i+"]="+a[i]+", should be "+ expected); |
| failed = true; |
| } |
| } |
| } |
| |
| assertTrue(!failed); |
| } |
| } |