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