| Yang Ni | 281c325 | 2014-10-24 08:52:24 -0700 | [diff] [blame] | 1 | package android.renderscript; |
| 2 | |
| 3 | import android.util.Log; |
| 4 | import android.util.Pair; |
| 5 | import java.util.ArrayList; |
| 6 | import java.util.HashMap; |
| 7 | import java.util.List; |
| 8 | import java.util.Map; |
| 9 | |
| 10 | /** |
| Yang Ni | 281c325 | 2014-10-24 08:52:24 -0700 | [diff] [blame] | 11 | |
| 12 | ****************************** |
| 13 | You have tried to change the API from what has been previously approved. |
| 14 | |
| 15 | To make these errors go away, you have two choices: |
| 16 | 1) You can add "@hide" javadoc comments to the methods, etc. listed in the |
| 17 | errors above. |
| 18 | |
| 19 | 2) You can update current.txt by executing the following command: |
| 20 | make update-api |
| 21 | |
| 22 | To submit the revised current.txt to the main Android repository, |
| 23 | you will need approval. |
| 24 | ****************************** |
| 25 | |
| 26 | @hide Pending Android public API approval. |
| 27 | */ |
| 28 | public class ScriptGroup2 extends BaseObj { |
| 29 | |
| 30 | public static class Closure extends BaseObj { |
| 31 | private Allocation mReturnValue; |
| 32 | private Map<Script.FieldID, Object> mBindings; |
| 33 | |
| 34 | private Future mReturnFuture; |
| 35 | private Map<Script.FieldID, Future> mGlobalFuture; |
| 36 | |
| Yang Ni | be392ad | 2015-01-23 17:16:02 -0800 | [diff] [blame] | 37 | private FieldPacker mFP; |
| 38 | |
| Yang Ni | 281c325 | 2014-10-24 08:52:24 -0700 | [diff] [blame] | 39 | private static final String TAG = "Closure"; |
| 40 | |
| 41 | public Closure(long id, RenderScript rs) { |
| 42 | super(id, rs); |
| 43 | } |
| 44 | |
| 45 | public Closure(RenderScript rs, Script.KernelID kernelID, Type returnType, |
| 46 | Object[] args, Map<Script.FieldID, Object> globals) { |
| 47 | super(0, rs); |
| 48 | |
| 49 | mReturnValue = Allocation.createTyped(rs, returnType); |
| 50 | mBindings = new HashMap<Script.FieldID, Object>(); |
| 51 | mGlobalFuture = new HashMap<Script.FieldID, Future>(); |
| 52 | |
| 53 | int numValues = args.length + globals.size(); |
| 54 | |
| 55 | long[] fieldIDs = new long[numValues]; |
| 56 | long[] values = new long[numValues]; |
| 57 | int[] sizes = new int[numValues]; |
| 58 | long[] depClosures = new long[numValues]; |
| 59 | long[] depFieldIDs = new long[numValues]; |
| 60 | |
| 61 | int i; |
| 62 | for (i = 0; i < args.length; i++) { |
| 63 | Object obj = args[i]; |
| 64 | fieldIDs[i] = 0; |
| 65 | if (obj instanceof UnboundValue) { |
| 66 | UnboundValue unbound = (UnboundValue)obj; |
| 67 | unbound.addReference(this, i); |
| 68 | } else { |
| 69 | retrieveValueAndDependenceInfo(rs, i, args[i], values, sizes, |
| 70 | depClosures, depFieldIDs); |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | for (Map.Entry<Script.FieldID, Object> entry : globals.entrySet()) { |
| 75 | Object obj = entry.getValue(); |
| 76 | Script.FieldID fieldID = entry.getKey(); |
| 77 | fieldIDs[i] = fieldID.getID(rs); |
| 78 | if (obj instanceof UnboundValue) { |
| 79 | UnboundValue unbound = (UnboundValue)obj; |
| 80 | unbound.addReference(this, fieldID); |
| 81 | } else { |
| 82 | retrieveValueAndDependenceInfo(rs, i, obj, values, |
| 83 | sizes, depClosures, depFieldIDs); |
| 84 | } |
| 85 | i++; |
| 86 | } |
| 87 | |
| 88 | long id = rs.nClosureCreate(kernelID.getID(rs), mReturnValue.getID(rs), |
| 89 | fieldIDs, values, sizes, depClosures, depFieldIDs); |
| 90 | |
| 91 | setID(id); |
| 92 | } |
| 93 | |
| Yang Ni | be392ad | 2015-01-23 17:16:02 -0800 | [diff] [blame] | 94 | public Closure(RenderScript rs, Script.InvokeID invokeID, |
| 95 | Object[] args, Map<Script.FieldID, Object> globals) { |
| 96 | super(0, rs); |
| 97 | mFP = FieldPacker.createFieldPack(args); |
| 98 | |
| 99 | mBindings = new HashMap<Script.FieldID, Object>(); |
| 100 | mGlobalFuture = new HashMap<Script.FieldID, Future>(); |
| 101 | |
| 102 | int numValues = globals.size(); |
| 103 | |
| 104 | long[] fieldIDs = new long[numValues]; |
| 105 | long[] values = new long[numValues]; |
| 106 | int[] sizes = new int[numValues]; |
| 107 | long[] depClosures = new long[numValues]; |
| 108 | long[] depFieldIDs = new long[numValues]; |
| 109 | |
| 110 | int i = 0; |
| 111 | for (Map.Entry<Script.FieldID, Object> entry : globals.entrySet()) { |
| 112 | Object obj = entry.getValue(); |
| 113 | Script.FieldID fieldID = entry.getKey(); |
| 114 | fieldIDs[i] = fieldID.getID(rs); |
| 115 | if (obj instanceof UnboundValue) { |
| 116 | UnboundValue unbound = (UnboundValue)obj; |
| 117 | unbound.addReference(this, fieldID); |
| 118 | } else { |
| 119 | // TODO(yangni): Verify obj not a future. |
| 120 | retrieveValueAndDependenceInfo(rs, i, obj, values, |
| 121 | sizes, depClosures, depFieldIDs); |
| 122 | } |
| 123 | i++; |
| 124 | } |
| 125 | |
| 126 | long id = rs.nInvokeClosureCreate(invokeID.getID(rs), mFP.getData(), fieldIDs, |
| 127 | values, sizes); |
| 128 | |
| 129 | setID(id); |
| 130 | } |
| 131 | |
| Yang Ni | 281c325 | 2014-10-24 08:52:24 -0700 | [diff] [blame] | 132 | private static void retrieveValueAndDependenceInfo(RenderScript rs, |
| 133 | int index, Object obj, long[] values, int[] sizes, long[] depClosures, |
| 134 | long[] depFieldIDs) { |
| 135 | |
| 136 | if (obj instanceof Future) { |
| 137 | Future f = (Future)obj; |
| 138 | obj = f.getValue(); |
| 139 | depClosures[index] = f.getClosure().getID(rs); |
| 140 | Script.FieldID fieldID = f.getFieldID(); |
| 141 | depFieldIDs[index] = fieldID != null ? fieldID.getID(rs) : 0; |
| Yang Ni | be392ad | 2015-01-23 17:16:02 -0800 | [diff] [blame] | 142 | if (obj == null) { |
| 143 | // Value is originally created by the owner closure |
| 144 | values[index] = 0; |
| 145 | sizes[index] = 0; |
| 146 | return; |
| 147 | } |
| Yang Ni | 281c325 | 2014-10-24 08:52:24 -0700 | [diff] [blame] | 148 | } else { |
| 149 | depClosures[index] = 0; |
| 150 | depFieldIDs[index] = 0; |
| 151 | } |
| 152 | |
| 153 | ValueAndSize vs = new ValueAndSize(rs, obj); |
| 154 | values[index] = vs.value; |
| 155 | sizes[index] = vs.size; |
| 156 | } |
| 157 | |
| 158 | public Future getReturn() { |
| 159 | if (mReturnFuture == null) { |
| 160 | mReturnFuture = new Future(this, null, mReturnValue); |
| 161 | } |
| 162 | |
| 163 | return mReturnFuture; |
| 164 | } |
| 165 | |
| 166 | public Future getGlobal(Script.FieldID field) { |
| 167 | Future f = mGlobalFuture.get(field); |
| 168 | |
| 169 | if (f == null) { |
| Yang Ni | be392ad | 2015-01-23 17:16:02 -0800 | [diff] [blame] | 170 | // If the field is not bound to this closure, this will return a future |
| 171 | // without an associated value (reference). So this is not working for |
| 172 | // cross-module (cross-script) linking in this case where a field not |
| 173 | // explicitly bound. |
| Yang Ni | 281c325 | 2014-10-24 08:52:24 -0700 | [diff] [blame] | 174 | f = new Future(this, field, mBindings.get(field)); |
| 175 | mGlobalFuture.put(field, f); |
| 176 | } |
| 177 | |
| 178 | return f; |
| 179 | } |
| 180 | |
| 181 | void setArg(int index, Object obj) { |
| 182 | ValueAndSize vs = new ValueAndSize(mRS, obj); |
| 183 | mRS.nClosureSetArg(getID(mRS), index, vs.value, vs.size); |
| 184 | } |
| 185 | |
| 186 | void setGlobal(Script.FieldID fieldID, Object obj) { |
| 187 | ValueAndSize vs = new ValueAndSize(mRS, obj); |
| 188 | mRS.nClosureSetGlobal(getID(mRS), fieldID.getID(mRS), vs.value, vs.size); |
| 189 | } |
| 190 | |
| 191 | private static final class ValueAndSize { |
| 192 | public ValueAndSize(RenderScript rs, Object obj) { |
| 193 | if (obj instanceof Allocation) { |
| 194 | value = ((Allocation)obj).getID(rs); |
| 195 | size = -1; |
| 196 | } else if (obj instanceof Boolean) { |
| 197 | value = ((Boolean)obj).booleanValue() ? 1 : 0; |
| 198 | size = 4; |
| 199 | } else if (obj instanceof Integer) { |
| 200 | value = ((Integer)obj).longValue(); |
| 201 | size = 4; |
| 202 | } else if (obj instanceof Long) { |
| 203 | value = ((Long)obj).longValue(); |
| 204 | size = 8; |
| 205 | } else if (obj instanceof Float) { |
| 206 | value = ((Float)obj).longValue(); |
| 207 | size = 4; |
| 208 | } else if (obj instanceof Double) { |
| 209 | value = ((Double)obj).longValue(); |
| 210 | size = 8; |
| 211 | } |
| 212 | } |
| Yang Ni | 281c325 | 2014-10-24 08:52:24 -0700 | [diff] [blame] | 213 | public long value; |
| 214 | public int size; |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | public static class Future { |
| 219 | Closure mClosure; |
| 220 | Script.FieldID mFieldID; |
| 221 | Object mValue; |
| 222 | |
| 223 | Future(Closure closure, Script.FieldID fieldID, Object value) { |
| 224 | mClosure = closure; |
| 225 | mFieldID = fieldID; |
| 226 | mValue = value; |
| 227 | } |
| 228 | |
| 229 | Closure getClosure() { return mClosure; } |
| 230 | Script.FieldID getFieldID() { return mFieldID; } |
| 231 | Object getValue() { return mValue; } |
| 232 | } |
| 233 | |
| 234 | public static class UnboundValue { |
| 235 | // Either mFieldID or mArgIndex should be set but not both. |
| 236 | List<Pair<Closure, Script.FieldID>> mFieldID; |
| 237 | // -1 means unset. Legal values are 0 .. n-1, where n is the number of |
| 238 | // arguments for the referencing closure. |
| 239 | List<Pair<Closure, Integer>> mArgIndex; |
| 240 | |
| 241 | UnboundValue() { |
| 242 | mFieldID = new ArrayList<Pair<Closure, Script.FieldID>>(); |
| 243 | mArgIndex = new ArrayList<Pair<Closure, Integer>>(); |
| 244 | } |
| 245 | |
| 246 | void addReference(Closure closure, int index) { |
| 247 | mArgIndex.add(Pair.create(closure, Integer.valueOf(index))); |
| 248 | } |
| 249 | |
| 250 | void addReference(Closure closure, Script.FieldID fieldID) { |
| 251 | mFieldID.add(Pair.create(closure, fieldID)); |
| 252 | } |
| 253 | |
| 254 | void set(Object value) { |
| 255 | for (Pair<Closure, Integer> p : mArgIndex) { |
| 256 | Closure closure = p.first; |
| 257 | int index = p.second.intValue(); |
| 258 | closure.setArg(index, value); |
| 259 | } |
| 260 | for (Pair<Closure, Script.FieldID> p : mFieldID) { |
| 261 | Closure closure = p.first; |
| 262 | Script.FieldID fieldID = p.second; |
| 263 | closure.setGlobal(fieldID, value); |
| 264 | } |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | List<Closure> mClosures; |
| 269 | List<UnboundValue> mInputs; |
| 270 | Future[] mOutputs; |
| 271 | |
| 272 | private static final String TAG = "ScriptGroup2"; |
| 273 | |
| 274 | public ScriptGroup2(long id, RenderScript rs) { |
| 275 | super(id, rs); |
| 276 | } |
| 277 | |
| 278 | ScriptGroup2(RenderScript rs, List<Closure> closures, |
| 279 | List<UnboundValue> inputs, Future[] outputs) { |
| 280 | super(0, rs); |
| 281 | mClosures = closures; |
| 282 | mInputs = inputs; |
| 283 | mOutputs = outputs; |
| 284 | |
| 285 | long[] closureIDs = new long[closures.size()]; |
| 286 | for (int i = 0; i < closureIDs.length; i++) { |
| 287 | closureIDs[i] = closures.get(i).getID(rs); |
| 288 | } |
| Yang Ni | ebf6340 | 2015-01-16 11:06:26 -0800 | [diff] [blame] | 289 | long id = rs.nScriptGroup2Create(ScriptC.mCachePath, closureIDs); |
| Yang Ni | 281c325 | 2014-10-24 08:52:24 -0700 | [diff] [blame] | 290 | setID(id); |
| 291 | } |
| 292 | |
| Yang Ni | 281c325 | 2014-10-24 08:52:24 -0700 | [diff] [blame] | 293 | public Object[] execute(Object... inputs) { |
| 294 | if (inputs.length < mInputs.size()) { |
| 295 | Log.e(TAG, this.toString() + " receives " + inputs.length + " inputs, " + |
| 296 | "less than expected " + mInputs.size()); |
| 297 | return null; |
| 298 | } |
| 299 | |
| 300 | if (inputs.length > mInputs.size()) { |
| 301 | Log.i(TAG, this.toString() + " receives " + inputs.length + " inputs, " + |
| 302 | "more than expected " + mInputs.size()); |
| 303 | } |
| 304 | |
| 305 | for (int i = 0; i < mInputs.size(); i++) { |
| 306 | Object obj = inputs[i]; |
| 307 | if (obj instanceof Future || obj instanceof UnboundValue) { |
| 308 | Log.e(TAG, this.toString() + ": input " + i + |
| 309 | " is a future or unbound value"); |
| 310 | return null; |
| 311 | } |
| 312 | UnboundValue unbound = mInputs.get(i); |
| 313 | unbound.set(obj); |
| 314 | } |
| 315 | |
| 316 | mRS.nScriptGroup2Execute(getID(mRS)); |
| 317 | |
| 318 | Object[] outputObjs = new Object[mOutputs.length]; |
| 319 | int i = 0; |
| 320 | for (Future f : mOutputs) { |
| 321 | outputObjs[i++] = f.getValue(); |
| 322 | } |
| 323 | return outputObjs; |
| 324 | } |
| 325 | |
| 326 | /** |
| 327 | @hide Pending Android public API approval. |
| 328 | */ |
| 329 | public static final class Builder { |
| 330 | RenderScript mRS; |
| 331 | List<Closure> mClosures; |
| 332 | List<UnboundValue> mInputs; |
| 333 | |
| 334 | private static final String TAG = "ScriptGroup2.Builder"; |
| 335 | |
| 336 | public Builder(RenderScript rs) { |
| 337 | mRS = rs; |
| 338 | mClosures = new ArrayList<Closure>(); |
| 339 | mInputs = new ArrayList<UnboundValue>(); |
| 340 | } |
| 341 | |
| 342 | public Closure addKernel(Script.KernelID k, Type returnType, Object[] args, |
| 343 | Map<Script.FieldID, Object> globalBindings) { |
| 344 | Closure c = new Closure(mRS, k, returnType, args, globalBindings); |
| 345 | mClosures.add(c); |
| 346 | return c; |
| 347 | } |
| 348 | |
| Yang Ni | be392ad | 2015-01-23 17:16:02 -0800 | [diff] [blame] | 349 | public Closure addInvoke(Script.InvokeID invoke, Object[] args, |
| 350 | Map<Script.FieldID, Object> globalBindings) { |
| 351 | Closure c = new Closure(mRS, invoke, args, globalBindings); |
| 352 | mClosures.add(c); |
| 353 | return c; |
| 354 | } |
| 355 | |
| Yang Ni | 281c325 | 2014-10-24 08:52:24 -0700 | [diff] [blame] | 356 | public UnboundValue addInput() { |
| 357 | UnboundValue unbound = new UnboundValue(); |
| 358 | mInputs.add(unbound); |
| 359 | return unbound; |
| 360 | } |
| 361 | |
| 362 | public ScriptGroup2 create(Future... outputs) { |
| Yang Ni | 281c325 | 2014-10-24 08:52:24 -0700 | [diff] [blame] | 363 | ScriptGroup2 ret = new ScriptGroup2(mRS, mClosures, mInputs, outputs); |
| 364 | return ret; |
| 365 | } |
| 366 | |
| 367 | } |
| 368 | } |