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 **/
3743public 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