Skip to content

Commit b2d5522

Browse files
Tim MurrayAndroid (Google) Code Review
authored andcommitted
Merge "Add DAG validation for ScriptGroups." into jb-mr1-dev
2 parents b8021a8 + 2a60389 commit b2d5522

File tree

1 file changed

+73
-9
lines changed

1 file changed

+73
-9
lines changed

graphics/java/android/renderscript/ScriptGroup.java

Lines changed: 73 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@
3232
* user supplied allocation. Inputs are similar but supply the
3333
* input of a kernal. Inputs bounds to a script are set directly
3434
* upon the script.
35+
* <p>
36+
* A ScriptGroup must contain at least one kernel. A ScriptGroup
37+
* must contain only a single directed acyclic graph (DAG) of
38+
* script kernels and connections. Attempting to create a
39+
* ScriptGroup with multiple DAGs or attempting to create
40+
* a cycle within a ScriptGroup will throw an exception.
3541
*
3642
**/
3743
public final class ScriptGroup extends BaseObj {
@@ -72,6 +78,7 @@ static class Node {
7278
ArrayList<ConnectLine> mInputs = new ArrayList<ConnectLine>();
7379
ArrayList<ConnectLine> mOutputs = new ArrayList<ConnectLine>();
7480
boolean mSeen;
81+
int dagNumber;
7582

7683
Node mNext;
7784

@@ -169,39 +176,85 @@ public Builder(RenderScript rs) {
169176
mRS = rs;
170177
}
171178

172-
private void validateRecurse(Node n, int depth) {
179+
private void validateCycleRecurse(Node n, int depth) {
173180
n.mSeen = true;
174181

175-
//android.util.Log.v("RSR", " validateRecurse outputCount " + n.mOutputs.size());
182+
//android.util.Log.v("RSR", " validateCycleRecurse outputCount " + n.mOutputs.size());
176183
for (int ct=0; ct < n.mOutputs.size(); ct++) {
177184
final ConnectLine cl = n.mOutputs.get(ct);
178185
if (cl.mToK != null) {
179186
Node tn = findNode(cl.mToK.mScript);
180187
if (tn.mSeen) {
181188
throw new RSInvalidStateException("Loops in group not allowed.");
182189
}
183-
validateRecurse(tn, depth + 1);
190+
validateCycleRecurse(tn, depth + 1);
184191
}
185192
if (cl.mToF != null) {
186193
Node tn = findNode(cl.mToF.mScript);
187194
if (tn.mSeen) {
188195
throw new RSInvalidStateException("Loops in group not allowed.");
189196
}
190-
validateRecurse(tn, depth + 1);
197+
validateCycleRecurse(tn, depth + 1);
191198
}
192199
}
193200
}
194201

195-
private void validate() {
196-
//android.util.Log.v("RSR", "validate");
202+
private void validateCycle() {
203+
//android.util.Log.v("RSR", "validateCycle");
197204

198205
for (int ct=0; ct < mNodes.size(); ct++) {
199206
for (int ct2=0; ct2 < mNodes.size(); ct2++) {
200207
mNodes.get(ct2).mSeen = false;
201208
}
202209
Node n = mNodes.get(ct);
203210
if (n.mInputs.size() == 0) {
204-
validateRecurse(n, 0);
211+
validateCycleRecurse(n, 0);
212+
}
213+
}
214+
}
215+
216+
private void mergeDAGs(int valueUsed, int valueKilled) {
217+
for (int ct=0; ct < mNodes.size(); ct++) {
218+
if (mNodes.get(ct).dagNumber == valueKilled)
219+
mNodes.get(ct).dagNumber = valueUsed;
220+
}
221+
}
222+
223+
private void validateDAGRecurse(Node n, int dagNumber) {
224+
// combine DAGs if this node has been seen already
225+
if (n.dagNumber != 0 && n.dagNumber != dagNumber) {
226+
mergeDAGs(n.dagNumber, dagNumber);
227+
return;
228+
}
229+
230+
n.dagNumber = dagNumber;
231+
for (int ct=0; ct < n.mOutputs.size(); ct++) {
232+
final ConnectLine cl = n.mOutputs.get(ct);
233+
if (cl.mToK != null) {
234+
Node tn = findNode(cl.mToK.mScript);
235+
validateDAGRecurse(tn, dagNumber);
236+
}
237+
if (cl.mToF != null) {
238+
Node tn = findNode(cl.mToF.mScript);
239+
validateDAGRecurse(tn, dagNumber);
240+
}
241+
}
242+
}
243+
244+
private void validateDAG() {
245+
for (int ct=0; ct < mNodes.size(); ct++) {
246+
Node n = mNodes.get(ct);
247+
if (n.mInputs.size() == 0) {
248+
if (n.mOutputs.size() == 0 && mNodes.size() > 1) {
249+
throw new RSInvalidStateException("Groups cannot contain unconnected scripts");
250+
}
251+
validateDAGRecurse(n, ct+1);
252+
}
253+
}
254+
int dagNumber = mNodes.get(0).dagNumber;
255+
for (int ct=0; ct < mNodes.size(); ct++) {
256+
if (mNodes.get(ct).dagNumber != dagNumber) {
257+
throw new RSInvalidStateException("Multiple DAGs in group not allowed.");
205258
}
206259
}
207260
}
@@ -288,7 +341,7 @@ public Builder addConnection(Type t, Script.KernelID from, Script.FieldID to) {
288341
nf.mOutputs.add(cl);
289342
nt.mInputs.add(cl);
290343

291-
validate();
344+
validateCycle();
292345
return this;
293346
}
294347

@@ -323,7 +376,7 @@ public Builder addConnection(Type t, Script.KernelID from, Script.KernelID to) {
323376
nf.mOutputs.add(cl);
324377
nt.mInputs.add(cl);
325378

326-
validate();
379+
validateCycle();
327380
return this;
328381
}
329382

@@ -336,6 +389,17 @@ public Builder addConnection(Type t, Script.KernelID from, Script.KernelID to) {
336389
* @return ScriptGroup The new ScriptGroup
337390
*/
338391
public ScriptGroup create() {
392+
393+
if (mNodes.size() == 0) {
394+
throw new RSInvalidStateException("Empty script groups are not allowed");
395+
}
396+
397+
// reset DAG numbers in case we're building a second group
398+
for (int ct=0; ct < mNodes.size(); ct++) {
399+
mNodes.get(ct).dagNumber = 0;
400+
}
401+
validateDAG();
402+
339403
ArrayList<IO> inputs = new ArrayList<IO>();
340404
ArrayList<IO> outputs = new ArrayList<IO>();
341405

0 commit comments

Comments
 (0)