1 /* 2 * Copyright (C) 2008-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 17 package android.renderscript; 18 19 import android.util.SparseArray; 20 21 /** 22 * The parent class for all executable scripts. This should not be used by 23 * applications. 24 **/ 25 public class Script extends BaseObj { 26 27 /** 28 * KernelID is an identifier for a Script + root function pair. It is used 29 * as an identifier for ScriptGroup creation. 30 * 31 * This class should not be directly created. Instead use the method in the 32 * reflected or intrinsic code "getKernelID_funcname()". 33 * 34 */ 35 public static final class KernelID extends BaseObj { 36 Script mScript; 37 int mSlot; 38 int mSig; KernelID(long id, RenderScript rs, Script s, int slot, int sig)39 KernelID(long id, RenderScript rs, Script s, int slot, int sig) { 40 super(id, rs); 41 mScript = s; 42 mSlot = slot; 43 mSig = sig; 44 } 45 } 46 47 private final SparseArray<KernelID> mKIDs = new SparseArray<KernelID>(); 48 /** 49 * Only to be used by generated reflected classes. 50 */ createKernelID(int slot, int sig, Element ein, Element eout)51 protected KernelID createKernelID(int slot, int sig, Element ein, 52 Element eout) { 53 KernelID k = mKIDs.get(slot); 54 if (k != null) { 55 return k; 56 } 57 58 long id = mRS.nScriptKernelIDCreate(getID(mRS), slot, sig); 59 if (id == 0) { 60 throw new RSDriverException("Failed to create KernelID"); 61 } 62 63 k = new KernelID(id, mRS, this, slot, sig); 64 mKIDs.put(slot, k); 65 return k; 66 } 67 68 /** 69 * InvokeID is an identifier for an invoke function. It is used 70 * as an identifier for ScriptGroup creation. 71 * 72 * This class should not be directly created. Instead use the method in the 73 * reflected or intrinsic code "getInvokeID_funcname()". 74 * 75 */ 76 public static final class InvokeID extends BaseObj { 77 Script mScript; 78 int mSlot; InvokeID(long id, RenderScript rs, Script s, int slot)79 InvokeID(long id, RenderScript rs, Script s, int slot) { 80 super(id, rs); 81 mScript = s; 82 mSlot = slot; 83 } 84 } 85 86 private final SparseArray<InvokeID> mIIDs = new SparseArray<InvokeID>(); 87 /** 88 * Only to be used by generated reflected classes. 89 */ createInvokeID(int slot)90 protected InvokeID createInvokeID(int slot) { 91 InvokeID i = mIIDs.get(slot); 92 if (i != null) { 93 return i; 94 } 95 96 long id = mRS.nScriptInvokeIDCreate(getID(mRS), slot); 97 if (id == 0) { 98 throw new RSDriverException("Failed to create KernelID"); 99 } 100 101 i = new InvokeID(id, mRS, this, slot); 102 mIIDs.put(slot, i); 103 return i; 104 } 105 106 /** 107 * FieldID is an identifier for a Script + exported field pair. It is used 108 * as an identifier for ScriptGroup creation. 109 * 110 * This class should not be directly created. Instead use the method in the 111 * reflected or intrinsic code "getFieldID_funcname()". 112 * 113 */ 114 public static final class FieldID extends BaseObj { 115 Script mScript; 116 int mSlot; FieldID(long id, RenderScript rs, Script s, int slot)117 FieldID(long id, RenderScript rs, Script s, int slot) { 118 super(id, rs); 119 mScript = s; 120 mSlot = slot; 121 } 122 } 123 124 private final SparseArray<FieldID> mFIDs = new SparseArray(); 125 /** 126 * Only to be used by generated reflected classes. 127 */ createFieldID(int slot, Element e)128 protected FieldID createFieldID(int slot, Element e) { 129 FieldID f = mFIDs.get(slot); 130 if (f != null) { 131 return f; 132 } 133 134 long id = mRS.nScriptFieldIDCreate(getID(mRS), slot); 135 if (id == 0) { 136 throw new RSDriverException("Failed to create FieldID"); 137 } 138 139 f = new FieldID(id, mRS, this, slot); 140 mFIDs.put(slot, f); 141 return f; 142 } 143 144 145 /** 146 * Only intended for use by generated reflected code. 147 * 148 */ invoke(int slot)149 protected void invoke(int slot) { 150 mRS.nScriptInvoke(getID(mRS), slot); 151 } 152 153 /** 154 * Only intended for use by generated reflected code. 155 * 156 */ invoke(int slot, FieldPacker v)157 protected void invoke(int slot, FieldPacker v) { 158 if (v != null) { 159 mRS.nScriptInvokeV(getID(mRS), slot, v.getData()); 160 } else { 161 mRS.nScriptInvoke(getID(mRS), slot); 162 } 163 } 164 165 /** 166 * Only intended for use by generated reflected code. 167 * 168 */ forEach(int slot, Allocation ain, Allocation aout, FieldPacker v)169 protected void forEach(int slot, Allocation ain, Allocation aout, 170 FieldPacker v) { 171 forEach(slot, ain, aout, v, null); 172 } 173 174 /** 175 * Only intended for use by generated reflected code. 176 * 177 */ forEach(int slot, Allocation ain, Allocation aout, FieldPacker v, LaunchOptions sc)178 protected void forEach(int slot, Allocation ain, Allocation aout, 179 FieldPacker v, LaunchOptions sc) { 180 // TODO: Is this necessary if nScriptForEach calls validate as well? 181 mRS.validate(); 182 mRS.validateObject(ain); 183 mRS.validateObject(aout); 184 185 if (ain == null && aout == null && sc == null) { 186 throw new RSIllegalArgumentException( 187 "At least one of input allocation, output allocation, or LaunchOptions is required to be non-null."); 188 } 189 190 long[] in_ids = null; 191 if (ain != null) { 192 in_ids = mInIdsBuffer; 193 in_ids[0] = ain.getID(mRS); 194 } 195 196 long out_id = 0; 197 if (aout != null) { 198 out_id = aout.getID(mRS); 199 } 200 201 byte[] params = null; 202 if (v != null) { 203 params = v.getData(); 204 } 205 206 int[] limits = null; 207 if (sc != null) { 208 limits = new int[6]; 209 210 limits[0] = sc.xstart; 211 limits[1] = sc.xend; 212 limits[2] = sc.ystart; 213 limits[3] = sc.yend; 214 limits[4] = sc.zstart; 215 limits[5] = sc.zend; 216 } 217 218 mRS.nScriptForEach(getID(mRS), slot, in_ids, out_id, params, limits); 219 } 220 221 /** 222 * Only intended for use by generated reflected code. 223 */ forEach(int slot, Allocation[] ains, Allocation aout, FieldPacker v)224 protected void forEach(int slot, Allocation[] ains, Allocation aout, 225 FieldPacker v) { 226 227 // FieldPacker is kept here to support regular params in the future. 228 forEach(slot, ains, aout, v, null); 229 } 230 231 /** 232 * Only intended for use by generated reflected code. 233 */ forEach(int slot, Allocation[] ains, Allocation aout, FieldPacker v, LaunchOptions sc)234 protected void forEach(int slot, Allocation[] ains, Allocation aout, 235 FieldPacker v, LaunchOptions sc) { 236 // TODO: Is this necessary if nScriptForEach calls validate as well? 237 // FieldPacker is kept here to support regular params in the future. 238 mRS.validate(); 239 if (ains != null) { 240 for (Allocation ain : ains) { 241 mRS.validateObject(ain); 242 } 243 } 244 mRS.validateObject(aout); 245 246 if (ains == null && aout == null) { 247 throw new RSIllegalArgumentException( 248 "At least one of ain or aout is required to be non-null."); 249 } 250 251 long[] in_ids; 252 if (ains != null) { 253 in_ids = new long[ains.length]; 254 for (int index = 0; index < ains.length; ++index) { 255 in_ids[index] = ains[index].getID(mRS); 256 } 257 } else { 258 in_ids = null; 259 } 260 261 long out_id = 0; 262 if (aout != null) { 263 out_id = aout.getID(mRS); 264 } 265 266 byte[] params = null; 267 if (v != null) { 268 params = v.getData(); 269 } 270 271 int[] limits = null; 272 if (sc != null) { 273 limits = new int[6]; 274 275 limits[0] = sc.xstart; 276 limits[1] = sc.xend; 277 limits[2] = sc.ystart; 278 limits[3] = sc.yend; 279 limits[4] = sc.zstart; 280 limits[5] = sc.zend; 281 } 282 283 mRS.nScriptForEach(getID(mRS), slot, in_ids, out_id, params, limits); 284 } 285 286 /** 287 * Only intended for use by generated reflected code. (General reduction) 288 * 289 */ reduce(int slot, Allocation[] ains, Allocation aout, LaunchOptions sc)290 protected void reduce(int slot, Allocation[] ains, Allocation aout, LaunchOptions sc) { 291 mRS.validate(); 292 if (ains == null || ains.length < 1) { 293 throw new RSIllegalArgumentException( 294 "At least one input is required."); 295 } 296 if (aout == null) { 297 throw new RSIllegalArgumentException( 298 "aout is required to be non-null."); 299 } 300 for (Allocation ain : ains) { 301 mRS.validateObject(ain); 302 } 303 304 long[] in_ids = new long[ains.length]; 305 for (int index = 0; index < ains.length; ++index) { 306 in_ids[index] = ains[index].getID(mRS); 307 } 308 long out_id = aout.getID(mRS); 309 310 int[] limits = null; 311 if (sc != null) { 312 limits = new int[6]; 313 314 limits[0] = sc.xstart; 315 limits[1] = sc.xend; 316 limits[2] = sc.ystart; 317 limits[3] = sc.yend; 318 limits[4] = sc.zstart; 319 limits[5] = sc.zend; 320 } 321 322 mRS.nScriptReduce(getID(mRS), slot, in_ids, out_id, limits); 323 } 324 325 long[] mInIdsBuffer; 326 Script(long id, RenderScript rs)327 Script(long id, RenderScript rs) { 328 super(id, rs); 329 330 mInIdsBuffer = new long[1]; 331 332 /* The constructors for the derived classes (including ScriptIntrinsic 333 * derived classes and ScriptC derived classes generated by Slang 334 * reflection) seem to be simple enough, so we just put the guard.open() 335 * call here, rather than in the end of the constructor for the derived 336 * class. This, of course, assumes the derived constructor would not 337 * throw any exception after calling this constructor. 338 * 339 * If new derived classes are added with more complicated constructors 340 * that throw exceptions, this call has to be (duplicated and) moved 341 * to the end of each derived class constructor. 342 */ 343 guard.open("destroy"); 344 } 345 346 /** 347 * Only intended for use by generated reflected code. 348 * 349 */ bindAllocation(Allocation va, int slot)350 public void bindAllocation(Allocation va, int slot) { 351 mRS.validate(); 352 mRS.validateObject(va); 353 if (va != null) { 354 355 android.content.Context context = mRS.getApplicationContext(); 356 357 if (context.getApplicationInfo().targetSdkVersion >= 20) { 358 final Type t = va.mType; 359 if (t.hasMipmaps() || t.hasFaces() || (t.getY() != 0) || 360 (t.getZ() != 0)) { 361 362 throw new RSIllegalArgumentException( 363 "API 20+ only allows simple 1D allocations to be " + 364 "used with bind."); 365 } 366 } 367 mRS.nScriptBindAllocation(getID(mRS), va.getID(mRS), slot); 368 } else { 369 mRS.nScriptBindAllocation(getID(mRS), 0, slot); 370 } 371 } 372 373 /** 374 * Only intended for use by generated reflected code. 375 * 376 */ setVar(int index, float v)377 public void setVar(int index, float v) { 378 mRS.nScriptSetVarF(getID(mRS), index, v); 379 } getVarF(int index)380 public float getVarF(int index) { 381 return mRS.nScriptGetVarF(getID(mRS), index); 382 } 383 384 /** 385 * Only intended for use by generated reflected code. 386 * 387 */ setVar(int index, double v)388 public void setVar(int index, double v) { 389 mRS.nScriptSetVarD(getID(mRS), index, v); 390 } getVarD(int index)391 public double getVarD(int index) { 392 return mRS.nScriptGetVarD(getID(mRS), index); 393 } 394 395 /** 396 * Only intended for use by generated reflected code. 397 * 398 */ setVar(int index, int v)399 public void setVar(int index, int v) { 400 mRS.nScriptSetVarI(getID(mRS), index, v); 401 } getVarI(int index)402 public int getVarI(int index) { 403 return mRS.nScriptGetVarI(getID(mRS), index); 404 } 405 406 407 /** 408 * Only intended for use by generated reflected code. 409 * 410 */ setVar(int index, long v)411 public void setVar(int index, long v) { 412 mRS.nScriptSetVarJ(getID(mRS), index, v); 413 } getVarJ(int index)414 public long getVarJ(int index) { 415 return mRS.nScriptGetVarJ(getID(mRS), index); 416 } 417 418 419 /** 420 * Only intended for use by generated reflected code. 421 * 422 */ setVar(int index, boolean v)423 public void setVar(int index, boolean v) { 424 mRS.nScriptSetVarI(getID(mRS), index, v ? 1 : 0); 425 } getVarB(int index)426 public boolean getVarB(int index) { 427 return mRS.nScriptGetVarI(getID(mRS), index) > 0 ? true : false; 428 } 429 430 /** 431 * Only intended for use by generated reflected code. 432 * 433 */ setVar(int index, BaseObj o)434 public void setVar(int index, BaseObj o) { 435 mRS.validate(); 436 mRS.validateObject(o); 437 mRS.nScriptSetVarObj(getID(mRS), index, (o == null) ? 0 : o.getID(mRS)); 438 } 439 440 /** 441 * Only intended for use by generated reflected code. 442 * 443 */ setVar(int index, FieldPacker v)444 public void setVar(int index, FieldPacker v) { 445 mRS.nScriptSetVarV(getID(mRS), index, v.getData()); 446 } 447 448 /** 449 * Only intended for use by generated reflected code. 450 * 451 */ setVar(int index, FieldPacker v, Element e, int[] dims)452 public void setVar(int index, FieldPacker v, Element e, int[] dims) { 453 mRS.nScriptSetVarVE(getID(mRS), index, v.getData(), e.getID(mRS), dims); 454 } 455 456 /** 457 * Only intended for use by generated reflected code. 458 * 459 */ getVarV(int index, FieldPacker v)460 public void getVarV(int index, FieldPacker v) { 461 mRS.nScriptGetVarV(getID(mRS), index, v.getData()); 462 } 463 setTimeZone(String timeZone)464 public void setTimeZone(String timeZone) { 465 mRS.validate(); 466 try { 467 mRS.nScriptSetTimeZone(getID(mRS), timeZone.getBytes("UTF-8")); 468 } catch (java.io.UnsupportedEncodingException e) { 469 throw new RuntimeException(e); 470 } 471 } 472 473 /** 474 * Only intended for use by generated reflected code. 475 * 476 */ 477 public static class Builder { 478 RenderScript mRS; 479 Builder(RenderScript rs)480 Builder(RenderScript rs) { 481 mRS = rs; 482 } 483 } 484 485 486 /** 487 * Only intended for use by generated reflected code. 488 * 489 */ 490 public static class FieldBase { 491 protected Element mElement; 492 protected Allocation mAllocation; 493 init(RenderScript rs, int dimx)494 protected void init(RenderScript rs, int dimx) { 495 mAllocation = Allocation.createSized(rs, mElement, dimx, 496 Allocation.USAGE_SCRIPT); 497 } 498 init(RenderScript rs, int dimx, int usages)499 protected void init(RenderScript rs, int dimx, int usages) { 500 mAllocation = 501 Allocation.createSized(rs, mElement, dimx, 502 Allocation.USAGE_SCRIPT | usages); 503 } 504 FieldBase()505 protected FieldBase() { 506 } 507 getElement()508 public Element getElement() { 509 return mElement; 510 } 511 getType()512 public Type getType() { 513 return mAllocation.getType(); 514 } 515 getAllocation()516 public Allocation getAllocation() { 517 return mAllocation; 518 } 519 520 //@Override updateAllocation()521 public void updateAllocation() { 522 } 523 } 524 525 526 /** 527 * Class for specifying the specifics about how a kernel will be 528 * launched. 529 * 530 * This class can specify a potential range of cells on which to 531 * run a kernel. If no set is called for a dimension then this 532 * class will have no impact on that dimension when the kernel 533 * is executed. 534 * 535 * The forEach kernel launch will operate over the intersection of 536 * the dimensions. 537 * 538 * Example: 539 * LaunchOptions with setX(5, 15) 540 * Allocation with dimension X=10, Y=10 541 * The resulting forEach run would execute over: 542 * x = 5 to 9 (inclusive) and 543 * y = 0 to 9 (inclusive). 544 * 545 * 546 */ 547 public static final class LaunchOptions { 548 private int xstart = 0; 549 private int ystart = 0; 550 private int xend = 0; 551 private int yend = 0; 552 private int zstart = 0; 553 private int zend = 0; 554 private int strategy; 555 556 /** 557 * Set the X range. xstartArg is the lowest coordinate of the range, 558 * and xendArg-1 is the highest coordinate of the range. 559 * 560 * @param xstartArg Must be >= 0 561 * @param xendArg Must be > xstartArg 562 * 563 * @return LaunchOptions 564 */ setX(int xstartArg, int xendArg)565 public LaunchOptions setX(int xstartArg, int xendArg) { 566 if (xstartArg < 0 || xendArg <= xstartArg) { 567 throw new RSIllegalArgumentException("Invalid dimensions"); 568 } 569 xstart = xstartArg; 570 xend = xendArg; 571 return this; 572 } 573 574 /** 575 * Set the Y range. ystartArg is the lowest coordinate of the range, 576 * and yendArg-1 is the highest coordinate of the range. 577 * 578 * @param ystartArg Must be >= 0 579 * @param yendArg Must be > ystartArg 580 * 581 * @return LaunchOptions 582 */ setY(int ystartArg, int yendArg)583 public LaunchOptions setY(int ystartArg, int yendArg) { 584 if (ystartArg < 0 || yendArg <= ystartArg) { 585 throw new RSIllegalArgumentException("Invalid dimensions"); 586 } 587 ystart = ystartArg; 588 yend = yendArg; 589 return this; 590 } 591 592 /** 593 * Set the Z range. zstartArg is the lowest coordinate of the range, 594 * and zendArg-1 is the highest coordinate of the range. 595 * 596 * @param zstartArg Must be >= 0 597 * @param zendArg Must be > zstartArg 598 * 599 * @return LaunchOptions 600 */ setZ(int zstartArg, int zendArg)601 public LaunchOptions setZ(int zstartArg, int zendArg) { 602 if (zstartArg < 0 || zendArg <= zstartArg) { 603 throw new RSIllegalArgumentException("Invalid dimensions"); 604 } 605 zstart = zstartArg; 606 zend = zendArg; 607 return this; 608 } 609 610 611 /** 612 * Returns the current X start 613 * 614 * @return int current value 615 */ getXStart()616 public int getXStart() { 617 return xstart; 618 } 619 /** 620 * Returns the current X end 621 * 622 * @return int current value 623 */ getXEnd()624 public int getXEnd() { 625 return xend; 626 } 627 /** 628 * Returns the current Y start 629 * 630 * @return int current value 631 */ getYStart()632 public int getYStart() { 633 return ystart; 634 } 635 /** 636 * Returns the current Y end 637 * 638 * @return int current value 639 */ getYEnd()640 public int getYEnd() { 641 return yend; 642 } 643 /** 644 * Returns the current Z start 645 * 646 * @return int current value 647 */ getZStart()648 public int getZStart() { 649 return zstart; 650 } 651 /** 652 * Returns the current Z end 653 * 654 * @return int current value 655 */ getZEnd()656 public int getZEnd() { 657 return zend; 658 } 659 660 } 661 } 662