392 lines
13 KiB
Java
392 lines
13 KiB
Java
|
/*
|
||
|
* 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;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
|