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 java.io.IOException; 20 import java.io.InputStream; 21 import java.util.HashMap; 22 import android.content.res.Resources; 23 import android.content.res.AssetManager; 24 import android.graphics.Bitmap; 25 import android.graphics.BitmapFactory; 26 import android.view.Surface; 27 import android.graphics.SurfaceTexture; 28 import android.util.Log; 29 import android.util.TypedValue; 30 import android.graphics.Canvas; 31 32 /** 33 * <p> This class provides the primary method through which data is passed to 34 * and from RenderScript kernels. An Allocation provides the backing store for 35 * a given {@link android.renderscript.Type}. </p> 36 * 37 * <p>An Allocation also contains a set of usage flags that denote how the 38 * Allocation could be used. For example, an Allocation may have usage flags 39 * specifying that it can be used from a script as well as input to a {@link 40 * android.renderscript.Sampler}. A developer must synchronize across these 41 * different usages using {@link android.renderscript.Allocation#syncAll} in 42 * order to ensure that different users of the Allocation have a consistent view 43 * of memory. For example, in the case where an Allocation is used as the output 44 * of one kernel and as Sampler input in a later kernel, a developer must call 45 * {@link #syncAll syncAll(Allocation.USAGE_SCRIPT)} prior to launching the 46 * second kernel to ensure correctness. 47 * 48 * <p>An Allocation can be populated with the {@link #copyFrom} routines. For 49 * more complex Element types, the {@link #copyFromUnchecked} methods can be 50 * used to copy from byte arrays or similar constructs.</p> 51 * 52 * <div class="special reference"> 53 * <h3>Developer Guides</h3> 54 * <p>For more information about creating an application that uses RenderScript, read the 55 * <a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a> developer guide.</p> 56 * </div> 57 **/ 58 public class Allocation extends BaseObj { 59 Type mType; 60 Bitmap mBitmap; 61 int mUsage; 62 Allocation mAdaptedAllocation; 63 64 boolean mConstrainedLOD; 65 boolean mConstrainedFace; 66 boolean mConstrainedY; 67 boolean mConstrainedZ; 68 boolean mReadAllowed = true; 69 boolean mWriteAllowed = true; 70 int mSelectedY; 71 int mSelectedZ; 72 int mSelectedLOD; 73 Type.CubemapFace mSelectedFace = Type.CubemapFace.POSITIVE_X; 74 75 int mCurrentDimX; 76 int mCurrentDimY; 77 int mCurrentDimZ; 78 int mCurrentCount; 79 static HashMap<Integer, Allocation> mAllocationMap = 80 new HashMap<Integer, Allocation>(); 81 IoInputNotifier mBufferNotifier; 82 83 /** 84 * The usage of the Allocation. These signal to RenderScript where to place 85 * the Allocation in memory. 86 * 87 */ 88 89 /** 90 * The Allocation will be bound to and accessed by scripts. 91 */ 92 public static final int USAGE_SCRIPT = 0x0001; 93 94 /** 95 * The Allocation will be used as a texture source by one or more graphics 96 * programs. 97 * 98 */ 99 public static final int USAGE_GRAPHICS_TEXTURE = 0x0002; 100 101 /** 102 * The Allocation will be used as a graphics mesh. 103 * 104 * This was deprecated in API level 16. 105 * 106 */ 107 public static final int USAGE_GRAPHICS_VERTEX = 0x0004; 108 109 110 /** 111 * The Allocation will be used as the source of shader constants by one or 112 * more programs. 113 * 114 * This was deprecated in API level 16. 115 * 116 */ 117 public static final int USAGE_GRAPHICS_CONSTANTS = 0x0008; 118 119 /** 120 * The Allocation will be used as a target for offscreen rendering 121 * 122 * This was deprecated in API level 16. 123 * 124 */ 125 public static final int USAGE_GRAPHICS_RENDER_TARGET = 0x0010; 126 127 /** 128 * The Allocation will be used as a {@link android.graphics.SurfaceTexture} 129 * consumer. This usage will cause the Allocation to be created as 130 * read-only. 131 * 132 */ 133 public static final int USAGE_IO_INPUT = 0x0020; 134 135 /** 136 * The Allocation will be used as a {@link android.graphics.SurfaceTexture} 137 * producer. The dimensions and format of the {@link 138 * android.graphics.SurfaceTexture} will be forced to those of the 139 * Allocation. 140 * 141 */ 142 public static final int USAGE_IO_OUTPUT = 0x0040; 143 144 /** 145 * The Allocation's backing store will be inherited from another object 146 * (usually a {@link android.graphics.Bitmap}); copying to or from the 147 * original source Bitmap will cause a synchronization rather than a full 148 * copy. {@link #syncAll} may also be used to synchronize the Allocation 149 * and the source Bitmap. 150 * 151 * <p>This is set by default for allocations created with {@link 152 * #createFromBitmap} in API version 18 and higher.</p> 153 * 154 */ 155 public static final int USAGE_SHARED = 0x0080; 156 157 /** 158 * Controls mipmap behavior when using the bitmap creation and update 159 * functions. 160 */ 161 public enum MipmapControl { 162 /** 163 * No mipmaps will be generated and the type generated from the incoming 164 * bitmap will not contain additional LODs. 165 */ 166 MIPMAP_NONE(0), 167 168 /** 169 * A full mipmap chain will be created in script memory. The Type of 170 * the Allocation will contain a full mipmap chain. On upload, the full 171 * chain will be transferred. 172 */ 173 MIPMAP_FULL(1), 174 175 /** 176 * The Type of the Allocation will be the same as MIPMAP_NONE. It will 177 * not contain mipmaps. On upload, the allocation data will contain a 178 * full mipmap chain generated from the top level in script memory. 179 */ 180 MIPMAP_ON_SYNC_TO_TEXTURE(2); 181 182 int mID; 183 MipmapControl(int id) { 184 mID = id; 185 } 186 } 187 188 189 private int getIDSafe() { 190 if (mAdaptedAllocation != null) { 191 return mAdaptedAllocation.getID(mRS); 192 } 193 return getID(mRS); 194 } 195 196 197 /** 198 * Get the {@link android.renderscript.Element} of the {@link 199 * android.renderscript.Type} of the Allocation. 200 * 201 * @return Element 202 * 203 */ 204 public Element getElement() { 205 return mType.getElement(); 206 } 207 208 /** 209 * Get the usage flags of the Allocation. 210 * 211 * @return usage this Allocation's set of the USAGE_* flags OR'd together 212 * 213 */ 214 public int getUsage() { 215 return mUsage; 216 } 217 218 /** 219 * Get the size of the Allocation in bytes. 220 * 221 * @return size of the Allocation in bytes. 222 * 223 */ 224 public int getBytesSize() { 225 return mType.getCount() * mType.getElement().getBytesSize(); 226 } 227 228 private void updateCacheInfo(Type t) { 229 mCurrentDimX = t.getX(); 230 mCurrentDimY = t.getY(); 231 mCurrentDimZ = t.getZ(); 232 mCurrentCount = mCurrentDimX; 233 if (mCurrentDimY > 1) { 234 mCurrentCount *= mCurrentDimY; 235 } 236 if (mCurrentDimZ > 1) { 237 mCurrentCount *= mCurrentDimZ; 238 } 239 } 240 241 private void setBitmap(Bitmap b) { 242 mBitmap = b; 243 } 244 245 Allocation(int id, RenderScript rs, Type t, int usage) { 246 super(id, rs); 247 if ((usage & ~(USAGE_SCRIPT | 248 USAGE_GRAPHICS_TEXTURE | 249 USAGE_GRAPHICS_VERTEX | 250 USAGE_GRAPHICS_CONSTANTS | 251 USAGE_GRAPHICS_RENDER_TARGET | 252 USAGE_IO_INPUT | 253 USAGE_IO_OUTPUT | 254 USAGE_SHARED)) != 0) { 255 throw new RSIllegalArgumentException("Unknown usage specified."); 256 } 257 258 if ((usage & USAGE_IO_INPUT) != 0) { 259 mWriteAllowed = false; 260 261 if ((usage & ~(USAGE_IO_INPUT | 262 USAGE_GRAPHICS_TEXTURE | 263 USAGE_SCRIPT)) != 0) { 264 throw new RSIllegalArgumentException("Invalid usage combination."); 265 } 266 } 267 268 mType = t; 269 mUsage = usage; 270 271 if (t != null) { 272 updateCacheInfo(t); 273 } 274 } 275 276 private void validateIsInt32() { 277 if ((mType.mElement.mType == Element.DataType.SIGNED_32) || 278 (mType.mElement.mType == Element.DataType.UNSIGNED_32)) { 279 return; 280 } 281 throw new RSIllegalArgumentException( 282 "32 bit integer source does not match allocation type " + mType.mElement.mType); 283 } 284 285 private void validateIsInt16() { 286 if ((mType.mElement.mType == Element.DataType.SIGNED_16) || 287 (mType.mElement.mType == Element.DataType.UNSIGNED_16)) { 288 return; 289 } 290 throw new RSIllegalArgumentException( 291 "16 bit integer source does not match allocation type " + mType.mElement.mType); 292 } 293 294 private void validateIsInt8() { 295 if ((mType.mElement.mType == Element.DataType.SIGNED_8) || 296 (mType.mElement.mType == Element.DataType.UNSIGNED_8)) { 297 return; 298 } 299 throw new RSIllegalArgumentException( 300 "8 bit integer source does not match allocation type " + mType.mElement.mType); 301 } 302 303 private void validateIsFloat32() { 304 if (mType.mElement.mType == Element.DataType.FLOAT_32) { 305 return; 306 } 307 throw new RSIllegalArgumentException( 308 "32 bit float source does not match allocation type " + mType.mElement.mType); 309 } 310 311 private void validateIsObject() { 312 if ((mType.mElement.mType == Element.DataType.RS_ELEMENT) || 313 (mType.mElement.mType == Element.DataType.RS_TYPE) || 314 (mType.mElement.mType == Element.DataType.RS_ALLOCATION) || 315 (mType.mElement.mType == Element.DataType.RS_SAMPLER) || 316 (mType.mElement.mType == Element.DataType.RS_SCRIPT) || 317 (mType.mElement.mType == Element.DataType.RS_MESH) || 318 (mType.mElement.mType == Element.DataType.RS_PROGRAM_FRAGMENT) || 319 (mType.mElement.mType == Element.DataType.RS_PROGRAM_VERTEX) || 320 (mType.mElement.mType == Element.DataType.RS_PROGRAM_RASTER) || 321 (mType.mElement.mType == Element.DataType.RS_PROGRAM_STORE)) { 322 return; 323 } 324 throw new RSIllegalArgumentException( 325 "Object source does not match allocation type " + mType.mElement.mType); 326 } 327 328 @Override 329 void updateFromNative() { 330 super.updateFromNative(); 331 int typeID = mRS.nAllocationGetType(getID(mRS)); 332 if(typeID != 0) { 333 mType = new Type(typeID, mRS); 334 mType.updateFromNative(); 335 updateCacheInfo(mType); 336 } 337 } 338 339 /** 340 * Get the {@link android.renderscript.Type} of the Allocation. 341 * 342 * @return Type 343 * 344 */ 345 public Type getType() { 346 return mType; 347 } 348 349 /** 350 * Propagate changes from one usage of the Allocation to the 351 * other usages of the Allocation. 352 * 353 */ 354 public void syncAll(int srcLocation) { 355 switch (srcLocation) { 356 case USAGE_GRAPHICS_TEXTURE: 357 case USAGE_SCRIPT: 358 if ((mUsage & USAGE_SHARED) != 0) { 359 copyFrom(mBitmap); 360 } 361 break; 362 case USAGE_GRAPHICS_CONSTANTS: 363 case USAGE_GRAPHICS_VERTEX: 364 break; 365 case USAGE_SHARED: 366 if ((mUsage & USAGE_SHARED) != 0) { 367 copyTo(mBitmap); 368 } 369 break; 370 default: 371 throw new RSIllegalArgumentException("Source must be exactly one usage type."); 372 } 373 mRS.validate(); 374 mRS.nAllocationSyncAll(getIDSafe(), srcLocation); 375 } 376 377 /** 378 * Send a buffer to the output stream. The contents of the Allocation will 379 * be undefined after this operation. This operation is only valid if {@link 380 * #USAGE_IO_OUTPUT} is set on the Allocation. 381 * 382 * 383 */ 384 public void ioSend() { 385 if ((mUsage & USAGE_IO_OUTPUT) == 0) { 386 throw new RSIllegalArgumentException( 387 "Can only send buffer if IO_OUTPUT usage specified."); 388 } 389 mRS.validate(); 390 mRS.nAllocationIoSend(getID(mRS)); 391 } 392 393 /** 394 * Delete once code is updated. 395 * @hide 396 */ 397 public void ioSendOutput() { 398 ioSend(); 399 } 400 401 /** 402 * Receive the latest input into the Allocation. This operation 403 * is only valid if {@link #USAGE_IO_INPUT} is set on the Allocation. 404 * 405 */ 406 public void ioReceive() { 407 if ((mUsage & USAGE_IO_INPUT) == 0) { 408 throw new RSIllegalArgumentException( 409 "Can only receive if IO_INPUT usage specified."); 410 } 411 mRS.validate(); 412 mRS.nAllocationIoReceive(getID(mRS)); 413 } 414 415 /** 416 * Copy an array of RS objects to the Allocation. 417 * 418 * @param d Source array. 419 */ 420 public void copyFrom(BaseObj[] d) { 421 mRS.validate(); 422 validateIsObject(); 423 if (d.length != mCurrentCount) { 424 throw new RSIllegalArgumentException("Array size mismatch, allocation sizeX = " + 425 mCurrentCount + ", array length = " + d.length); 426 } 427 int i[] = new int[d.length]; 428 for (int ct=0; ct < d.length; ct++) { 429 i[ct] = d[ct].getID(mRS); 430 } 431 copy1DRangeFromUnchecked(0, mCurrentCount, i); 432 } 433 434 private void validateBitmapFormat(Bitmap b) { 435 Bitmap.Config bc = b.getConfig(); 436 if (bc == null) { 437 throw new RSIllegalArgumentException("Bitmap has an unsupported format for this operation"); 438 } 439 switch (bc) { 440 case ALPHA_8: 441 if (mType.getElement().mKind != Element.DataKind.PIXEL_A) { 442 throw new RSIllegalArgumentException("Allocation kind is " + 443 mType.getElement().mKind + ", type " + 444 mType.getElement().mType + 445 " of " + mType.getElement().getBytesSize() + 446 " bytes, passed bitmap was " + bc); 447 } 448 break; 449 case ARGB_8888: 450 if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) || 451 (mType.getElement().getBytesSize() != 4)) { 452 throw new RSIllegalArgumentException("Allocation kind is " + 453 mType.getElement().mKind + ", type " + 454 mType.getElement().mType + 455 " of " + mType.getElement().getBytesSize() + 456 " bytes, passed bitmap was " + bc); 457 } 458 break; 459 case RGB_565: 460 if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGB) || 461 (mType.getElement().getBytesSize() != 2)) { 462 throw new RSIllegalArgumentException("Allocation kind is " + 463 mType.getElement().mKind + ", type " + 464 mType.getElement().mType + 465 " of " + mType.getElement().getBytesSize() + 466 " bytes, passed bitmap was " + bc); 467 } 468 break; 469 case ARGB_4444: 470 if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) || 471 (mType.getElement().getBytesSize() != 2)) { 472 throw new RSIllegalArgumentException("Allocation kind is " + 473 mType.getElement().mKind + ", type " + 474 mType.getElement().mType + 475 " of " + mType.getElement().getBytesSize() + 476 " bytes, passed bitmap was " + bc); 477 } 478 break; 479 480 } 481 } 482 483 private void validateBitmapSize(Bitmap b) { 484 if((mCurrentDimX != b.getWidth()) || (mCurrentDimY != b.getHeight())) { 485 throw new RSIllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch"); 486 } 487 } 488 489 /** 490 * Copy into this Allocation from an array. This method does not guarantee 491 * that the Allocation is compatible with the input buffer; it copies memory 492 * without reinterpretation. 493 * 494 * @param d the source data array 495 */ 496 public void copyFromUnchecked(int[] d) { 497 mRS.validate(); 498 if (mCurrentDimZ > 0) { 499 copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d); 500 } else if (mCurrentDimY > 0) { 501 copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d); 502 } else { 503 copy1DRangeFromUnchecked(0, mCurrentCount, d); 504 } 505 } 506 /** 507 * Copy into this Allocation from an array. This method does not guarantee 508 * that the Allocation is compatible with the input buffer; it copies memory 509 * without reinterpretation. 510 * 511 * @param d the source data array 512 */ 513 public void copyFromUnchecked(short[] d) { 514 mRS.validate(); 515 if (mCurrentDimZ > 0) { 516 copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d); 517 } else if (mCurrentDimY > 0) { 518 copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d); 519 } else { 520 copy1DRangeFromUnchecked(0, mCurrentCount, d); 521 } 522 } 523 /** 524 * Copy into this Allocation from an array. This method does not guarantee 525 * that the Allocation is compatible with the input buffer; it copies memory 526 * without reinterpretation. 527 * 528 * @param d the source data array 529 */ 530 public void copyFromUnchecked(byte[] d) { 531 mRS.validate(); 532 if (mCurrentDimZ > 0) { 533 copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d); 534 } else if (mCurrentDimY > 0) { 535 copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d); 536 } else { 537 copy1DRangeFromUnchecked(0, mCurrentCount, d); 538 } 539 } 540 /** 541 * Copy into this Allocation from an array. This method does not guarantee 542 * that the Allocation is compatible with the input buffer; it copies memory 543 * without reinterpretation. 544 * 545 * @param d the source data array 546 */ 547 public void copyFromUnchecked(float[] d) { 548 mRS.validate(); 549 if (mCurrentDimZ > 0) { 550 copy3DRangeFromUnchecked(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d); 551 } else if (mCurrentDimY > 0) { 552 copy2DRangeFromUnchecked(0, 0, mCurrentDimX, mCurrentDimY, d); 553 } else { 554 copy1DRangeFromUnchecked(0, mCurrentCount, d); 555 } 556 } 557 558 /** 559 * Copy into this Allocation from an array. This variant is type checked 560 * and will generate exceptions if the Allocation's {@link 561 * android.renderscript.Element} is not a 32 bit integer type. 562 * 563 * @param d the source data array 564 */ 565 public void copyFrom(int[] d) { 566 mRS.validate(); 567 if (mCurrentDimZ > 0) { 568 copy3DRangeFrom(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d); 569 } else if (mCurrentDimY > 0) { 570 copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d); 571 } else { 572 copy1DRangeFrom(0, mCurrentCount, d); 573 } 574 } 575 576 /** 577 * Copy into this Allocation from an array. This variant is type checked 578 * and will generate exceptions if the Allocation's {@link 579 * android.renderscript.Element} is not a 16 bit integer type. 580 * 581 * @param d the source data array 582 */ 583 public void copyFrom(short[] d) { 584 mRS.validate(); 585 if (mCurrentDimZ > 0) { 586 copy3DRangeFrom(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d); 587 } else if (mCurrentDimY > 0) { 588 copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d); 589 } else { 590 copy1DRangeFrom(0, mCurrentCount, d); 591 } 592 } 593 594 /** 595 * Copy into this Allocation from an array. This variant is type checked 596 * and will generate exceptions if the Allocation's {@link 597 * android.renderscript.Element} is not an 8 bit integer type. 598 * 599 * @param d the source data array 600 */ 601 public void copyFrom(byte[] d) { 602 mRS.validate(); 603 if (mCurrentDimZ > 0) { 604 copy3DRangeFrom(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d); 605 } else if (mCurrentDimY > 0) { 606 copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d); 607 } else { 608 copy1DRangeFrom(0, mCurrentCount, d); 609 } 610 } 611 612 /** 613 * Copy into this Allocation from an array. This variant is type checked 614 * and will generate exceptions if the Allocation's {@link 615 * android.renderscript.Element} is not a 32 bit float type. 616 * 617 * @param d the source data array 618 */ 619 public void copyFrom(float[] d) { 620 mRS.validate(); 621 if (mCurrentDimZ > 0) { 622 copy3DRangeFrom(0, 0, 0, mCurrentDimX, mCurrentDimY, mCurrentDimZ, d); 623 } else if (mCurrentDimY > 0) { 624 copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, d); 625 } else { 626 copy1DRangeFrom(0, mCurrentCount, d); 627 } 628 } 629 630 /** 631 * Copy into an Allocation from a {@link android.graphics.Bitmap}. The 632 * height, width, and format of the bitmap must match the existing 633 * allocation. 634 * 635 * <p>If the {@link android.graphics.Bitmap} is the same as the {@link 636 * android.graphics.Bitmap} used to create the Allocation with {@link 637 * #createFromBitmap} and {@link #USAGE_SHARED} is set on the Allocation, 638 * this will synchronize the Allocation with the latest data from the {@link 639 * android.graphics.Bitmap}, potentially avoiding the actual copy.</p> 640 * 641 * @param b the source bitmap 642 */ 643 public void copyFrom(Bitmap b) { 644 mRS.validate(); 645 if (b.getConfig() == null) { 646 Bitmap newBitmap = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ARGB_8888); 647 Canvas c = new Canvas(newBitmap); 648 c.drawBitmap(b, 0, 0, null); 649 copyFrom(newBitmap); 650 return; 651 } 652 validateBitmapSize(b); 653 validateBitmapFormat(b); 654 mRS.nAllocationCopyFromBitmap(getID(mRS), b); 655 } 656 657 /** 658 * Copy an Allocation from an Allocation. The types of both allocations 659 * must be identical. 660 * 661 * @param a the source allocation 662 */ 663 public void copyFrom(Allocation a) { 664 mRS.validate(); 665 if (!mType.equals(a.getType())) { 666 throw new RSIllegalArgumentException("Types of allocations must match."); 667 } 668 copy2DRangeFrom(0, 0, mCurrentDimX, mCurrentDimY, a, 0, 0); 669 } 670 671 672 /** 673 * This is only intended to be used by auto-generated code reflected from 674 * the RenderScript script files and should not be used by developers. 675 * 676 * @param xoff 677 * @param fp 678 */ 679 public void setFromFieldPacker(int xoff, FieldPacker fp) { 680 mRS.validate(); 681 int eSize = mType.mElement.getBytesSize(); 682 final byte[] data = fp.getData(); 683 684 int count = data.length / eSize; 685 if ((eSize * count) != data.length) { 686 throw new RSIllegalArgumentException("Field packer length " + data.length + 687 " not divisible by element size " + eSize + "."); 688 } 689 copy1DRangeFromUnchecked(xoff, count, data); 690 } 691 692 /** 693 * This is only intended to be used by auto-generated code reflected from 694 * the RenderScript script files. 695 * 696 * @param xoff 697 * @param component_number 698 * @param fp 699 */ 700 public void setFromFieldPacker(int xoff, int component_number, FieldPacker fp) { 701 mRS.validate(); 702 if (component_number >= mType.mElement.mElements.length) { 703 throw new RSIllegalArgumentException("Component_number " + component_number + " out of range."); 704 } 705 if(xoff < 0) { 706 throw new RSIllegalArgumentException("Offset must be >= 0."); 707 } 708 709 final byte[] data = fp.getData(); 710 int eSize = mType.mElement.mElements[component_number].getBytesSize(); 711 eSize *= mType.mElement.mArraySizes[component_number]; 712 713 if (data.length != eSize) { 714 throw new RSIllegalArgumentException("Field packer sizelength " + data.length + 715 " does not match component size " + eSize + "."); 716 } 717 718 mRS.nAllocationElementData1D(getIDSafe(), xoff, mSelectedLOD, 719 component_number, data, data.length); 720 } 721 722 private void data1DChecks(int off, int count, int len, int dataSize) { 723 mRS.validate(); 724 if(off < 0) { 725 throw new RSIllegalArgumentException("Offset must be >= 0."); 726 } 727 if(count < 1) { 728 throw new RSIllegalArgumentException("Count must be >= 1."); 729 } 730 if((off + count) > mCurrentCount) { 731 throw new RSIllegalArgumentException("Overflow, Available count " + mCurrentCount + 732 ", got " + count + " at offset " + off + "."); 733 } 734 if(len < dataSize) { 735 throw new RSIllegalArgumentException("Array too small for allocation type."); 736 } 737 } 738 739 /** 740 * Generate a mipmap chain. This is only valid if the Type of the Allocation 741 * includes mipmaps. 742 * 743 * <p>This function will generate a complete set of mipmaps from the top 744 * level LOD and place them into the script memory space.</p> 745 * 746 * <p>If the Allocation is also using other memory spaces, a call to {@link 747 * #syncAll syncAll(Allocation.USAGE_SCRIPT)} is required.</p> 748 */ 749 public void generateMipmaps() { 750 mRS.nAllocationGenerateMipmaps(getID(mRS)); 751 } 752 753 /** 754 * Copy an array into part of this Allocation. This method does not 755 * guarantee that the Allocation is compatible with the input buffer. 756 * 757 * @param off The offset of the first element to be copied. 758 * @param count The number of elements to be copied. 759 * @param d the source data array 760 */ 761 public void copy1DRangeFromUnchecked(int off, int count, int[] d) { 762 int dataSize = mType.mElement.getBytesSize() * count; 763 data1DChecks(off, count, d.length * 4, dataSize); 764 mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize); 765 } 766 /** 767 * Copy an array into part of this Allocation. This method does not 768 * guarantee that the Allocation is compatible with the input buffer. 769 * 770 * @param off The offset of the first element to be copied. 771 * @param count The number of elements to be copied. 772 * @param d the source data array 773 */ 774 public void copy1DRangeFromUnchecked(int off, int count, short[] d) { 775 int dataSize = mType.mElement.getBytesSize() * count; 776 data1DChecks(off, count, d.length * 2, dataSize); 777 mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize); 778 } 779 /** 780 * Copy an array into part of this Allocation. This method does not 781 * guarantee that the Allocation is compatible with the input buffer. 782 * 783 * @param off The offset of the first element to be copied. 784 * @param count The number of elements to be copied. 785 * @param d the source data array 786 */ 787 public void copy1DRangeFromUnchecked(int off, int count, byte[] d) { 788 int dataSize = mType.mElement.getBytesSize() * count; 789 data1DChecks(off, count, d.length, dataSize); 790 mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize); 791 } 792 /** 793 * Copy an array into part of this Allocation. This method does not 794 * guarantee that the Allocation is compatible with the input buffer. 795 * 796 * @param off The offset of the first element to be copied. 797 * @param count The number of elements to be copied. 798 * @param d the source data array 799 */ 800 public void copy1DRangeFromUnchecked(int off, int count, float[] d) { 801 int dataSize = mType.mElement.getBytesSize() * count; 802 data1DChecks(off, count, d.length * 4, dataSize); 803 mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize); 804 } 805 806 /** 807 * Copy an array into part of this Allocation. This variant is type checked 808 * and will generate exceptions if the Allocation type is not a 32 bit 809 * integer type. 810 * 811 * @param off The offset of the first element to be copied. 812 * @param count The number of elements to be copied. 813 * @param d the source data array 814 */ 815 public void copy1DRangeFrom(int off, int count, int[] d) { 816 validateIsInt32(); 817 copy1DRangeFromUnchecked(off, count, d); 818 } 819 820 /** 821 * Copy an array into part of this Allocation. This variant is type checked 822 * and will generate exceptions if the Allocation type is not a 16 bit 823 * integer type. 824 * 825 * @param off The offset of the first element to be copied. 826 * @param count The number of elements to be copied. 827 * @param d the source data array 828 */ 829 public void copy1DRangeFrom(int off, int count, short[] d) { 830 validateIsInt16(); 831 copy1DRangeFromUnchecked(off, count, d); 832 } 833 834 /** 835 * Copy an array into part of this Allocation. This variant is type checked 836 * and will generate exceptions if the Allocation type is not an 8 bit 837 * integer type. 838 * 839 * @param off The offset of the first element to be copied. 840 * @param count The number of elements to be copied. 841 * @param d the source data array 842 */ 843 public void copy1DRangeFrom(int off, int count, byte[] d) { 844 validateIsInt8(); 845 copy1DRangeFromUnchecked(off, count, d); 846 } 847 848 /** 849 * Copy an array into part of this Allocation. This variant is type checked 850 * and will generate exceptions if the Allocation type is not a 32 bit float 851 * type. 852 * 853 * @param off The offset of the first element to be copied. 854 * @param count The number of elements to be copied. 855 * @param d the source data array. 856 */ 857 public void copy1DRangeFrom(int off, int count, float[] d) { 858 validateIsFloat32(); 859 copy1DRangeFromUnchecked(off, count, d); 860 } 861 862 /** 863 * Copy part of an Allocation into this Allocation. 864 * 865 * @param off The offset of the first element to be copied. 866 * @param count The number of elements to be copied. 867 * @param data the source data allocation. 868 * @param dataOff off The offset of the first element in data to 869 * be copied. 870 */ 871 public void copy1DRangeFrom(int off, int count, Allocation data, int dataOff) { 872 mRS.nAllocationData2D(getIDSafe(), off, 0, 873 mSelectedLOD, mSelectedFace.mID, 874 count, 1, data.getID(mRS), dataOff, 0, 875 data.mSelectedLOD, data.mSelectedFace.mID); 876 } 877 878 private void validate2DRange(int xoff, int yoff, int w, int h) { 879 if (mAdaptedAllocation != null) { 880 881 } else { 882 883 if (xoff < 0 || yoff < 0) { 884 throw new RSIllegalArgumentException("Offset cannot be negative."); 885 } 886 if (h < 0 || w < 0) { 887 throw new RSIllegalArgumentException("Height or width cannot be negative."); 888 } 889 if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY)) { 890 throw new RSIllegalArgumentException("Updated region larger than allocation."); 891 } 892 } 893 } 894 895 void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, byte[] data) { 896 mRS.validate(); 897 validate2DRange(xoff, yoff, w, h); 898 mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, 899 w, h, data, data.length); 900 } 901 902 void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, short[] data) { 903 mRS.validate(); 904 validate2DRange(xoff, yoff, w, h); 905 mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, 906 w, h, data, data.length * 2); 907 } 908 909 void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, int[] data) { 910 mRS.validate(); 911 validate2DRange(xoff, yoff, w, h); 912 mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, 913 w, h, data, data.length * 4); 914 } 915 916 void copy2DRangeFromUnchecked(int xoff, int yoff, int w, int h, float[] data) { 917 mRS.validate(); 918 validate2DRange(xoff, yoff, w, h); 919 mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, 920 w, h, data, data.length * 4); 921 } 922 923 924 /** 925 * Copy from an array into a rectangular region in this Allocation. The 926 * array is assumed to be tightly packed. 927 * 928 * @param xoff X offset of the region to update in this Allocation 929 * @param yoff Y offset of the region to update in this Allocation 930 * @param w Width of the region to update 931 * @param h Height of the region to update 932 * @param data to be placed into the Allocation 933 */ 934 public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] data) { 935 validateIsInt8(); 936 copy2DRangeFromUnchecked(xoff, yoff, w, h, data); 937 } 938 939 /** 940 * Copy from an array into a rectangular region in this Allocation. The 941 * array is assumed to be tightly packed. 942 * 943 * @param xoff X offset of the region to update in this Allocation 944 * @param yoff Y offset of the region to update in this Allocation 945 * @param w Width of the region to update 946 * @param h Height of the region to update 947 * @param data to be placed into the Allocation 948 */ 949 public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) { 950 validateIsInt16(); 951 copy2DRangeFromUnchecked(xoff, yoff, w, h, data); 952 } 953 954 /** 955 * Copy from an array into a rectangular region in this Allocation. The 956 * array is assumed to be tightly packed. 957 * 958 * @param xoff X offset of the region to update in this Allocation 959 * @param yoff Y offset of the region to update in this Allocation 960 * @param w Width of the region to update 961 * @param h Height of the region to update 962 * @param data to be placed into the Allocation 963 */ 964 public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] data) { 965 validateIsInt32(); 966 copy2DRangeFromUnchecked(xoff, yoff, w, h, data); 967 } 968 969 /** 970 * Copy from an array into a rectangular region in this Allocation. The 971 * array is assumed to be tightly packed. 972 * 973 * @param xoff X offset of the region to update in this Allocation 974 * @param yoff Y offset of the region to update in this Allocation 975 * @param w Width of the region to update 976 * @param h Height of the region to update 977 * @param data to be placed into the Allocation 978 */ 979 public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] data) { 980 validateIsFloat32(); 981 copy2DRangeFromUnchecked(xoff, yoff, w, h, data); 982 } 983 984 /** 985 * Copy a rectangular region from an Allocation into a rectangular region in 986 * this Allocation. 987 * 988 * @param xoff X offset of the region in this Allocation 989 * @param yoff Y offset of the region in this Allocation 990 * @param w Width of the region to update. 991 * @param h Height of the region to update. 992 * @param data source Allocation. 993 * @param dataXoff X offset in source Allocation 994 * @param dataYoff Y offset in source Allocation 995 */ 996 public void copy2DRangeFrom(int xoff, int yoff, int w, int h, 997 Allocation data, int dataXoff, int dataYoff) { 998 mRS.validate(); 999 validate2DRange(xoff, yoff, w, h); 1000 mRS.nAllocationData2D(getIDSafe(), xoff, yoff, 1001 mSelectedLOD, mSelectedFace.mID, 1002 w, h, data.getID(mRS), dataXoff, dataYoff, 1003 data.mSelectedLOD, data.mSelectedFace.mID); 1004 } 1005 1006 /** 1007 * Copy a {@link android.graphics.Bitmap} into an Allocation. The height 1008 * and width of the update will use the height and width of the {@link 1009 * android.graphics.Bitmap}. 1010 * 1011 * @param xoff X offset of the region to update in this Allocation 1012 * @param yoff Y offset of the region to update in this Allocation 1013 * @param data the Bitmap to be copied 1014 */ 1015 public void copy2DRangeFrom(int xoff, int yoff, Bitmap data) { 1016 mRS.validate(); 1017 if (data.getConfig() == null) { 1018 Bitmap newBitmap = Bitmap.createBitmap(data.getWidth(), data.getHeight(), Bitmap.Config.ARGB_8888); 1019 Canvas c = new Canvas(newBitmap); 1020 c.drawBitmap(data, 0, 0, null); 1021 copy2DRangeFrom(xoff, yoff, newBitmap); 1022 return; 1023 } 1024 validateBitmapFormat(data); 1025 validate2DRange(xoff, yoff, data.getWidth(), data.getHeight()); 1026 mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, data); 1027 } 1028 1029 private void validate3DRange(int xoff, int yoff, int zoff, int w, int h, int d) { 1030 if (mAdaptedAllocation != null) { 1031 1032 } else { 1033 1034 if (xoff < 0 || yoff < 0 || zoff < 0) { 1035 throw new RSIllegalArgumentException("Offset cannot be negative."); 1036 } 1037 if (h < 0 || w < 0 || d < 0) { 1038 throw new RSIllegalArgumentException("Height or width cannot be negative."); 1039 } 1040 if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY) || ((zoff + d) > mCurrentDimZ)) { 1041 throw new RSIllegalArgumentException("Updated region larger than allocation."); 1042 } 1043 } 1044 } 1045 1046 /** 1047 * @hide 1048 * 1049 */ 1050 void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d, byte[] data) { 1051 mRS.validate(); 1052 validate3DRange(xoff, yoff, zoff, w, h, d); 1053 mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, 1054 w, h, d, data, data.length); 1055 } 1056 1057 /** 1058 * @hide 1059 * 1060 */ 1061 void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d, short[] data) { 1062 mRS.validate(); 1063 validate3DRange(xoff, yoff, zoff, w, h, d); 1064 mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, 1065 w, h, d, data, data.length * 2); 1066 } 1067 1068 /** 1069 * @hide 1070 * 1071 */ 1072 void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d, int[] data) { 1073 mRS.validate(); 1074 validate3DRange(xoff, yoff, zoff, w, h, d); 1075 mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, 1076 w, h, d, data, data.length * 4); 1077 } 1078 1079 /** 1080 * @hide 1081 * 1082 */ 1083 void copy3DRangeFromUnchecked(int xoff, int yoff, int zoff, int w, int h, int d, float[] data) { 1084 mRS.validate(); 1085 validate3DRange(xoff, yoff, zoff, w, h, d); 1086 mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, 1087 w, h, d, data, data.length * 4); 1088 } 1089 1090 1091 /** 1092 * @hide 1093 * Copy a rectangular region from the array into the allocation. 1094 * The array is assumed to be tightly packed. 1095 * 1096 * @param xoff X offset of the region to update in this Allocation 1097 * @param yoff Y offset of the region to update in this Allocation 1098 * @param zoff Z offset of the region to update in this Allocation 1099 * @param w Width of the region to update 1100 * @param h Height of the region to update 1101 * @param d Depth of the region to update 1102 * @param data to be placed into the allocation 1103 */ 1104 public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, byte[] data) { 1105 validateIsInt8(); 1106 copy3DRangeFromUnchecked(xoff, yoff, zoff, w, h, d, data); 1107 } 1108 1109 /** 1110 * @hide 1111 * 1112 */ 1113 public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, short[] data) { 1114 validateIsInt16(); 1115 copy3DRangeFromUnchecked(xoff, yoff, zoff, w, h, d, data); 1116 } 1117 1118 /** 1119 * @hide 1120 * 1121 */ 1122 public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, int[] data) { 1123 validateIsInt32(); 1124 copy3DRangeFromUnchecked(xoff, yoff, zoff, w, h, d, data); 1125 } 1126 1127 /** 1128 * @hide 1129 * 1130 */ 1131 public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, float[] data) { 1132 validateIsFloat32(); 1133 copy3DRangeFromUnchecked(xoff, yoff, zoff, w, h, d, data); 1134 } 1135 1136 /** 1137 * @hide 1138 * Copy a rectangular region into the allocation from another 1139 * allocation. 1140 * 1141 * @param xoff X offset of the region to update in this Allocation 1142 * @param yoff Y offset of the region to update in this Allocation 1143 * @param zoff Z offset of the region to update in this Allocation 1144 * @param w Width of the region to update. 1145 * @param h Height of the region to update. 1146 * @param d Depth of the region to update. 1147 * @param data source allocation. 1148 * @param dataXoff X offset of the region in the source Allocation 1149 * @param dataYoff Y offset of the region in the source Allocation 1150 * @param dataZoff Z offset of the region in the source Allocation 1151 */ 1152 public void copy3DRangeFrom(int xoff, int yoff, int zoff, int w, int h, int d, 1153 Allocation data, int dataXoff, int dataYoff, int dataZoff) { 1154 mRS.validate(); 1155 validate3DRange(xoff, yoff, zoff, w, h, d); 1156 mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD, 1157 w, h, d, data.getID(mRS), dataXoff, dataYoff, dataZoff, 1158 data.mSelectedLOD); 1159 } 1160 1161 1162 /** 1163 * Copy from the Allocation into a {@link android.graphics.Bitmap}. The 1164 * bitmap must match the dimensions of the Allocation. 1165 * 1166 * @param b The bitmap to be set from the Allocation. 1167 */ 1168 public void copyTo(Bitmap b) { 1169 mRS.validate(); 1170 validateBitmapFormat(b); 1171 validateBitmapSize(b); 1172 mRS.nAllocationCopyToBitmap(getID(mRS), b); 1173 } 1174 1175 /** 1176 * Copy from the Allocation into a byte array. The array must be at least 1177 * as large as the Allocation. The allocation must be of an 8 bit integer 1178 * {@link android.renderscript.Element} type. 1179 * 1180 * @param d The array to be set from the Allocation. 1181 */ 1182 public void copyTo(byte[] d) { 1183 validateIsInt8(); 1184 mRS.validate(); 1185 mRS.nAllocationRead(getID(mRS), d); 1186 } 1187 1188 /** 1189 * Copy from the Allocation into a short array. The array must be at least 1190 * as large as the Allocation. The allocation must be of an 16 bit integer 1191 * {@link android.renderscript.Element} type. 1192 * 1193 * @param d The array to be set from the Allocation. 1194 */ 1195 public void copyTo(short[] d) { 1196 validateIsInt16(); 1197 mRS.validate(); 1198 mRS.nAllocationRead(getID(mRS), d); 1199 } 1200 1201 /** 1202 * Copy from the Allocation into a int array. The array must be at least as 1203 * large as the Allocation. The allocation must be of an 32 bit integer 1204 * {@link android.renderscript.Element} type. 1205 * 1206 * @param d The array to be set from the Allocation. 1207 */ 1208 public void copyTo(int[] d) { 1209 validateIsInt32(); 1210 mRS.validate(); 1211 mRS.nAllocationRead(getID(mRS), d); 1212 } 1213 1214 /** 1215 * Copy from the Allocation into a float array. The array must be at least 1216 * as large as the Allocation. The allocation must be of an 32 bit float 1217 * {@link android.renderscript.Element} type. 1218 * 1219 * @param d The array to be set from the Allocation. 1220 */ 1221 public void copyTo(float[] d) { 1222 validateIsFloat32(); 1223 mRS.validate(); 1224 mRS.nAllocationRead(getID(mRS), d); 1225 } 1226 1227 /** 1228 * Resize a 1D allocation. The contents of the allocation are preserved. 1229 * If new elements are allocated objects are created with null contents and 1230 * the new region is otherwise undefined. 1231 * 1232 * <p>If the new region is smaller the references of any objects outside the 1233 * new region will be released.</p> 1234 * 1235 * <p>A new type will be created with the new dimension.</p> 1236 * 1237 * @param dimX The new size of the allocation. 1238 * 1239 * @deprecated RenderScript objects should be immutable once created. The 1240 * replacement is to create a new allocation and copy the contents. 1241 */ 1242 public synchronized void resize(int dimX) { 1243 if ((mType.getY() > 0)|| (mType.getZ() > 0) || mType.hasFaces() || mType.hasMipmaps()) { 1244 throw new RSInvalidStateException("Resize only support for 1D allocations at this time."); 1245 } 1246 mRS.nAllocationResize1D(getID(mRS), dimX); 1247 mRS.finish(); // Necessary because resize is fifoed and update is async. 1248 1249 int typeID = mRS.nAllocationGetType(getID(mRS)); 1250 mType = new Type(typeID, mRS); 1251 mType.updateFromNative(); 1252 updateCacheInfo(mType); 1253 } 1254 1255 1256 // creation 1257 1258 static BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options(); 1259 static { 1260 mBitmapOptions.inScaled = false; 1261 } 1262 1263 /** 1264 * Creates a new Allocation with the given {@link 1265 * android.renderscript.Type}, mipmap flag, and usage flags. 1266 * 1267 * @param type RenderScript type describing data layout 1268 * @param mips specifies desired mipmap behaviour for the 1269 * allocation 1270 * @param usage bit field specifying how the Allocation is 1271 * utilized 1272 */ 1273 static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips, int usage) { 1274 rs.validate(); 1275 if (type.getID(rs) == 0) { 1276 throw new RSInvalidStateException("Bad Type"); 1277 } 1278 int id = rs.nAllocationCreateTyped(type.getID(rs), mips.mID, usage, 0); 1279 if (id == 0) { 1280 throw new RSRuntimeException("Allocation creation failed."); 1281 } 1282 return new Allocation(id, rs, type, usage); 1283 } 1284 1285 /** 1286 * Creates an Allocation with the size specified by the type and no mipmaps 1287 * generated by default 1288 * 1289 * @param rs Context to which the allocation will belong. 1290 * @param type renderscript type describing data layout 1291 * @param usage bit field specifying how the allocation is 1292 * utilized 1293 * 1294 * @return allocation 1295 */ 1296 static public Allocation createTyped(RenderScript rs, Type type, int usage) { 1297 return createTyped(rs, type, MipmapControl.MIPMAP_NONE, usage); 1298 } 1299 1300 /** 1301 * Creates an Allocation for use by scripts with a given {@link 1302 * android.renderscript.Type} and no mipmaps 1303 * 1304 * @param rs Context to which the Allocation will belong. 1305 * @param type RenderScript Type describing data layout 1306 * 1307 * @return allocation 1308 */ 1309 static public Allocation createTyped(RenderScript rs, Type type) { 1310 return createTyped(rs, type, MipmapControl.MIPMAP_NONE, USAGE_SCRIPT); 1311 } 1312 1313 /** 1314 * Creates an Allocation with a specified number of given elements 1315 * 1316 * @param rs Context to which the Allocation will belong. 1317 * @param e Element to use in the Allocation 1318 * @param count the number of Elements in the Allocation 1319 * @param usage bit field specifying how the Allocation is 1320 * utilized 1321 * 1322 * @return allocation 1323 */ 1324 static public Allocation createSized(RenderScript rs, Element e, 1325 int count, int usage) { 1326 rs.validate(); 1327 Type.Builder b = new Type.Builder(rs, e); 1328 b.setX(count); 1329 Type t = b.create(); 1330 1331 int id = rs.nAllocationCreateTyped(t.getID(rs), MipmapControl.MIPMAP_NONE.mID, usage, 0); 1332 if (id == 0) { 1333 throw new RSRuntimeException("Allocation creation failed."); 1334 } 1335 return new Allocation(id, rs, t, usage); 1336 } 1337 1338 /** 1339 * Creates an Allocation with a specified number of given elements 1340 * 1341 * @param rs Context to which the Allocation will belong. 1342 * @param e Element to use in the Allocation 1343 * @param count the number of Elements in the Allocation 1344 * 1345 * @return allocation 1346 */ 1347 static public Allocation createSized(RenderScript rs, Element e, int count) { 1348 return createSized(rs, e, count, USAGE_SCRIPT); 1349 } 1350 1351 static Element elementFromBitmap(RenderScript rs, Bitmap b) { 1352 final Bitmap.Config bc = b.getConfig(); 1353 if (bc == Bitmap.Config.ALPHA_8) { 1354 return Element.A_8(rs); 1355 } 1356 if (bc == Bitmap.Config.ARGB_4444) { 1357 return Element.RGBA_4444(rs); 1358 } 1359 if (bc == Bitmap.Config.ARGB_8888) { 1360 return Element.RGBA_8888(rs); 1361 } 1362 if (bc == Bitmap.Config.RGB_565) { 1363 return Element.RGB_565(rs); 1364 } 1365 throw new RSInvalidStateException("Bad bitmap type: " + bc); 1366 } 1367 1368 static Type typeFromBitmap(RenderScript rs, Bitmap b, 1369 MipmapControl mip) { 1370 Element e = elementFromBitmap(rs, b); 1371 Type.Builder tb = new Type.Builder(rs, e); 1372 tb.setX(b.getWidth()); 1373 tb.setY(b.getHeight()); 1374 tb.setMipmaps(mip == MipmapControl.MIPMAP_FULL); 1375 return tb.create(); 1376 } 1377 1378 /** 1379 * Creates an Allocation from a {@link android.graphics.Bitmap}. 1380 * 1381 * @param rs Context to which the allocation will belong. 1382 * @param b Bitmap source for the allocation data 1383 * @param mips specifies desired mipmap behaviour for the 1384 * allocation 1385 * @param usage bit field specifying how the allocation is 1386 * utilized 1387 * 1388 * @return Allocation containing bitmap data 1389 * 1390 */ 1391 static public Allocation createFromBitmap(RenderScript rs, Bitmap b, 1392 MipmapControl mips, 1393 int usage) { 1394 rs.validate(); 1395 1396 // WAR undocumented color formats 1397 if (b.getConfig() == null) { 1398 if ((usage & USAGE_SHARED) != 0) { 1399 throw new RSIllegalArgumentException("USAGE_SHARED cannot be used with a Bitmap that has a null config."); 1400 } 1401 Bitmap newBitmap = Bitmap.createBitmap(b.getWidth(), b.getHeight(), Bitmap.Config.ARGB_8888); 1402 Canvas c = new Canvas(newBitmap); 1403 c.drawBitmap(b, 0, 0, null); 1404 return createFromBitmap(rs, newBitmap, mips, usage); 1405 } 1406 1407 Type t = typeFromBitmap(rs, b, mips); 1408 1409 // enable optimized bitmap path only with no mipmap and script-only usage 1410 if (mips == MipmapControl.MIPMAP_NONE && 1411 t.getElement().isCompatible(Element.RGBA_8888(rs)) && 1412 usage == (USAGE_SHARED | USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE)) { 1413 int id = rs.nAllocationCreateBitmapBackedAllocation(t.getID(rs), mips.mID, b, usage); 1414 if (id == 0) { 1415 throw new RSRuntimeException("Load failed."); 1416 } 1417 1418 // keep a reference to the Bitmap around to prevent GC 1419 Allocation alloc = new Allocation(id, rs, t, usage); 1420 alloc.setBitmap(b); 1421 return alloc; 1422 } 1423 1424 1425 int id = rs.nAllocationCreateFromBitmap(t.getID(rs), mips.mID, b, usage); 1426 if (id == 0) { 1427 throw new RSRuntimeException("Load failed."); 1428 } 1429 return new Allocation(id, rs, t, usage); 1430 } 1431 1432 /** 1433 * Returns the handle to a raw buffer that is being managed by the screen 1434 * compositor. This operation is only valid for Allocations with {@link 1435 * #USAGE_IO_INPUT}. 1436 * 1437 * @return Surface object associated with allocation 1438 * 1439 */ 1440 public Surface getSurface() { 1441 if ((mUsage & USAGE_IO_INPUT) == 0) { 1442 throw new RSInvalidStateException("Allocation is not a surface texture."); 1443 } 1444 return mRS.nAllocationGetSurface(getID(mRS)); 1445 } 1446 1447 /** 1448 * @hide 1449 */ 1450 public void setSurfaceTexture(SurfaceTexture st) { 1451 setSurface(new Surface(st)); 1452 } 1453 1454 /** 1455 * Associate a {@link android.view.Surface} with this Allocation. This 1456 * operation is only valid for Allocations with {@link #USAGE_IO_OUTPUT}. 1457 * 1458 * @param sur Surface to associate with allocation 1459 */ 1460 public void setSurface(Surface sur) { 1461 mRS.validate(); 1462 if ((mUsage & USAGE_IO_OUTPUT) == 0) { 1463 throw new RSInvalidStateException("Allocation is not USAGE_IO_OUTPUT."); 1464 } 1465 1466 mRS.nAllocationSetSurface(getID(mRS), sur); 1467 } 1468 1469 /** 1470 * Creates an Allocation from a {@link android.graphics.Bitmap}. 1471 * 1472 * <p>With target API version 18 or greater, this Allocation will be created 1473 * with {@link #USAGE_SHARED}, {@link #USAGE_SCRIPT}, and {@link 1474 * #USAGE_GRAPHICS_TEXTURE}. With target API version 17 or lower, this 1475 * Allocation will be created with {@link #USAGE_GRAPHICS_TEXTURE}.</p> 1476 * 1477 * @param rs Context to which the allocation will belong. 1478 * @param b bitmap source for the allocation data 1479 * 1480 * @return Allocation containing bitmap data 1481 * 1482 */ 1483 static public Allocation createFromBitmap(RenderScript rs, Bitmap b) { 1484 if (rs.getApplicationContext().getApplicationInfo().targetSdkVersion >= 18) { 1485 return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE, 1486 USAGE_SHARED | USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE); 1487 } 1488 return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE, 1489 USAGE_GRAPHICS_TEXTURE); 1490 } 1491 1492 /** 1493 * Creates a cubemap Allocation from a {@link android.graphics.Bitmap} 1494 * containing the horizontal list of cube faces. Each face must be a square, 1495 * have the same size as all other faces, and have a width that is a power 1496 * of 2. 1497 * 1498 * @param rs Context to which the allocation will belong. 1499 * @param b Bitmap with cubemap faces layed out in the following 1500 * format: right, left, top, bottom, front, back 1501 * @param mips specifies desired mipmap behaviour for the cubemap 1502 * @param usage bit field specifying how the cubemap is utilized 1503 * 1504 * @return allocation containing cubemap data 1505 * 1506 */ 1507 static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b, 1508 MipmapControl mips, 1509 int usage) { 1510 rs.validate(); 1511 1512 int height = b.getHeight(); 1513 int width = b.getWidth(); 1514 1515 if (width % 6 != 0) { 1516 throw new RSIllegalArgumentException("Cubemap height must be multiple of 6"); 1517 } 1518 if (width / 6 != height) { 1519 throw new RSIllegalArgumentException("Only square cube map faces supported"); 1520 } 1521 boolean isPow2 = (height & (height - 1)) == 0; 1522 if (!isPow2) { 1523 throw new RSIllegalArgumentException("Only power of 2 cube faces supported"); 1524 } 1525 1526 Element e = elementFromBitmap(rs, b); 1527 Type.Builder tb = new Type.Builder(rs, e); 1528 tb.setX(height); 1529 tb.setY(height); 1530 tb.setFaces(true); 1531 tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL); 1532 Type t = tb.create(); 1533 1534 int id = rs.nAllocationCubeCreateFromBitmap(t.getID(rs), mips.mID, b, usage); 1535 if(id == 0) { 1536 throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e); 1537 } 1538 return new Allocation(id, rs, t, usage); 1539 } 1540 1541 /** 1542 * Creates a non-mipmapped cubemap Allocation for use as a graphics texture 1543 * from a {@link android.graphics.Bitmap} containing the horizontal list of 1544 * cube faces. Each face must be a square, have the same size as all other 1545 * faces, and have a width that is a power of 2. 1546 * 1547 * @param rs Context to which the allocation will belong. 1548 * @param b bitmap with cubemap faces layed out in the following 1549 * format: right, left, top, bottom, front, back 1550 * 1551 * @return allocation containing cubemap data 1552 * 1553 */ 1554 static public Allocation createCubemapFromBitmap(RenderScript rs, 1555 Bitmap b) { 1556 return createCubemapFromBitmap(rs, b, MipmapControl.MIPMAP_NONE, 1557 USAGE_GRAPHICS_TEXTURE); 1558 } 1559 1560 /** 1561 * Creates a cubemap Allocation from 6 {@link android.graphics.Bitmap} 1562 * objects containing the cube faces. Each face must be a square, have the 1563 * same size as all other faces, and have a width that is a power of 2. 1564 * 1565 * @param rs Context to which the allocation will belong. 1566 * @param xpos cubemap face in the positive x direction 1567 * @param xneg cubemap face in the negative x direction 1568 * @param ypos cubemap face in the positive y direction 1569 * @param yneg cubemap face in the negative y direction 1570 * @param zpos cubemap face in the positive z direction 1571 * @param zneg cubemap face in the negative z direction 1572 * @param mips specifies desired mipmap behaviour for the cubemap 1573 * @param usage bit field specifying how the cubemap is utilized 1574 * 1575 * @return allocation containing cubemap data 1576 * 1577 */ 1578 static public Allocation createCubemapFromCubeFaces(RenderScript rs, 1579 Bitmap xpos, 1580 Bitmap xneg, 1581 Bitmap ypos, 1582 Bitmap yneg, 1583 Bitmap zpos, 1584 Bitmap zneg, 1585 MipmapControl mips, 1586 int usage) { 1587 int height = xpos.getHeight(); 1588 if (xpos.getWidth() != height || 1589 xneg.getWidth() != height || xneg.getHeight() != height || 1590 ypos.getWidth() != height || ypos.getHeight() != height || 1591 yneg.getWidth() != height || yneg.getHeight() != height || 1592 zpos.getWidth() != height || zpos.getHeight() != height || 1593 zneg.getWidth() != height || zneg.getHeight() != height) { 1594 throw new RSIllegalArgumentException("Only square cube map faces supported"); 1595 } 1596 boolean isPow2 = (height & (height - 1)) == 0; 1597 if (!isPow2) { 1598 throw new RSIllegalArgumentException("Only power of 2 cube faces supported"); 1599 } 1600 1601 Element e = elementFromBitmap(rs, xpos); 1602 Type.Builder tb = new Type.Builder(rs, e); 1603 tb.setX(height); 1604 tb.setY(height); 1605 tb.setFaces(true); 1606 tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL); 1607 Type t = tb.create(); 1608 Allocation cubemap = Allocation.createTyped(rs, t, mips, usage); 1609 1610 AllocationAdapter adapter = AllocationAdapter.create2D(rs, cubemap); 1611 adapter.setFace(Type.CubemapFace.POSITIVE_X); 1612 adapter.copyFrom(xpos); 1613 adapter.setFace(Type.CubemapFace.NEGATIVE_X); 1614 adapter.copyFrom(xneg); 1615 adapter.setFace(Type.CubemapFace.POSITIVE_Y); 1616 adapter.copyFrom(ypos); 1617 adapter.setFace(Type.CubemapFace.NEGATIVE_Y); 1618 adapter.copyFrom(yneg); 1619 adapter.setFace(Type.CubemapFace.POSITIVE_Z); 1620 adapter.copyFrom(zpos); 1621 adapter.setFace(Type.CubemapFace.NEGATIVE_Z); 1622 adapter.copyFrom(zneg); 1623 1624 return cubemap; 1625 } 1626 1627 /** 1628 * Creates a non-mipmapped cubemap Allocation for use as a sampler input 1629 * from 6 {@link android.graphics.Bitmap} objects containing the cube 1630 * faces. Each face must be a square, have the same size as all other faces, 1631 * and have a width that is a power of 2. 1632 * 1633 * @param rs Context to which the allocation will belong. 1634 * @param xpos cubemap face in the positive x direction 1635 * @param xneg cubemap face in the negative x direction 1636 * @param ypos cubemap face in the positive y direction 1637 * @param yneg cubemap face in the negative y direction 1638 * @param zpos cubemap face in the positive z direction 1639 * @param zneg cubemap face in the negative z direction 1640 * 1641 * @return allocation containing cubemap data 1642 * 1643 */ 1644 static public Allocation createCubemapFromCubeFaces(RenderScript rs, 1645 Bitmap xpos, 1646 Bitmap xneg, 1647 Bitmap ypos, 1648 Bitmap yneg, 1649 Bitmap zpos, 1650 Bitmap zneg) { 1651 return createCubemapFromCubeFaces(rs, xpos, xneg, ypos, yneg, 1652 zpos, zneg, MipmapControl.MIPMAP_NONE, 1653 USAGE_GRAPHICS_TEXTURE); 1654 } 1655 1656 /** 1657 * Creates an Allocation from the Bitmap referenced 1658 * by resource ID. 1659 * 1660 * @param rs Context to which the allocation will belong. 1661 * @param res application resources 1662 * @param id resource id to load the data from 1663 * @param mips specifies desired mipmap behaviour for the 1664 * allocation 1665 * @param usage bit field specifying how the allocation is 1666 * utilized 1667 * 1668 * @return Allocation containing resource data 1669 * 1670 */ 1671 static public Allocation createFromBitmapResource(RenderScript rs, 1672 Resources res, 1673 int id, 1674 MipmapControl mips, 1675 int usage) { 1676 1677 rs.validate(); 1678 if ((usage & (USAGE_SHARED | USAGE_IO_INPUT | USAGE_IO_OUTPUT)) != 0) { 1679 throw new RSIllegalArgumentException("Unsupported usage specified."); 1680 } 1681 Bitmap b = BitmapFactory.decodeResource(res, id); 1682 Allocation alloc = createFromBitmap(rs, b, mips, usage); 1683 b.recycle(); 1684 return alloc; 1685 } 1686 1687 /** 1688 * Creates a non-mipmapped Allocation to use as a graphics texture from the 1689 * {@link android.graphics.Bitmap} referenced by resource ID. 1690 * 1691 * <p>With target API version 18 or greater, this allocation will be created 1692 * with {@link #USAGE_SCRIPT} and {@link #USAGE_GRAPHICS_TEXTURE}. With 1693 * target API version 17 or lower, this allocation will be created with 1694 * {@link #USAGE_GRAPHICS_TEXTURE}.</p> 1695 * 1696 * @param rs Context to which the allocation will belong. 1697 * @param res application resources 1698 * @param id resource id to load the data from 1699 * 1700 * @return Allocation containing resource data 1701 * 1702 */ 1703 static public Allocation createFromBitmapResource(RenderScript rs, 1704 Resources res, 1705 int id) { 1706 if (rs.getApplicationContext().getApplicationInfo().targetSdkVersion >= 18) { 1707 return createFromBitmapResource(rs, res, id, 1708 MipmapControl.MIPMAP_NONE, 1709 USAGE_SCRIPT | USAGE_GRAPHICS_TEXTURE); 1710 } 1711 return createFromBitmapResource(rs, res, id, 1712 MipmapControl.MIPMAP_NONE, 1713 USAGE_GRAPHICS_TEXTURE); 1714 } 1715 1716 /** 1717 * Creates an Allocation containing string data encoded in UTF-8 format. 1718 * 1719 * @param rs Context to which the allocation will belong. 1720 * @param str string to create the allocation from 1721 * @param usage bit field specifying how the allocaiton is 1722 * utilized 1723 * 1724 */ 1725 static public Allocation createFromString(RenderScript rs, 1726 String str, 1727 int usage) { 1728 rs.validate(); 1729 byte[] allocArray = null; 1730 try { 1731 allocArray = str.getBytes("UTF-8"); 1732 Allocation alloc = Allocation.createSized(rs, Element.U8(rs), allocArray.length, usage); 1733 alloc.copyFrom(allocArray); 1734 return alloc; 1735 } 1736 catch (Exception e) { 1737 throw new RSRuntimeException("Could not convert string to utf-8."); 1738 } 1739 } 1740 1741 /** 1742 * @hide 1743 * 1744 * Interface to handle notification when new buffers are available via 1745 * {@link #USAGE_IO_INPUT}. An application will receive one notification 1746 * when a buffer is available. Additional buffers will not trigger new 1747 * notifications until a buffer is processed. 1748 */ 1749 public interface IoInputNotifier { 1750 public void onBufferAvailable(Allocation a); 1751 } 1752 1753 /** 1754 * @hide 1755 * 1756 * Set a notification handler for {@link #USAGE_IO_INPUT}. 1757 * 1758 * @param callback instance of the IoInputNotifier class to be called 1759 * when buffer arrive. 1760 */ 1761 public void setIoInputNotificationHandler(IoInputNotifier callback) { 1762 synchronized(mAllocationMap) { 1763 mAllocationMap.put(new Integer(getID(mRS)), this); 1764 mBufferNotifier = callback; 1765 } 1766 } 1767 1768 static void sendBufferNotification(int id) { 1769 synchronized(mAllocationMap) { 1770 Allocation a = mAllocationMap.get(new Integer(id)); 1771 1772 if ((a != null) && (a.mBufferNotifier != null)) { 1773 a.mBufferNotifier.onBufferAvailable(a); 1774 } 1775 } 1776 } 1777 1778 } 1779 1780