summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jason Sams <jsams@google.com> 2012-08-10 15:40:53 -0700
committer Jason Sams <jsams@google.com> 2012-08-10 16:02:33 -0700
commit423ebcb4dc4881c3a83e8121d5212466287d0d0c (patch)
treeb8ad64ce2954386060441c9726e0d81e57b7e308
parent6cc7a9276bdad8b230e35141204c949291350f0b (diff)
Implement ScriptGroup and add test.
Change-Id: I6ce0479c20f425d501c759c15717aa8b418c3f5f
-rw-r--r--graphics/java/android/renderscript/ScriptGroup.java391
-rw-r--r--tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/GroupTest.java94
-rw-r--r--tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java10
-rw-r--r--tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/colormatrix.rs38
-rw-r--r--tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/convolve3x3.rs72
5 files changed, 604 insertions, 1 deletions
diff --git a/graphics/java/android/renderscript/ScriptGroup.java b/graphics/java/android/renderscript/ScriptGroup.java
new file mode 100644
index 000000000000..c4064b5e6969
--- /dev/null
+++ b/graphics/java/android/renderscript/ScriptGroup.java
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 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;
+
+import java.lang.reflect.Method;
+
+/**
+ * @hide
+ **/
+public class ScriptGroup extends BaseObj {
+ Node mNodes[];
+ Connection mConnections[];
+ Node mFirstNode;
+ IO mOutputs[];
+ IO mInputs[];
+
+ static class IO {
+ Script mScript;
+ Allocation mAllocation;
+ String mName;
+
+ IO(Script s) {
+ mScript = s;
+ }
+ IO(Script s, String n) {
+ mScript = s;
+ mName = n;
+ }
+ }
+
+ static class Connection {
+ Node mTo[];
+ String mToName[];
+ Node mFrom;
+ Type mAllocationType;
+ Allocation mInternalAllocation;
+
+ Connection(Node out, Type t) {
+ mFrom = out;
+ mAllocationType = t;
+ }
+
+ void addTo(Node n, String name) {
+ if (mTo == null) {
+ mTo = new Node[1];
+ mToName = new String[1];
+ } else {
+ Node nt[] = new Node[mTo.length + 1];
+ String ns[] = new String[mTo.length + 1];
+ System.arraycopy(mTo, 0, nt, 0, mTo.length);
+ System.arraycopy(mToName, 0, ns, 0, mTo.length);
+ mTo = nt;
+ mToName = ns;
+ }
+ mTo[mTo.length - 1] = n;
+ mToName[mTo.length - 1] = name;
+ }
+ }
+
+ static class Node {
+ Script mScript;
+ Connection mInput[] = new Connection[8];
+ Connection mOutput[] = new Connection[1];
+ int mInputCount;
+ int mOutputCount;
+ int mDepth;
+ boolean mSeen;
+
+ Node mNext;
+
+ Node(Script s) {
+ mScript = s;
+ }
+
+ void addInput(Connection c) {
+ if (mInput.length <= mInputCount) {
+ Connection[] nc = new Connection[mInput.length + 8];
+ System.arraycopy(mInput, 0, nc, 0, mInputCount);
+ mInput = nc;
+ }
+ mInput[mInputCount++] = c;
+ }
+
+ void addOutput(Connection c) {
+ if (mOutput.length <= mOutputCount) {
+ Connection[] nc = new Connection[mOutput.length + 8];
+ System.arraycopy(mOutput, 0, nc, 0, mOutputCount);
+ mOutput = nc;
+ }
+ mOutput[mOutputCount++] = c;
+ }
+ }
+
+
+ ScriptGroup(int id, RenderScript rs) {
+ super(id, rs);
+ }
+
+ void init(int nodeCount, int connectionCount) {
+ mNodes = new Node[nodeCount];
+ mConnections = new Connection[connectionCount];
+
+ android.util.Log.v("RSR", "init" + nodeCount + ", " + connectionCount);
+
+ // Count outputs and create array.
+ Node n = mFirstNode;
+ int outputCount = 0;
+ int inputCount = 0;
+ int connectionIndex = 0;
+ int nodeNum = 0;
+ while (n != null) {
+ mNodes[nodeNum++] = n;
+
+ // Look for unattached kernel inputs
+ boolean hasInput = false;
+ for (int ct=0; ct < n.mInput.length; ct++) {
+ if (n.mInput[ct] != null) {
+ if (n.mInput[ct].mToName == null) {
+ hasInput = true;
+ }
+ }
+ }
+ if (!hasInput) {
+ if (mInputs == null) {
+ mInputs = new IO[1];
+ }
+ if (mInputs.length <= inputCount) {
+ IO t[] = new IO[mInputs.length + 1];
+ System.arraycopy(mInputs, 0, t, 0, mInputs.length);
+ mInputs = t;
+ }
+ mInputs[inputCount++] = new IO(n.mScript);
+ }
+
+ // Look for unattached kernel outputs
+ boolean hasOutput = false;
+ for (int ct=0; ct < n.mOutput.length; ct++) {
+ if (n.mOutput[ct] != null) {
+ hasOutput = true;
+ }
+ }
+ if (!hasOutput) {
+ if (mOutputs == null) {
+ mOutputs = new IO[1];
+ }
+ if (mOutputs.length <= outputCount) {
+ IO t[] = new IO[mOutputs.length + 1];
+ System.arraycopy(mOutputs, 0, t, 0, mOutputs.length);
+ mOutputs = t;
+ }
+ mOutputs[outputCount++] = new IO(n.mScript);
+ }
+
+ // Make allocations for internal connections
+ // Since script outputs are unique, use those to avoid duplicates.
+ for (int ct=0; ct < n.mOutput.length; ct++) {
+ android.util.Log.v("RSR", "init out2 " + n.mOutput[ct]);
+ if (n.mOutput[ct] != null) {
+ Connection t = n.mOutput[ct];
+ mConnections[connectionIndex++] = t;
+ t.mInternalAllocation = Allocation.createTyped(mRS, t.mAllocationType);
+ }
+ }
+
+ n = n.mNext;
+ }
+ }
+
+ public void setInput(Script s, Allocation a) {
+ for (int ct=0; ct < mInputs.length; ct++) {
+ if (mInputs[ct].mScript == s) {
+ mInputs[ct].mAllocation = a;
+ return;
+ }
+ }
+ throw new RSIllegalArgumentException("Script not found");
+ }
+
+ public void setOutput(Script s, Allocation a) {
+ for (int ct=0; ct < mOutputs.length; ct++) {
+ if (mOutputs[ct].mScript == s) {
+ mOutputs[ct].mAllocation = a;
+ return;
+ }
+ }
+ throw new RSIllegalArgumentException("Script not found");
+ }
+
+ public void execute() {
+ android.util.Log.v("RSR", "execute");
+ boolean more = true;
+ int depth = 0;
+ while (more) {
+ more = false;
+ for (int ct=0; ct < mNodes.length; ct++) {
+ if (mNodes[ct].mDepth == depth) {
+ more = true;
+
+ Allocation kernelIn = null;
+ for (int ct2=0; ct2 < mNodes[ct].mInputCount; ct2++) {
+ android.util.Log.v("RSR", " kin " + ct2 + ", to " + mNodes[ct].mInput[ct2].mTo[0] + ", name " + mNodes[ct].mInput[ct2].mToName[0]);
+ if (mNodes[ct].mInput[ct2].mToName[0] == null) {
+ kernelIn = mNodes[ct].mInput[ct2].mInternalAllocation;
+ break;
+ }
+ }
+
+ Allocation kernelOut= null;
+ for (int ct2=0; ct2 < mNodes[ct].mOutputCount; ct2++) {
+ android.util.Log.v("RSR", " kout " + ct2 + ", from " + mNodes[ct].mOutput[ct2].mFrom);
+ if (mNodes[ct].mOutput[ct2].mFrom != null) {
+ kernelOut = mNodes[ct].mOutput[ct2].mInternalAllocation;
+ break;
+ }
+ }
+ if (kernelOut == null) {
+ for (int ct2=0; ct2 < mOutputs.length; ct2++) {
+ if (mOutputs[ct2].mScript == mNodes[ct].mScript) {
+ kernelOut = mOutputs[ct2].mAllocation;
+ break;
+ }
+ }
+ }
+
+ android.util.Log.v("RSR", "execute calling " + mNodes[ct] + ", with " + kernelIn);
+ if (kernelIn != null) {
+ try {
+
+ Method m = mNodes[ct].mScript.getClass().getMethod("forEach_root",
+ new Class[] { Allocation.class, Allocation.class });
+ m.invoke(mNodes[ct].mScript, new Object[] {kernelIn, kernelOut} );
+ } catch (Throwable t) {
+ android.util.Log.e("RSR", "execute error " + t);
+ }
+ } else {
+ try {
+ Method m = mNodes[ct].mScript.getClass().getMethod("forEach_root",
+ new Class[] { Allocation.class });
+ m.invoke(mNodes[ct].mScript, new Object[] {kernelOut} );
+ } catch (Throwable t) {
+ android.util.Log.e("RSR", "execute error " + t);
+ }
+ }
+
+ }
+ }
+ depth ++;
+ }
+
+ }
+
+
+ public static class Builder {
+ RenderScript mRS;
+ Node mFirstNode;
+ int mConnectionCount = 0;
+ int mNodeCount = 0;
+
+ public Builder(RenderScript rs) {
+ mRS = rs;
+ }
+
+ private void validateRecurse(Node n, int depth) {
+ n.mSeen = true;
+ if (depth > n.mDepth) {
+ n.mDepth = depth;
+ }
+
+ android.util.Log.v("RSR", " validateRecurse outputCount " + n.mOutputCount);
+ for (int ct=0; ct < n.mOutputCount; ct++) {
+ for (int ct2=0; ct2 < n.mOutput[ct].mTo.length; ct2++) {
+ if (n.mOutput[ct].mTo[ct2].mSeen) {
+ throw new RSInvalidStateException("Loops in group not allowed.");
+ }
+ validateRecurse(n.mOutput[ct].mTo[ct2], depth + 1);
+ }
+ }
+ }
+
+ private void validate() {
+ android.util.Log.v("RSR", "validate");
+ Node n = mFirstNode;
+ while (n != null) {
+ n.mSeen = false;
+ n.mDepth = 0;
+ n = n.mNext;
+ }
+
+ n = mFirstNode;
+ while (n != null) {
+ android.util.Log.v("RSR", "validate n= " + n);
+ if ((n.mSeen == false) && (n.mInputCount == 0)) {
+ android.util.Log.v("RSR", " recursing " + n);
+ validateRecurse(n, 0);
+ }
+ n = n.mNext;
+ }
+ }
+
+ private Node findScript(Script s) {
+ Node n = mFirstNode;
+ while (n != null) {
+ if (n.mScript == s) {
+ return n;
+ }
+ n = n.mNext;
+ }
+ return null;
+ }
+
+ private void addNode(Node n) {
+ n.mNext = mFirstNode;
+ mFirstNode = n;
+ }
+
+ public Builder addConnection(Type t, Script output, Script input, String inputName) {
+ android.util.Log.v("RSR", "addConnection " + t +", " + output + ", " + input);
+
+ // Look for existing output
+ Node nout = findScript(output);
+ Connection c;
+ if (nout == null) {
+ // Make new node
+ android.util.Log.v("RSR", "addConnection new output node");
+ nout = new Node(output);
+ mNodeCount++;
+ c = new Connection(nout, t);
+ mConnectionCount++;
+ nout.addOutput(c);
+ addNode(nout);
+ } else {
+ // Add to existing node
+ android.util.Log.v("RSR", "addConnection reuse output node");
+ if (nout.mOutput[0] != null) {
+ if (nout.mOutput[0].mFrom.mScript != output) {
+ throw new RSInvalidStateException("Changed output of existing node");
+ }
+ if (nout.mOutput[0].mAllocationType != t) {
+ throw new RSInvalidStateException("Changed output type of existing node");
+ }
+ }
+ c = nout.mOutput[0];
+ }
+ // At this point we should have a connection attached to a script ouput.
+
+ // Find input
+ Node nin = findScript(input);
+ if (nin == null) {
+ android.util.Log.v("RSR", "addConnection new input node");
+ nin = new Node(input);
+ mNodeCount++;
+ addNode(nin);
+ }
+ c.addTo(nin, inputName);
+ nin.addInput(c);
+
+ validate();
+ return this;
+ }
+
+ public ScriptGroup create() {
+ ScriptGroup sg = new ScriptGroup(0, mRS);
+ sg.mFirstNode = mFirstNode;
+ mFirstNode = null;
+
+ android.util.Log.v("RSR", "create nodes= " + mNodeCount + ", Connections= " + mConnectionCount);
+
+ sg.init(mNodeCount, mConnectionCount);
+ return sg;
+ }
+
+ }
+
+
+}
+
+
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/GroupTest.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/GroupTest.java
new file mode 100644
index 000000000000..732da4ec04c4
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/GroupTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 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 com.android.rs.image;
+
+import java.lang.Math;
+
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.RenderScript;
+import android.renderscript.Script;
+import android.renderscript.ScriptC;
+import android.renderscript.Type;
+import android.renderscript.Matrix4f;
+import android.renderscript.ScriptGroup;
+import android.util.Log;
+
+public class GroupTest extends TestBase {
+ private ScriptC_convolve3x3 mConvolve;
+ private ScriptC_colormatrix mMatrix;
+
+ private Allocation mScratchPixelsAllocation1;
+ private ScriptGroup mGroup;
+
+ private int mWidth;
+ private int mHeight;
+ private boolean mUseNative;
+
+
+ public GroupTest(boolean useNative) {
+ mUseNative = useNative;
+ }
+
+ public void createTest(android.content.res.Resources res) {
+ mWidth = mInPixelsAllocation.getType().getX();
+ mHeight = mInPixelsAllocation.getType().getY();
+
+ mConvolve = new ScriptC_convolve3x3(mRS, res, R.raw.convolve3x3);
+ mMatrix = new ScriptC_colormatrix(mRS, res, R.raw.colormatrix);
+
+ 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;
+ mConvolve.set_gCoeffs(f);
+
+ Matrix4f m = new Matrix4f();
+ m.set(1, 0, 0.2f);
+ m.set(1, 1, 0.9f);
+ m.set(1, 2, 0.2f);
+ mMatrix.invoke_setMatrix(m);
+
+ Type.Builder tb = new Type.Builder(mRS, Element.U8_4(mRS));
+ tb.setX(mWidth);
+ tb.setY(mHeight);
+ Type connect = tb.create();
+
+ if (mUseNative) {
+ ScriptGroup.Builder b = new ScriptGroup.Builder(mRS);
+ b.addConnection(connect, mConvolve, mMatrix, null);
+ mGroup = b.create();
+
+ } else {
+ mScratchPixelsAllocation1 = Allocation.createTyped(mRS, connect);
+ }
+ }
+
+ public void runTest() {
+ mConvolve.set_gIn(mInPixelsAllocation);
+ mConvolve.set_gWidth(mWidth);
+ mConvolve.set_gHeight(mHeight);
+ if (mUseNative) {
+ mGroup.setOutput(mMatrix, mOutPixelsAllocation);
+ mGroup.execute();
+ } else {
+ mConvolve.forEach_root(mScratchPixelsAllocation1);
+ mMatrix.forEach_root(mScratchPixelsAllocation1, mOutPixelsAllocation);
+ }
+ }
+
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index d9cbf8134b13..7cd485ebedd3 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -161,6 +161,12 @@ public class ImageProcessingActivity extends Activity
case 12:
mTest = new Vignette(true, true);
break;
+ case 13:
+ mTest = new GroupTest(true);
+ break;
+ case 14:
+ mTest = new GroupTest(false);
+ break;
}
mTest.createBaseTest(this, mBitmapIn);
@@ -173,7 +179,7 @@ public class ImageProcessingActivity extends Activity
}
void setupTests() {
- mTestNames = new String[13];
+ mTestNames = new String[15];
mTestNames[0] = "Levels Vec3 Relaxed";
mTestNames[1] = "Levels Vec4 Relaxed";
mTestNames[2] = "Levels Vec3 Full";
@@ -187,6 +193,8 @@ public class ImageProcessingActivity extends Activity
mTestNames[10] = "Vignette Relaxed";
mTestNames[11] = "Vignette Approximate Full";
mTestNames[12] = "Vignette Approximate Relaxed";
+ mTestNames[13] = "Group Test (emulated)";
+ mTestNames[14] = "Group Test (native)";
mTestSpinner.setAdapter(new ArrayAdapter<String>(
this, R.layout.spinner_layout, mTestNames));
}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/colormatrix.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/colormatrix.rs
new file mode 100644
index 000000000000..a83e81986116
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/colormatrix.rs
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image)
+#pragma rs_fp_relaxed
+
+
+static rs_matrix4x4 Mat;
+
+void init() {
+ rsMatrixLoadIdentity(&Mat);
+}
+
+void setMatrix(rs_matrix4x4 m) {
+ Mat = m;
+}
+
+void root(const uchar4 *in, uchar4 *out) {
+ float4 f = convert_float4(*in);
+ f = rsMatrixMultiply(&Mat, f);
+ f = clamp(f, 0.f, 255.f);
+ *out = convert_uchar4(f);
+}
+
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/convolve3x3.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/convolve3x3.rs
new file mode 100644
index 000000000000..d3e6a4d2daa4
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/convolve3x3.rs
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image)
+#pragma rs_fp_relaxed
+
+int32_t gWidth;
+int32_t gHeight;
+rs_allocation gIn;
+
+float gCoeffs[9] ;
+void setCoefficients(float coef[9]) {
+ for(int i=0; i < 9; i++) {
+ gCoeffs[i] = coef[i];
+ }
+}
+
+void root(uchar4 *out, uint32_t x, uint32_t y) {
+ uint32_t x1 = min((int32_t)x+1, gWidth);
+ uint32_t x2 = max((int32_t)x-1, 0);
+ uint32_t y1 = min((int32_t)y+1, gHeight);
+ uint32_t y2 = max((int32_t)y-1, 0);
+
+ float4 p00 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x1, y1))[0]);
+ float4 p01 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x, y1))[0]);
+ float4 p02 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x2, y1))[0]);
+ float4 p10 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x1, y))[0]);
+ float4 p11 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x, y))[0]);
+ float4 p12 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x2, y))[0]);
+ float4 p20 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x1, y2))[0]);
+ float4 p21 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x, y2))[0]);
+ float4 p22 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x2, y2))[0]);
+ p00 *= gCoeffs[0];
+ p01 *= gCoeffs[1];
+ p02 *= gCoeffs[2];
+ p10 *= gCoeffs[3];
+ p11 *= gCoeffs[4];
+ p12 *= gCoeffs[5];
+ p20 *= gCoeffs[6];
+ p21 *= gCoeffs[7];
+ p22 *= gCoeffs[8];
+
+ p00 += p01;
+ p02 += p10;
+ p11 += p12;
+ p20 += p21;
+
+ p22 += p00;
+ p02 += p11;
+
+ p20 += p22;
+ p20 += p02;
+
+ p20 = clamp(p20, 0.f, 255.f);
+ *out = convert_uchar4(p20);
+}
+
+