1423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams/* 2423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams * Copyright (C) 2012 The Android Open Source Project 3423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams * 4423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams * Licensed under the Apache License, Version 2.0 (the "License"); 5423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams * you may not use this file except in compliance with the License. 6423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams * You may obtain a copy of the License at 7423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams * 8423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams * http://www.apache.org/licenses/LICENSE-2.0 9423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams * 10423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams * Unless required by applicable law or agreed to in writing, software 11423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams * distributed under the License is distributed on an "AS IS" BASIS, 12423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams * See the License for the specific language governing permissions and 14423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams * limitations under the License. 15423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams */ 16423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 17423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Samspackage android.renderscript; 18423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 1908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Samsimport java.util.ArrayList; 20423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 21423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams/** 22c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * ScriptGroup creates a group of kernels that are executed 23c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * together with one execution call as if they were a single kernel. 24c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * The kernels may be connected internally or to an external allocation. 25c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * The intermediate results for internal connections are not observable 26c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * after the execution of the script. 2708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * <p> 28c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * External connections are grouped into inputs and outputs. 2908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * All outputs are produced by a script kernel and placed into a 30c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * user-supplied allocation. Inputs provide the input of a kernel. 31c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * Inputs bound to script globals are set directly upon the script. 322a603897c6fdeba553051eedb911ec3b0b794530Tim Murray * <p> 332a603897c6fdeba553051eedb911ec3b0b794530Tim Murray * A ScriptGroup must contain at least one kernel. A ScriptGroup 342a603897c6fdeba553051eedb911ec3b0b794530Tim Murray * must contain only a single directed acyclic graph (DAG) of 352a603897c6fdeba553051eedb911ec3b0b794530Tim Murray * script kernels and connections. Attempting to create a 362a603897c6fdeba553051eedb911ec3b0b794530Tim Murray * ScriptGroup with multiple DAGs or attempting to create 372a603897c6fdeba553051eedb911ec3b0b794530Tim Murray * a cycle within a ScriptGroup will throw an exception. 38c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * <p> 39c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * Currently, all kernels in a ScriptGroup must be from separate 40c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * Script objects. Attempting to use multiple kernels from the same 41c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * Script object will result in an {@link android.renderscript.RSInvalidStateException}. 4208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * 43423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams **/ 4408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Samspublic final class ScriptGroup extends BaseObj { 45423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams IO mOutputs[]; 46423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams IO mInputs[]; 47423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 48423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams static class IO { 4908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams Script.KernelID mKID; 50423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams Allocation mAllocation; 51423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 5208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams IO(Script.KernelID s) { 5308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams mKID = s; 54423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 55423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 56423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 5708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams static class ConnectLine { 5808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams ConnectLine(Type t, Script.KernelID from, Script.KernelID to) { 5908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams mFrom = from; 6008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams mToK = to; 61423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams mAllocationType = t; 62423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 63423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 6408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams ConnectLine(Type t, Script.KernelID from, Script.FieldID to) { 6508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams mFrom = from; 6608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams mToF = to; 6708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams mAllocationType = t; 68423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 6908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 7008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams Script.FieldID mToF; 7108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams Script.KernelID mToK; 7208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams Script.KernelID mFrom; 7308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams Type mAllocationType; 74423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 75423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 76423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams static class Node { 77423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams Script mScript; 7808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams ArrayList<Script.KernelID> mKernels = new ArrayList<Script.KernelID>(); 7908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams ArrayList<ConnectLine> mInputs = new ArrayList<ConnectLine>(); 8008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams ArrayList<ConnectLine> mOutputs = new ArrayList<ConnectLine>(); 812a603897c6fdeba553051eedb911ec3b0b794530Tim Murray int dagNumber; 82423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 83423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams Node mNext; 84423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 85423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams Node(Script s) { 86423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams mScript = s; 87423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 88423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 89423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 90423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 91460a04971c494fec39ffcb38e873bb8fdd82d113Tim Murray ScriptGroup(long id, RenderScript rs) { 92423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams super(id, rs); 93423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 94423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 9508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams /** 9608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * Sets an input of the ScriptGroup. This specifies an 97c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * Allocation to be used for kernels that require an input 98c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * Allocation provided from outside of the ScriptGroup. 9908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * 10008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * @param s The ID of the kernel where the allocation should be 10108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * connected. 10208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * @param a The allocation to connect. 10308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams */ 10408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams public void setInput(Script.KernelID s, Allocation a) { 105423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams for (int ct=0; ct < mInputs.length; ct++) { 10608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (mInputs[ct].mKID == s) { 107423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams mInputs[ct].mAllocation = a; 10808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams mRS.nScriptGroupSetInput(getID(mRS), s.getID(mRS), mRS.safeID(a)); 109423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams return; 110423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 111423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 112423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams throw new RSIllegalArgumentException("Script not found"); 113423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 114423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 11508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams /** 11608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * Sets an output of the ScriptGroup. This specifies an 117c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * Allocation to be used for the kernels that require an output 118c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * Allocation visible after the ScriptGroup is executed. 11908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * 12008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * @param s The ID of the kernel where the allocation should be 12108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * connected. 12208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * @param a The allocation to connect. 12308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams */ 12408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams public void setOutput(Script.KernelID s, Allocation a) { 125423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams for (int ct=0; ct < mOutputs.length; ct++) { 12608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (mOutputs[ct].mKID == s) { 127423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams mOutputs[ct].mAllocation = a; 12808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams mRS.nScriptGroupSetOutput(getID(mRS), s.getID(mRS), mRS.safeID(a)); 129423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams return; 130423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 131423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 132423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams throw new RSIllegalArgumentException("Script not found"); 133423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 134423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 13508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams /** 13608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * Execute the ScriptGroup. This will run all the kernels in 137c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * the ScriptGroup. No internal connection results will be visible 138c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * after execution of the ScriptGroup. 13908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams */ 140423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams public void execute() { 14108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams mRS.nScriptGroupExecute(getID(mRS)); 142423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 143423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 144423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 14508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams /** 146c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * Helper class to build a ScriptGroup. A ScriptGroup is 147c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * created in two steps. 148c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * <p> 149c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * First, all kernels to be used by the ScriptGroup should be added. 15008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * <p> 151c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * Second, add connections between kernels. There are two types 152c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * of connections: kernel to kernel and kernel to field. 153c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * Kernel to kernel allows a kernel's output to be passed to 154c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * another kernel as input. Kernel to field allows the output of 155c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * one kernel to be bound as a script global. Kernel to kernel is 156c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * higher performance and should be used where possible. 15708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * <p> 158c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * A ScriptGroup must contain a single directed acyclic graph (DAG); it 159c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * cannot contain cycles. Currently, all kernels used in a ScriptGroup 160c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * must come from different Script objects. Additionally, all kernels 161c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * in a ScriptGroup must have at least one input, output, or internal 162c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * connection. 16308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * <p> 164c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * Once all connections are made, a call to {@link #create} will 16508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * return the ScriptGroup object. 16608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * 16708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams */ 16808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams public static final class Builder { 16908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams private RenderScript mRS; 17008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams private ArrayList<Node> mNodes = new ArrayList<Node>(); 17108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams private ArrayList<ConnectLine> mLines = new ArrayList<ConnectLine>(); 17208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams private int mKernelCount; 17308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 17408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams /** 175c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * Create a Builder for generating a ScriptGroup. 17608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * 17708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * 178c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * @param rs The RenderScript context. 17908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams */ 180423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams public Builder(RenderScript rs) { 181423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams mRS = rs; 182423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 183423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 184091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray // do a DFS from original node, looking for original node 185091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray // any cycle that could be created must contain original node 186091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray private void validateCycle(Node target, Node original) { 187091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray for (int ct = 0; ct < target.mOutputs.size(); ct++) { 188091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray final ConnectLine cl = target.mOutputs.get(ct); 18908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (cl.mToK != null) { 19008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams Node tn = findNode(cl.mToK.mScript); 191091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray if (tn.equals(original)) { 192423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams throw new RSInvalidStateException("Loops in group not allowed."); 193423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 194091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray validateCycle(tn, original); 19508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 19608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (cl.mToF != null) { 19708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams Node tn = findNode(cl.mToF.mScript); 198091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray if (tn.equals(original)) { 19908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams throw new RSInvalidStateException("Loops in group not allowed."); 20008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 201091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray validateCycle(tn, original); 2022a603897c6fdeba553051eedb911ec3b0b794530Tim Murray } 2032a603897c6fdeba553051eedb911ec3b0b794530Tim Murray } 2042a603897c6fdeba553051eedb911ec3b0b794530Tim Murray } 2052a603897c6fdeba553051eedb911ec3b0b794530Tim Murray 2062a603897c6fdeba553051eedb911ec3b0b794530Tim Murray private void mergeDAGs(int valueUsed, int valueKilled) { 2072a603897c6fdeba553051eedb911ec3b0b794530Tim Murray for (int ct=0; ct < mNodes.size(); ct++) { 2082a603897c6fdeba553051eedb911ec3b0b794530Tim Murray if (mNodes.get(ct).dagNumber == valueKilled) 2092a603897c6fdeba553051eedb911ec3b0b794530Tim Murray mNodes.get(ct).dagNumber = valueUsed; 2102a603897c6fdeba553051eedb911ec3b0b794530Tim Murray } 2112a603897c6fdeba553051eedb911ec3b0b794530Tim Murray } 2122a603897c6fdeba553051eedb911ec3b0b794530Tim Murray 2132a603897c6fdeba553051eedb911ec3b0b794530Tim Murray private void validateDAGRecurse(Node n, int dagNumber) { 2142a603897c6fdeba553051eedb911ec3b0b794530Tim Murray // combine DAGs if this node has been seen already 2152a603897c6fdeba553051eedb911ec3b0b794530Tim Murray if (n.dagNumber != 0 && n.dagNumber != dagNumber) { 2162a603897c6fdeba553051eedb911ec3b0b794530Tim Murray mergeDAGs(n.dagNumber, dagNumber); 2172a603897c6fdeba553051eedb911ec3b0b794530Tim Murray return; 2182a603897c6fdeba553051eedb911ec3b0b794530Tim Murray } 2192a603897c6fdeba553051eedb911ec3b0b794530Tim Murray 2202a603897c6fdeba553051eedb911ec3b0b794530Tim Murray n.dagNumber = dagNumber; 2212a603897c6fdeba553051eedb911ec3b0b794530Tim Murray for (int ct=0; ct < n.mOutputs.size(); ct++) { 2222a603897c6fdeba553051eedb911ec3b0b794530Tim Murray final ConnectLine cl = n.mOutputs.get(ct); 2232a603897c6fdeba553051eedb911ec3b0b794530Tim Murray if (cl.mToK != null) { 2242a603897c6fdeba553051eedb911ec3b0b794530Tim Murray Node tn = findNode(cl.mToK.mScript); 2252a603897c6fdeba553051eedb911ec3b0b794530Tim Murray validateDAGRecurse(tn, dagNumber); 2262a603897c6fdeba553051eedb911ec3b0b794530Tim Murray } 2272a603897c6fdeba553051eedb911ec3b0b794530Tim Murray if (cl.mToF != null) { 2282a603897c6fdeba553051eedb911ec3b0b794530Tim Murray Node tn = findNode(cl.mToF.mScript); 2292a603897c6fdeba553051eedb911ec3b0b794530Tim Murray validateDAGRecurse(tn, dagNumber); 2302a603897c6fdeba553051eedb911ec3b0b794530Tim Murray } 2312a603897c6fdeba553051eedb911ec3b0b794530Tim Murray } 2322a603897c6fdeba553051eedb911ec3b0b794530Tim Murray } 2332a603897c6fdeba553051eedb911ec3b0b794530Tim Murray 2342a603897c6fdeba553051eedb911ec3b0b794530Tim Murray private void validateDAG() { 2352a603897c6fdeba553051eedb911ec3b0b794530Tim Murray for (int ct=0; ct < mNodes.size(); ct++) { 2362a603897c6fdeba553051eedb911ec3b0b794530Tim Murray Node n = mNodes.get(ct); 2372a603897c6fdeba553051eedb911ec3b0b794530Tim Murray if (n.mInputs.size() == 0) { 2382a603897c6fdeba553051eedb911ec3b0b794530Tim Murray if (n.mOutputs.size() == 0 && mNodes.size() > 1) { 2392a603897c6fdeba553051eedb911ec3b0b794530Tim Murray throw new RSInvalidStateException("Groups cannot contain unconnected scripts"); 2402a603897c6fdeba553051eedb911ec3b0b794530Tim Murray } 2412a603897c6fdeba553051eedb911ec3b0b794530Tim Murray validateDAGRecurse(n, ct+1); 2422a603897c6fdeba553051eedb911ec3b0b794530Tim Murray } 2432a603897c6fdeba553051eedb911ec3b0b794530Tim Murray } 2442a603897c6fdeba553051eedb911ec3b0b794530Tim Murray int dagNumber = mNodes.get(0).dagNumber; 2452a603897c6fdeba553051eedb911ec3b0b794530Tim Murray for (int ct=0; ct < mNodes.size(); ct++) { 2462a603897c6fdeba553051eedb911ec3b0b794530Tim Murray if (mNodes.get(ct).dagNumber != dagNumber) { 2472a603897c6fdeba553051eedb911ec3b0b794530Tim Murray throw new RSInvalidStateException("Multiple DAGs in group not allowed."); 248423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 249423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 250423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 251423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 25208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams private Node findNode(Script s) { 25308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams for (int ct=0; ct < mNodes.size(); ct++) { 25408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (s == mNodes.get(ct).mScript) { 25508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams return mNodes.get(ct); 256423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 257423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 258423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams return null; 259423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 260423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 26108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams private Node findNode(Script.KernelID k) { 26208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams for (int ct=0; ct < mNodes.size(); ct++) { 26308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams Node n = mNodes.get(ct); 26408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams for (int ct2=0; ct2 < n.mKernels.size(); ct2++) { 26508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (k == n.mKernels.get(ct2)) { 26608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams return n; 267423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 268423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 269423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 27008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams return null; 27108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 27208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 27308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams /** 27408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * Adds a Kernel to the group. 27508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * 27608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * 27708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * @param k The kernel to add. 27808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * 27908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * @return Builder Returns this. 28008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams */ 28108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams public Builder addKernel(Script.KernelID k) { 28208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (mLines.size() != 0) { 28308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams throw new RSInvalidStateException( 28408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams "Kernels may not be added once connections exist."); 28508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 28608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 28708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams //android.util.Log.v("RSR", "addKernel 1 k=" + k); 28808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (findNode(k) != null) { 28908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams return this; 29008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 29108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams //android.util.Log.v("RSR", "addKernel 2 "); 29208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams mKernelCount++; 29308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams Node n = findNode(k.mScript); 29408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (n == null) { 29508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams //android.util.Log.v("RSR", "addKernel 3 "); 29608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams n = new Node(k.mScript); 29708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams mNodes.add(n); 29808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 29908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams n.mKernels.add(k); 30008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams return this; 30108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 30208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 30308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams /** 30408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * Adds a connection to the group. 30508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * 30608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * 30708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * @param t The type of the connection. This is used to 30808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * determine the kernel launch sizes on the source side 30908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * of this connection. 31008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * @param from The source for the connection. 31108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * @param to The destination of the connection. 31208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * 31308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * @return Builder Returns this 31408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams */ 31508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams public Builder addConnection(Type t, Script.KernelID from, Script.FieldID to) { 31608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams //android.util.Log.v("RSR", "addConnection " + t +", " + from + ", " + to); 31708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 31808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams Node nf = findNode(from); 31908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (nf == null) { 320091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray throw new RSInvalidStateException("From script not found."); 32108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 32208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 32308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams Node nt = findNode(to.mScript); 32408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (nt == null) { 32508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams throw new RSInvalidStateException("To script not found."); 32608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 32708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 32808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams ConnectLine cl = new ConnectLine(t, from, to); 32908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams mLines.add(new ConnectLine(t, from, to)); 33008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 33108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams nf.mOutputs.add(cl); 33208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams nt.mInputs.add(cl); 33308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 334091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray validateCycle(nf, nf); 33508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams return this; 33608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 33708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 33808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams /** 33908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * Adds a connection to the group. 34008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * 34108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * 34208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * @param t The type of the connection. This is used to 34308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * determine the kernel launch sizes for both sides of 34408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * this connection. 34508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * @param from The source for the connection. 34608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * @param to The destination of the connection. 34708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * 34808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * @return Builder Returns this 34908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams */ 35008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams public Builder addConnection(Type t, Script.KernelID from, Script.KernelID to) { 35108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams //android.util.Log.v("RSR", "addConnection " + t +", " + from + ", " + to); 35208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 35308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams Node nf = findNode(from); 35408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (nf == null) { 355091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray throw new RSInvalidStateException("From script not found."); 35608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 35708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 35808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams Node nt = findNode(to); 35908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (nt == null) { 36008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams throw new RSInvalidStateException("To script not found."); 361423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 36208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 36308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams ConnectLine cl = new ConnectLine(t, from, to); 36408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams mLines.add(new ConnectLine(t, from, to)); 36508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 36608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams nf.mOutputs.add(cl); 36708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams nt.mInputs.add(cl); 368423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 369091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray validateCycle(nf, nf); 370423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams return this; 371423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 372423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 37308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 37408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 37508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams /** 37608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * Creates the Script group. 37708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * 37808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * 37908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * @return ScriptGroup The new ScriptGroup 38008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams */ 381423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams public ScriptGroup create() { 3822a603897c6fdeba553051eedb911ec3b0b794530Tim Murray 3832a603897c6fdeba553051eedb911ec3b0b794530Tim Murray if (mNodes.size() == 0) { 3842a603897c6fdeba553051eedb911ec3b0b794530Tim Murray throw new RSInvalidStateException("Empty script groups are not allowed"); 3852a603897c6fdeba553051eedb911ec3b0b794530Tim Murray } 3862a603897c6fdeba553051eedb911ec3b0b794530Tim Murray 3872a603897c6fdeba553051eedb911ec3b0b794530Tim Murray // reset DAG numbers in case we're building a second group 3882a603897c6fdeba553051eedb911ec3b0b794530Tim Murray for (int ct=0; ct < mNodes.size(); ct++) { 3892a603897c6fdeba553051eedb911ec3b0b794530Tim Murray mNodes.get(ct).dagNumber = 0; 3902a603897c6fdeba553051eedb911ec3b0b794530Tim Murray } 3912a603897c6fdeba553051eedb911ec3b0b794530Tim Murray validateDAG(); 3922a603897c6fdeba553051eedb911ec3b0b794530Tim Murray 39308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams ArrayList<IO> inputs = new ArrayList<IO>(); 39408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams ArrayList<IO> outputs = new ArrayList<IO>(); 39508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 3969807155b11a25fb6068edc9b1cd82928ac2f05deAshok Bhat long[] kernels = new long[mKernelCount]; 39708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams int idx = 0; 39808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams for (int ct=0; ct < mNodes.size(); ct++) { 39908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams Node n = mNodes.get(ct); 40008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams for (int ct2=0; ct2 < n.mKernels.size(); ct2++) { 40108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams final Script.KernelID kid = n.mKernels.get(ct2); 4029807155b11a25fb6068edc9b1cd82928ac2f05deAshok Bhat kernels[idx++] = kid.getID(mRS); 40308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 40408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams boolean hasInput = false; 40508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams boolean hasOutput = false; 40608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams for (int ct3=0; ct3 < n.mInputs.size(); ct3++) { 40708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (n.mInputs.get(ct3).mToK == kid) { 40808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams hasInput = true; 40908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 41008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 41108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams for (int ct3=0; ct3 < n.mOutputs.size(); ct3++) { 41208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (n.mOutputs.get(ct3).mFrom == kid) { 41308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams hasOutput = true; 41408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 41508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 41608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (!hasInput) { 41708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams inputs.add(new IO(kid)); 41808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 41908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (!hasOutput) { 42008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams outputs.add(new IO(kid)); 42108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 422423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 42308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 42408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 42508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (idx != mKernelCount) { 42608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams throw new RSRuntimeException("Count mismatch, should not happen."); 42708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 42808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 4299807155b11a25fb6068edc9b1cd82928ac2f05deAshok Bhat long[] src = new long[mLines.size()]; 4309807155b11a25fb6068edc9b1cd82928ac2f05deAshok Bhat long[] dstk = new long[mLines.size()]; 4319807155b11a25fb6068edc9b1cd82928ac2f05deAshok Bhat long[] dstf = new long[mLines.size()]; 4329807155b11a25fb6068edc9b1cd82928ac2f05deAshok Bhat long[] types = new long[mLines.size()]; 43308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 43408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams for (int ct=0; ct < mLines.size(); ct++) { 43508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams ConnectLine cl = mLines.get(ct); 4369807155b11a25fb6068edc9b1cd82928ac2f05deAshok Bhat src[ct] = cl.mFrom.getID(mRS); 43708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (cl.mToK != null) { 4389807155b11a25fb6068edc9b1cd82928ac2f05deAshok Bhat dstk[ct] = cl.mToK.getID(mRS); 43908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 44008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (cl.mToF != null) { 4419807155b11a25fb6068edc9b1cd82928ac2f05deAshok Bhat dstf[ct] = cl.mToF.getID(mRS); 44208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 4439807155b11a25fb6068edc9b1cd82928ac2f05deAshok Bhat types[ct] = cl.mAllocationType.getID(mRS); 44408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 44508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 446460a04971c494fec39ffcb38e873bb8fdd82d113Tim Murray long id = mRS.nScriptGroupCreate(kernels, src, dstk, dstf, types); 44708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams if (id == 0) { 44808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams throw new RSRuntimeException("Object creation error, should not happen."); 44908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 45008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 45108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams ScriptGroup sg = new ScriptGroup(id, mRS); 45208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams sg.mOutputs = new IO[outputs.size()]; 45308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams for (int ct=0; ct < outputs.size(); ct++) { 45408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams sg.mOutputs[ct] = outputs.get(ct); 45508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 45608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 45708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams sg.mInputs = new IO[inputs.size()]; 45808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams for (int ct=0; ct < inputs.size(); ct++) { 45908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams sg.mInputs[ct] = inputs.get(ct); 46008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 461423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 462423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams return sg; 463423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 464423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 465423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams } 466423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 467423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 468423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams} 469423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 470423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams 471