blob: c4064b5e69699f28f43830342ad8c9f8b0ba2837 [file] [log] [blame]
Jason Sams423ebcb2012-08-10 15:40:53 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.renderscript;
18
19import java.lang.reflect.Method;
20
21/**
22 * @hide
23 **/
24public class ScriptGroup extends BaseObj {
25 Node mNodes[];
26 Connection mConnections[];
27 Node mFirstNode;
28 IO mOutputs[];
29 IO mInputs[];
30
31 static class IO {
32 Script mScript;
33 Allocation mAllocation;
34 String mName;
35
36 IO(Script s) {
37 mScript = s;
38 }
39 IO(Script s, String n) {
40 mScript = s;
41 mName = n;
42 }
43 }
44
45 static class Connection {
46 Node mTo[];
47 String mToName[];
48 Node mFrom;
49 Type mAllocationType;
50 Allocation mInternalAllocation;
51
52 Connection(Node out, Type t) {
53 mFrom = out;
54 mAllocationType = t;
55 }
56
57 void addTo(Node n, String name) {
58 if (mTo == null) {
59 mTo = new Node[1];
60 mToName = new String[1];
61 } else {
62 Node nt[] = new Node[mTo.length + 1];
63 String ns[] = new String[mTo.length + 1];
64 System.arraycopy(mTo, 0, nt, 0, mTo.length);
65 System.arraycopy(mToName, 0, ns, 0, mTo.length);
66 mTo = nt;
67 mToName = ns;
68 }
69 mTo[mTo.length - 1] = n;
70 mToName[mTo.length - 1] = name;
71 }
72 }
73
74 static class Node {
75 Script mScript;
76 Connection mInput[] = new Connection[8];
77 Connection mOutput[] = new Connection[1];
78 int mInputCount;
79 int mOutputCount;
80 int mDepth;
81 boolean mSeen;
82
83 Node mNext;
84
85 Node(Script s) {
86 mScript = s;
87 }
88
89 void addInput(Connection c) {
90 if (mInput.length <= mInputCount) {
91 Connection[] nc = new Connection[mInput.length + 8];
92 System.arraycopy(mInput, 0, nc, 0, mInputCount);
93 mInput = nc;
94 }
95 mInput[mInputCount++] = c;
96 }
97
98 void addOutput(Connection c) {
99 if (mOutput.length <= mOutputCount) {
100 Connection[] nc = new Connection[mOutput.length + 8];
101 System.arraycopy(mOutput, 0, nc, 0, mOutputCount);
102 mOutput = nc;
103 }
104 mOutput[mOutputCount++] = c;
105 }
106 }
107
108
109 ScriptGroup(int id, RenderScript rs) {
110 super(id, rs);
111 }
112
113 void init(int nodeCount, int connectionCount) {
114 mNodes = new Node[nodeCount];
115 mConnections = new Connection[connectionCount];
116
117 android.util.Log.v("RSR", "init" + nodeCount + ", " + connectionCount);
118
119 // Count outputs and create array.
120 Node n = mFirstNode;
121 int outputCount = 0;
122 int inputCount = 0;
123 int connectionIndex = 0;
124 int nodeNum = 0;
125 while (n != null) {
126 mNodes[nodeNum++] = n;
127
128 // Look for unattached kernel inputs
129 boolean hasInput = false;
130 for (int ct=0; ct < n.mInput.length; ct++) {
131 if (n.mInput[ct] != null) {
132 if (n.mInput[ct].mToName == null) {
133 hasInput = true;
134 }
135 }
136 }
137 if (!hasInput) {
138 if (mInputs == null) {
139 mInputs = new IO[1];
140 }
141 if (mInputs.length <= inputCount) {
142 IO t[] = new IO[mInputs.length + 1];
143 System.arraycopy(mInputs, 0, t, 0, mInputs.length);
144 mInputs = t;
145 }
146 mInputs[inputCount++] = new IO(n.mScript);
147 }
148
149 // Look for unattached kernel outputs
150 boolean hasOutput = false;
151 for (int ct=0; ct < n.mOutput.length; ct++) {
152 if (n.mOutput[ct] != null) {
153 hasOutput = true;
154 }
155 }
156 if (!hasOutput) {
157 if (mOutputs == null) {
158 mOutputs = new IO[1];
159 }
160 if (mOutputs.length <= outputCount) {
161 IO t[] = new IO[mOutputs.length + 1];
162 System.arraycopy(mOutputs, 0, t, 0, mOutputs.length);
163 mOutputs = t;
164 }
165 mOutputs[outputCount++] = new IO(n.mScript);
166 }
167
168 // Make allocations for internal connections
169 // Since script outputs are unique, use those to avoid duplicates.
170 for (int ct=0; ct < n.mOutput.length; ct++) {
171 android.util.Log.v("RSR", "init out2 " + n.mOutput[ct]);
172 if (n.mOutput[ct] != null) {
173 Connection t = n.mOutput[ct];
174 mConnections[connectionIndex++] = t;
175 t.mInternalAllocation = Allocation.createTyped(mRS, t.mAllocationType);
176 }
177 }
178
179 n = n.mNext;
180 }
181 }
182
183 public void setInput(Script s, Allocation a) {
184 for (int ct=0; ct < mInputs.length; ct++) {
185 if (mInputs[ct].mScript == s) {
186 mInputs[ct].mAllocation = a;
187 return;
188 }
189 }
190 throw new RSIllegalArgumentException("Script not found");
191 }
192
193 public void setOutput(Script s, Allocation a) {
194 for (int ct=0; ct < mOutputs.length; ct++) {
195 if (mOutputs[ct].mScript == s) {
196 mOutputs[ct].mAllocation = a;
197 return;
198 }
199 }
200 throw new RSIllegalArgumentException("Script not found");
201 }
202
203 public void execute() {
204 android.util.Log.v("RSR", "execute");
205 boolean more = true;
206 int depth = 0;
207 while (more) {
208 more = false;
209 for (int ct=0; ct < mNodes.length; ct++) {
210 if (mNodes[ct].mDepth == depth) {
211 more = true;
212
213 Allocation kernelIn = null;
214 for (int ct2=0; ct2 < mNodes[ct].mInputCount; ct2++) {
215 android.util.Log.v("RSR", " kin " + ct2 + ", to " + mNodes[ct].mInput[ct2].mTo[0] + ", name " + mNodes[ct].mInput[ct2].mToName[0]);
216 if (mNodes[ct].mInput[ct2].mToName[0] == null) {
217 kernelIn = mNodes[ct].mInput[ct2].mInternalAllocation;
218 break;
219 }
220 }
221
222 Allocation kernelOut= null;
223 for (int ct2=0; ct2 < mNodes[ct].mOutputCount; ct2++) {
224 android.util.Log.v("RSR", " kout " + ct2 + ", from " + mNodes[ct].mOutput[ct2].mFrom);
225 if (mNodes[ct].mOutput[ct2].mFrom != null) {
226 kernelOut = mNodes[ct].mOutput[ct2].mInternalAllocation;
227 break;
228 }
229 }
230 if (kernelOut == null) {
231 for (int ct2=0; ct2 < mOutputs.length; ct2++) {
232 if (mOutputs[ct2].mScript == mNodes[ct].mScript) {
233 kernelOut = mOutputs[ct2].mAllocation;
234 break;
235 }
236 }
237 }
238
239 android.util.Log.v("RSR", "execute calling " + mNodes[ct] + ", with " + kernelIn);
240 if (kernelIn != null) {
241 try {
242
243 Method m = mNodes[ct].mScript.getClass().getMethod("forEach_root",
244 new Class[] { Allocation.class, Allocation.class });
245 m.invoke(mNodes[ct].mScript, new Object[] {kernelIn, kernelOut} );
246 } catch (Throwable t) {
247 android.util.Log.e("RSR", "execute error " + t);
248 }
249 } else {
250 try {
251 Method m = mNodes[ct].mScript.getClass().getMethod("forEach_root",
252 new Class[] { Allocation.class });
253 m.invoke(mNodes[ct].mScript, new Object[] {kernelOut} );
254 } catch (Throwable t) {
255 android.util.Log.e("RSR", "execute error " + t);
256 }
257 }
258
259 }
260 }
261 depth ++;
262 }
263
264 }
265
266
267 public static class Builder {
268 RenderScript mRS;
269 Node mFirstNode;
270 int mConnectionCount = 0;
271 int mNodeCount = 0;
272
273 public Builder(RenderScript rs) {
274 mRS = rs;
275 }
276
277 private void validateRecurse(Node n, int depth) {
278 n.mSeen = true;
279 if (depth > n.mDepth) {
280 n.mDepth = depth;
281 }
282
283 android.util.Log.v("RSR", " validateRecurse outputCount " + n.mOutputCount);
284 for (int ct=0; ct < n.mOutputCount; ct++) {
285 for (int ct2=0; ct2 < n.mOutput[ct].mTo.length; ct2++) {
286 if (n.mOutput[ct].mTo[ct2].mSeen) {
287 throw new RSInvalidStateException("Loops in group not allowed.");
288 }
289 validateRecurse(n.mOutput[ct].mTo[ct2], depth + 1);
290 }
291 }
292 }
293
294 private void validate() {
295 android.util.Log.v("RSR", "validate");
296 Node n = mFirstNode;
297 while (n != null) {
298 n.mSeen = false;
299 n.mDepth = 0;
300 n = n.mNext;
301 }
302
303 n = mFirstNode;
304 while (n != null) {
305 android.util.Log.v("RSR", "validate n= " + n);
306 if ((n.mSeen == false) && (n.mInputCount == 0)) {
307 android.util.Log.v("RSR", " recursing " + n);
308 validateRecurse(n, 0);
309 }
310 n = n.mNext;
311 }
312 }
313
314 private Node findScript(Script s) {
315 Node n = mFirstNode;
316 while (n != null) {
317 if (n.mScript == s) {
318 return n;
319 }
320 n = n.mNext;
321 }
322 return null;
323 }
324
325 private void addNode(Node n) {
326 n.mNext = mFirstNode;
327 mFirstNode = n;
328 }
329
330 public Builder addConnection(Type t, Script output, Script input, String inputName) {
331 android.util.Log.v("RSR", "addConnection " + t +", " + output + ", " + input);
332
333 // Look for existing output
334 Node nout = findScript(output);
335 Connection c;
336 if (nout == null) {
337 // Make new node
338 android.util.Log.v("RSR", "addConnection new output node");
339 nout = new Node(output);
340 mNodeCount++;
341 c = new Connection(nout, t);
342 mConnectionCount++;
343 nout.addOutput(c);
344 addNode(nout);
345 } else {
346 // Add to existing node
347 android.util.Log.v("RSR", "addConnection reuse output node");
348 if (nout.mOutput[0] != null) {
349 if (nout.mOutput[0].mFrom.mScript != output) {
350 throw new RSInvalidStateException("Changed output of existing node");
351 }
352 if (nout.mOutput[0].mAllocationType != t) {
353 throw new RSInvalidStateException("Changed output type of existing node");
354 }
355 }
356 c = nout.mOutput[0];
357 }
358 // At this point we should have a connection attached to a script ouput.
359
360 // Find input
361 Node nin = findScript(input);
362 if (nin == null) {
363 android.util.Log.v("RSR", "addConnection new input node");
364 nin = new Node(input);
365 mNodeCount++;
366 addNode(nin);
367 }
368 c.addTo(nin, inputName);
369 nin.addInput(c);
370
371 validate();
372 return this;
373 }
374
375 public ScriptGroup create() {
376 ScriptGroup sg = new ScriptGroup(0, mRS);
377 sg.mFirstNode = mFirstNode;
378 mFirstNode = null;
379
380 android.util.Log.v("RSR", "create nodes= " + mNodeCount + ", Connections= " + mConnectionCount);
381
382 sg.init(mNodeCount, mConnectionCount);
383 return sg;
384 }
385
386 }
387
388
389}
390
391