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
19423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Samsimport java.lang.reflect.Method;
2008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Samsimport java.util.ArrayList;
21423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
22423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams/**
2308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * ScriptGroup creates a groups of scripts which are executed
2408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * together based upon upon one execution call as if they were
2508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * all part of a single script.  The scripts may be connected
2608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * internally or to an external allocation. For the internal
2708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * connections the intermediate results are not observable after
2808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * the execution of the script.
2908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * <p>
3008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * The external connections are grouped into inputs and outputs.
3108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * All outputs are produced by a script kernel and placed into a
3208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * user supplied allocation. Inputs are similar but supply the
3308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * input of a kernal. Inputs bounds to a script are set directly
3408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * upon the script.
352a603897c6fdeba553051eedb911ec3b0b794530Tim Murray * <p>
362a603897c6fdeba553051eedb911ec3b0b794530Tim Murray * A ScriptGroup must contain at least one kernel. A ScriptGroup
372a603897c6fdeba553051eedb911ec3b0b794530Tim Murray * must contain only a single directed acyclic graph (DAG) of
382a603897c6fdeba553051eedb911ec3b0b794530Tim Murray * script kernels and connections. Attempting to create a
392a603897c6fdeba553051eedb911ec3b0b794530Tim Murray * ScriptGroup with multiple DAGs or attempting to create
402a603897c6fdeba553051eedb911ec3b0b794530Tim Murray * a cycle within a ScriptGroup will throw an exception.
4108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams *
42423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams **/
4308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Samspublic final class ScriptGroup extends BaseObj {
44423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams    IO mOutputs[];
45423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams    IO mInputs[];
46423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
47423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams    static class IO {
4808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        Script.KernelID mKID;
49423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        Allocation mAllocation;
50423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
5108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        IO(Script.KernelID s) {
5208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            mKID = s;
53423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        }
54423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams    }
55423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
5608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams    static class ConnectLine {
5708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        ConnectLine(Type t, Script.KernelID from, Script.KernelID to) {
5808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            mFrom = from;
5908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            mToK = to;
60423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams            mAllocationType = t;
61423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        }
62423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
6308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        ConnectLine(Type t, Script.KernelID from, Script.FieldID to) {
6408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            mFrom = from;
6508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            mToF = to;
6608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            mAllocationType = t;
67423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        }
6808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
6908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        Script.FieldID mToF;
7008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        Script.KernelID mToK;
7108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        Script.KernelID mFrom;
7208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        Type mAllocationType;
73423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams    }
74423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
75423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams    static class Node {
76423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        Script mScript;
7708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        ArrayList<Script.KernelID> mKernels = new ArrayList<Script.KernelID>();
7808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        ArrayList<ConnectLine> mInputs = new ArrayList<ConnectLine>();
7908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        ArrayList<ConnectLine> mOutputs = new ArrayList<ConnectLine>();
802a603897c6fdeba553051eedb911ec3b0b794530Tim Murray        int dagNumber;
81423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
82423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        Node mNext;
83423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
84423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        Node(Script s) {
85423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams            mScript = s;
86423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        }
87423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams    }
88423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
89423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
90423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams    ScriptGroup(int id, RenderScript rs) {
91423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        super(id, rs);
92423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams    }
93423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
9408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams    /**
9508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * Sets an input of the ScriptGroup. This specifies an
9608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * Allocation to be used for the kernels which require a kernel
9708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * input and that input is provided external to the group.
9808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     *
9908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * @param s The ID of the kernel where the allocation should be
10008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     *          connected.
10108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * @param a The allocation to connect.
10208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     */
10308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams    public void setInput(Script.KernelID s, Allocation a) {
104423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        for (int ct=0; ct < mInputs.length; ct++) {
10508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            if (mInputs[ct].mKID == s) {
106423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams                mInputs[ct].mAllocation = a;
10708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                mRS.nScriptGroupSetInput(getID(mRS), s.getID(mRS), mRS.safeID(a));
108423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams                return;
109423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams            }
110423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        }
111423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        throw new RSIllegalArgumentException("Script not found");
112423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams    }
113423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
11408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams    /**
11508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * Sets an output of the ScriptGroup. This specifies an
11608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * Allocation to be used for the kernels which require a kernel
11708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * output and that output is provided external to the group.
11808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     *
11908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * @param s The ID of the kernel where the allocation should be
12008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     *          connected.
12108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * @param a The allocation to connect.
12208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     */
12308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams    public void setOutput(Script.KernelID s, Allocation a) {
124423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        for (int ct=0; ct < mOutputs.length; ct++) {
12508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            if (mOutputs[ct].mKID == s) {
126423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams                mOutputs[ct].mAllocation = a;
12708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                mRS.nScriptGroupSetOutput(getID(mRS), s.getID(mRS), mRS.safeID(a));
128423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams                return;
129423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams            }
130423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        }
131423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        throw new RSIllegalArgumentException("Script not found");
132423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams    }
133423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
13408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams    /**
13508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * Execute the ScriptGroup.  This will run all the kernels in
13608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * the script.  The state of the connecting lines will not be
13708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * observable after this operation.
13808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     */
139423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams    public void execute() {
14008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        mRS.nScriptGroupExecute(getID(mRS));
141423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams    }
142423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
143423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
14408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams    /**
14508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * Create a ScriptGroup. There are two steps to creating a
14608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * ScriptGoup.
14708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * <p>
14808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * First all the Kernels to be used by the group should be
14908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * added.  Once this is done the kernels should be connected.
15008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * Kernels cannot be added once a connection has been made.
15108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * <p>
15208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * Second, add connections. There are two forms of connections.
15308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * Kernel to Kernel and Kernel to Field. Kernel to Kernel is
15408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * higher performance and should be used where possible. The
15508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * line of connections cannot form a loop. If a loop is detected
15608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * an exception is thrown.
15708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * <p>
15808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * Once all the connections are made a call to create will
15908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     * return the ScriptGroup object.
16008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     *
16108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams     */
16208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams    public static final class Builder {
16308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        private RenderScript mRS;
16408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        private ArrayList<Node> mNodes = new ArrayList<Node>();
16508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        private ArrayList<ConnectLine> mLines = new ArrayList<ConnectLine>();
16608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        private int mKernelCount;
16708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
16808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        /**
16908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         * Create a builder for generating a ScriptGroup.
17008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         *
17108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         *
17208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         * @param rs The Renderscript context.
17308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         */
174423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        public Builder(RenderScript rs) {
175423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams            mRS = rs;
176423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        }
177423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
178091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray        // do a DFS from original node, looking for original node
179091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray        // any cycle that could be created must contain original node
180091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray        private void validateCycle(Node target, Node original) {
181091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray            for (int ct = 0; ct < target.mOutputs.size(); ct++) {
182091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray                final ConnectLine cl = target.mOutputs.get(ct);
18308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                if (cl.mToK != null) {
18408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    Node tn = findNode(cl.mToK.mScript);
185091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray                    if (tn.equals(original)) {
186423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams                        throw new RSInvalidStateException("Loops in group not allowed.");
187423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams                    }
188091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray                    validateCycle(tn, original);
18908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                }
19008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                if (cl.mToF != null) {
19108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    Node tn = findNode(cl.mToF.mScript);
192091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray                    if (tn.equals(original)) {
19308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                        throw new RSInvalidStateException("Loops in group not allowed.");
19408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    }
195091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray                    validateCycle(tn, original);
1962a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                }
1972a603897c6fdeba553051eedb911ec3b0b794530Tim Murray            }
1982a603897c6fdeba553051eedb911ec3b0b794530Tim Murray        }
1992a603897c6fdeba553051eedb911ec3b0b794530Tim Murray
2002a603897c6fdeba553051eedb911ec3b0b794530Tim Murray        private void mergeDAGs(int valueUsed, int valueKilled) {
2012a603897c6fdeba553051eedb911ec3b0b794530Tim Murray            for (int ct=0; ct < mNodes.size(); ct++) {
2022a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                if (mNodes.get(ct).dagNumber == valueKilled)
2032a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                    mNodes.get(ct).dagNumber = valueUsed;
2042a603897c6fdeba553051eedb911ec3b0b794530Tim Murray            }
2052a603897c6fdeba553051eedb911ec3b0b794530Tim Murray        }
2062a603897c6fdeba553051eedb911ec3b0b794530Tim Murray
2072a603897c6fdeba553051eedb911ec3b0b794530Tim Murray        private void validateDAGRecurse(Node n, int dagNumber) {
2082a603897c6fdeba553051eedb911ec3b0b794530Tim Murray            // combine DAGs if this node has been seen already
2092a603897c6fdeba553051eedb911ec3b0b794530Tim Murray            if (n.dagNumber != 0 && n.dagNumber != dagNumber) {
2102a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                mergeDAGs(n.dagNumber, dagNumber);
2112a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                return;
2122a603897c6fdeba553051eedb911ec3b0b794530Tim Murray            }
2132a603897c6fdeba553051eedb911ec3b0b794530Tim Murray
2142a603897c6fdeba553051eedb911ec3b0b794530Tim Murray            n.dagNumber = dagNumber;
2152a603897c6fdeba553051eedb911ec3b0b794530Tim Murray            for (int ct=0; ct < n.mOutputs.size(); ct++) {
2162a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                final ConnectLine cl = n.mOutputs.get(ct);
2172a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                if (cl.mToK != null) {
2182a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                    Node tn = findNode(cl.mToK.mScript);
2192a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                    validateDAGRecurse(tn, dagNumber);
2202a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                }
2212a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                if (cl.mToF != null) {
2222a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                    Node tn = findNode(cl.mToF.mScript);
2232a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                    validateDAGRecurse(tn, dagNumber);
2242a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                }
2252a603897c6fdeba553051eedb911ec3b0b794530Tim Murray            }
2262a603897c6fdeba553051eedb911ec3b0b794530Tim Murray        }
2272a603897c6fdeba553051eedb911ec3b0b794530Tim Murray
2282a603897c6fdeba553051eedb911ec3b0b794530Tim Murray        private void validateDAG() {
2292a603897c6fdeba553051eedb911ec3b0b794530Tim Murray            for (int ct=0; ct < mNodes.size(); ct++) {
2302a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                Node n = mNodes.get(ct);
2312a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                if (n.mInputs.size() == 0) {
2322a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                    if (n.mOutputs.size() == 0 && mNodes.size() > 1) {
2332a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                        throw new RSInvalidStateException("Groups cannot contain unconnected scripts");
2342a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                    }
2352a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                    validateDAGRecurse(n, ct+1);
2362a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                }
2372a603897c6fdeba553051eedb911ec3b0b794530Tim Murray            }
2382a603897c6fdeba553051eedb911ec3b0b794530Tim Murray            int dagNumber = mNodes.get(0).dagNumber;
2392a603897c6fdeba553051eedb911ec3b0b794530Tim Murray            for (int ct=0; ct < mNodes.size(); ct++) {
2402a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                if (mNodes.get(ct).dagNumber != dagNumber) {
2412a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                    throw new RSInvalidStateException("Multiple DAGs in group not allowed.");
242423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams                }
243423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams            }
244423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        }
245423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
24608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        private Node findNode(Script s) {
24708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            for (int ct=0; ct < mNodes.size(); ct++) {
24808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                if (s == mNodes.get(ct).mScript) {
24908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    return mNodes.get(ct);
250423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams                }
251423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams            }
252423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams            return null;
253423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        }
254423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
25508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        private Node findNode(Script.KernelID k) {
25608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            for (int ct=0; ct < mNodes.size(); ct++) {
25708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                Node n = mNodes.get(ct);
25808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                for (int ct2=0; ct2 < n.mKernels.size(); ct2++) {
25908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    if (k == n.mKernels.get(ct2)) {
26008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                        return n;
261423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams                    }
262423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams                }
263423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams            }
26408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            return null;
26508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        }
26608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
26708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        /**
26808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         * Adds a Kernel to the group.
26908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         *
27008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         *
27108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         * @param k The kernel to add.
27208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         *
27308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         * @return Builder Returns this.
27408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         */
27508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        public Builder addKernel(Script.KernelID k) {
27608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            if (mLines.size() != 0) {
27708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                throw new RSInvalidStateException(
27808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    "Kernels may not be added once connections exist.");
27908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            }
28008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
28108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            //android.util.Log.v("RSR", "addKernel 1 k=" + k);
28208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            if (findNode(k) != null) {
28308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                return this;
28408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            }
28508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            //android.util.Log.v("RSR", "addKernel 2 ");
28608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            mKernelCount++;
28708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            Node n = findNode(k.mScript);
28808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            if (n == null) {
28908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                //android.util.Log.v("RSR", "addKernel 3 ");
29008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                n = new Node(k.mScript);
29108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                mNodes.add(n);
29208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            }
29308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            n.mKernels.add(k);
29408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            return this;
29508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        }
29608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
29708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        /**
29808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         * Adds a connection to the group.
29908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         *
30008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         *
30108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         * @param t The type of the connection. This is used to
30208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         *          determine the kernel launch sizes on the source side
30308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         *          of this connection.
30408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         * @param from The source for the connection.
30508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         * @param to The destination of the connection.
30608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         *
30708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         * @return Builder Returns this
30808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         */
30908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        public Builder addConnection(Type t, Script.KernelID from, Script.FieldID to) {
31008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            //android.util.Log.v("RSR", "addConnection " + t +", " + from + ", " + to);
31108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
31208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            Node nf = findNode(from);
31308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            if (nf == null) {
314091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray                throw new RSInvalidStateException("From script not found.");
31508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            }
31608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
31708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            Node nt = findNode(to.mScript);
31808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            if (nt == null) {
31908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                throw new RSInvalidStateException("To script not found.");
32008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            }
32108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
32208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            ConnectLine cl = new ConnectLine(t, from, to);
32308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            mLines.add(new ConnectLine(t, from, to));
32408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
32508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            nf.mOutputs.add(cl);
32608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            nt.mInputs.add(cl);
32708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
328091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray            validateCycle(nf, nf);
32908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            return this;
33008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        }
33108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
33208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        /**
33308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         * Adds a connection to the group.
33408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         *
33508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         *
33608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         * @param t The type of the connection. This is used to
33708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         *          determine the kernel launch sizes for both sides of
33808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         *          this connection.
33908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         * @param from The source for the connection.
34008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         * @param to The destination of the connection.
34108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         *
34208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         * @return Builder Returns this
34308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         */
34408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        public Builder addConnection(Type t, Script.KernelID from, Script.KernelID to) {
34508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            //android.util.Log.v("RSR", "addConnection " + t +", " + from + ", " + to);
34608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
34708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            Node nf = findNode(from);
34808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            if (nf == null) {
349091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray                throw new RSInvalidStateException("From script not found.");
35008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            }
35108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
35208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            Node nt = findNode(to);
35308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            if (nt == null) {
35408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                throw new RSInvalidStateException("To script not found.");
355423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams            }
35608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
35708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            ConnectLine cl = new ConnectLine(t, from, to);
35808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            mLines.add(new ConnectLine(t, from, to));
35908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
36008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            nf.mOutputs.add(cl);
36108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            nt.mInputs.add(cl);
362423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
363091f7ccf9a97aed94383370666b592a57a1b9400Tim Murray            validateCycle(nf, nf);
364423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams            return this;
365423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        }
366423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
36708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
36808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
36908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams        /**
37008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         * Creates the Script group.
37108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         *
37208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         *
37308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         * @return ScriptGroup The new ScriptGroup
37408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams         */
375423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        public ScriptGroup create() {
3762a603897c6fdeba553051eedb911ec3b0b794530Tim Murray
3772a603897c6fdeba553051eedb911ec3b0b794530Tim Murray            if (mNodes.size() == 0) {
3782a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                throw new RSInvalidStateException("Empty script groups are not allowed");
3792a603897c6fdeba553051eedb911ec3b0b794530Tim Murray            }
3802a603897c6fdeba553051eedb911ec3b0b794530Tim Murray
3812a603897c6fdeba553051eedb911ec3b0b794530Tim Murray            // reset DAG numbers in case we're building a second group
3822a603897c6fdeba553051eedb911ec3b0b794530Tim Murray            for (int ct=0; ct < mNodes.size(); ct++) {
3832a603897c6fdeba553051eedb911ec3b0b794530Tim Murray                mNodes.get(ct).dagNumber = 0;
3842a603897c6fdeba553051eedb911ec3b0b794530Tim Murray            }
3852a603897c6fdeba553051eedb911ec3b0b794530Tim Murray            validateDAG();
3862a603897c6fdeba553051eedb911ec3b0b794530Tim Murray
38708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            ArrayList<IO> inputs = new ArrayList<IO>();
38808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            ArrayList<IO> outputs = new ArrayList<IO>();
38908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
39008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            int[] kernels = new int[mKernelCount];
39108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            int idx = 0;
39208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            for (int ct=0; ct < mNodes.size(); ct++) {
39308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                Node n = mNodes.get(ct);
39408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                for (int ct2=0; ct2 < n.mKernels.size(); ct2++) {
39508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    final Script.KernelID kid = n.mKernels.get(ct2);
39608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    kernels[idx++] = kid.getID(mRS);
39708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
39808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    boolean hasInput = false;
39908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    boolean hasOutput = false;
40008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    for (int ct3=0; ct3 < n.mInputs.size(); ct3++) {
40108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                        if (n.mInputs.get(ct3).mToK == kid) {
40208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                            hasInput = true;
40308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                        }
40408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    }
40508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    for (int ct3=0; ct3 < n.mOutputs.size(); ct3++) {
40608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                        if (n.mOutputs.get(ct3).mFrom == kid) {
40708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                            hasOutput = true;
40808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                        }
40908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    }
41008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    if (!hasInput) {
41108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                        inputs.add(new IO(kid));
41208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    }
41308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    if (!hasOutput) {
41408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                        outputs.add(new IO(kid));
41508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    }
416423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
41708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                }
41808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            }
41908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            if (idx != mKernelCount) {
42008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                throw new RSRuntimeException("Count mismatch, should not happen.");
42108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            }
42208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
42308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            int[] src = new int[mLines.size()];
42408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            int[] dstk = new int[mLines.size()];
42508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            int[] dstf = new int[mLines.size()];
42608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            int[] types = new int[mLines.size()];
42708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
42808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            for (int ct=0; ct < mLines.size(); ct++) {
42908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                ConnectLine cl = mLines.get(ct);
43008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                src[ct] = cl.mFrom.getID(mRS);
43108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                if (cl.mToK != null) {
43208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    dstk[ct] = cl.mToK.getID(mRS);
43308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                }
43408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                if (cl.mToF != null) {
43508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                    dstf[ct] = cl.mToF.getID(mRS);
43608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                }
43708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                types[ct] = cl.mAllocationType.getID(mRS);
43808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            }
43908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
44008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            int id = mRS.nScriptGroupCreate(kernels, src, dstk, dstf, types);
44108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            if (id == 0) {
44208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                throw new RSRuntimeException("Object creation error, should not happen.");
44308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            }
44408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
44508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            ScriptGroup sg = new ScriptGroup(id, mRS);
44608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            sg.mOutputs = new IO[outputs.size()];
44708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            for (int ct=0; ct < outputs.size(); ct++) {
44808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                sg.mOutputs[ct] = outputs.get(ct);
44908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            }
45008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams
45108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            sg.mInputs = new IO[inputs.size()];
45208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            for (int ct=0; ct < inputs.size(); ct++) {
45308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams                sg.mInputs[ct] = inputs.get(ct);
45408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams            }
455423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
456423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams            return sg;
457423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams        }
458423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
459423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams    }
460423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
461423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
462423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams}
463423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
464423ebcb4dc4881c3a83e8121d5212466287d0d0cJason Sams
465