ScriptGroup.java revision 423ebcb4dc4881c3a83e8121d5212466287d0d0c
1/* 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 392