Allocation.java revision 532efd3ce261f9901bfa51d37377069fe6e8ccdf
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.renderscript; 18 19import java.io.IOException; 20import java.io.InputStream; 21import android.content.res.Resources; 22import android.content.res.AssetManager; 23import android.graphics.Bitmap; 24import android.graphics.BitmapFactory; 25import android.graphics.SurfaceTexture; 26import android.util.Log; 27import android.util.TypedValue; 28 29/** 30 * <p> 31 * Memory allocation class for renderscript. An allocation combines a 32 * {@link android.renderscript.Type} with the memory to provide storage for user data and objects. 33 * This implies that all memory in Renderscript is typed. 34 * </p> 35 * 36 * <p>Allocations are the primary way data moves into and out of scripts. Memory is user 37 * synchronized and it's possible for allocations to exist in multiple memory spaces 38 * concurrently. Currently those spaces are:</p> 39 * <ul> 40 * <li>Script: accessable by RS scripts.</li> 41 * <li>Graphics Texture: accessable as a graphics texture.</li> 42 * <li>Graphics Vertex: accessable as graphical vertex data.</li> 43 * <li>Graphics Constants: Accessable as constants in user shaders</li> 44 * </ul> 45 * </p> 46 * <p> 47 * For example, when creating a allocation for a texture, the user can 48 * specify its memory spaces as both script and textures. This means that it can both 49 * be used as script binding and as a GPU texture for rendering. To maintain 50 * synchronization if a script modifies an allocation used by other targets it must 51 * call a synchronizing function to push the updates to the memory, otherwise the results 52 * are undefined. 53 * </p> 54 * <p>By default, Android system side updates are always applied to the script accessable 55 * memory. If this is not present, they are then applied to the various HW 56 * memory types. A {@link android.renderscript.Allocation#syncAll syncAll()} 57 * call is necessary after the script data is updated to 58 * keep the other memory spaces in sync.</p> 59 * 60 * <p>Allocation data is uploaded in one of two primary ways. For simple 61 * arrays there are copyFrom() functions that take an array from the control code and 62 * copy it to the slave memory store. Both type checked and unchecked copies are provided. 63 * The unchecked variants exist to allow apps to copy over arrays of structures from a 64 * control language that does not support structures.</p> 65 * 66 * <div class="special reference"> 67 * <h3>Developer Guides</h3> 68 * <p>For more information about creating an application that uses Renderscript, read the 69 * <a href="{@docRoot}guide/topics/graphics/renderscript.html">Renderscript</a> developer guide.</p> 70 * </div> 71 **/ 72public class Allocation extends BaseObj { 73 Type mType; 74 Bitmap mBitmap; 75 int mUsage; 76 Allocation mAdaptedAllocation; 77 78 boolean mConstrainedLOD; 79 boolean mConstrainedFace; 80 boolean mConstrainedY; 81 boolean mConstrainedZ; 82 boolean mReadAllowed = true; 83 boolean mWriteAllowed = true; 84 int mSelectedY; 85 int mSelectedZ; 86 int mSelectedLOD; 87 Type.CubemapFace mSelectedFace = Type.CubemapFace.POSITIVE_X; 88 89 int mCurrentDimX; 90 int mCurrentDimY; 91 int mCurrentDimZ; 92 int mCurrentCount; 93 94 95 /** 96 * The usage of the allocation. These signal to renderscript 97 * where to place the allocation in memory. 98 * 99 * SCRIPT The allocation will be bound to and accessed by 100 * scripts. 101 */ 102 public static final int USAGE_SCRIPT = 0x0001; 103 104 /** 105 * GRAPHICS_TEXTURE The allcation will be used as a texture 106 * source by one or more graphics programs. 107 * 108 */ 109 public static final int USAGE_GRAPHICS_TEXTURE = 0x0002; 110 111 /** 112 * GRAPHICS_VERTEX The allocation will be used as a graphics 113 * mesh. 114 * 115 */ 116 public static final int USAGE_GRAPHICS_VERTEX = 0x0004; 117 118 119 /** 120 * GRAPHICS_CONSTANTS The allocation will be used as the source 121 * of shader constants by one or more programs. 122 * 123 */ 124 public static final int USAGE_GRAPHICS_CONSTANTS = 0x0008; 125 126 /** 127 * USAGE_GRAPHICS_RENDER_TARGET The allcation will be used as a 128 * target for offscreen rendering 129 * 130 */ 131 public static final int USAGE_GRAPHICS_RENDER_TARGET = 0x0010; 132 133 /** 134 * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT The allcation will be 135 * used with a SurfaceTexture object. This usage will cause the 136 * allocation to be created read only. 137 * 138 * @hide 139 */ 140 public static final int USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE = 0x0020; 141 142 /** 143 * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT The allcation will be 144 * used with a SurfaceTexture object. This usage will cause the 145 * allocation to be created read only. 146 * 147 * @hide 148 */ 149 150 public static final int USAGE_IO_INPUT = 0x0040; 151 /** 152 * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT The allcation will be 153 * used with a SurfaceTexture object. This usage will cause the 154 * allocation to be created read only. 155 * 156 * @hide 157 */ 158 public static final int USAGE_IO_OUTPUT = 0x0080; 159 160 /** 161 * Controls mipmap behavior when using the bitmap creation and 162 * update functions. 163 */ 164 public enum MipmapControl { 165 /** 166 * No mipmaps will be generated and the type generated from the 167 * incoming bitmap will not contain additional LODs. 168 */ 169 MIPMAP_NONE(0), 170 171 /** 172 * A Full mipmap chain will be created in script memory. The 173 * type of the allocation will contain a full mipmap chain. On 174 * upload to graphics the full chain will be transfered. 175 */ 176 MIPMAP_FULL(1), 177 178 /** 179 * The type of the allocation will be the same as MIPMAP_NONE. 180 * It will not contain mipmaps. On upload to graphics the 181 * graphics copy of the allocation data will contain a full 182 * mipmap chain generated from the top level in script memory. 183 */ 184 MIPMAP_ON_SYNC_TO_TEXTURE(2); 185 186 int mID; 187 MipmapControl(int id) { 188 mID = id; 189 } 190 } 191 192 193 private int getIDSafe() { 194 if (mAdaptedAllocation != null) { 195 return mAdaptedAllocation.getID(); 196 } 197 return getID(); 198 } 199 200 private void updateCacheInfo(Type t) { 201 mCurrentDimX = t.getX(); 202 mCurrentDimY = t.getY(); 203 mCurrentDimZ = t.getZ(); 204 mCurrentCount = mCurrentDimX; 205 if (mCurrentDimY > 1) { 206 mCurrentCount *= mCurrentDimY; 207 } 208 if (mCurrentDimZ > 1) { 209 mCurrentCount *= mCurrentDimZ; 210 } 211 } 212 213 Allocation(int id, RenderScript rs, Type t, int usage) { 214 super(id, rs); 215 if ((usage & ~(USAGE_SCRIPT | 216 USAGE_GRAPHICS_TEXTURE | 217 USAGE_GRAPHICS_VERTEX | 218 USAGE_GRAPHICS_CONSTANTS | 219 USAGE_GRAPHICS_RENDER_TARGET | 220 USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE | 221 USAGE_IO_INPUT | 222 USAGE_IO_OUTPUT)) != 0) { 223 throw new RSIllegalArgumentException("Unknown usage specified."); 224 } 225 226 if ((usage & (USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE | USAGE_IO_INPUT)) != 0) { 227 mWriteAllowed = false; 228 229 if ((usage & ~(USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE | 230 USAGE_IO_INPUT | 231 USAGE_GRAPHICS_TEXTURE | 232 USAGE_SCRIPT)) != 0) { 233 throw new RSIllegalArgumentException("Invalid usage combination."); 234 } 235 } 236 237 mType = t; 238 mUsage = usage; 239 240 if (t != null) { 241 updateCacheInfo(t); 242 } 243 } 244 245 private void validateIsInt32() { 246 if ((mType.mElement.mType == Element.DataType.SIGNED_32) || 247 (mType.mElement.mType == Element.DataType.UNSIGNED_32)) { 248 return; 249 } 250 throw new RSIllegalArgumentException( 251 "32 bit integer source does not match allocation type " + mType.mElement.mType); 252 } 253 254 private void validateIsInt16() { 255 if ((mType.mElement.mType == Element.DataType.SIGNED_16) || 256 (mType.mElement.mType == Element.DataType.UNSIGNED_16)) { 257 return; 258 } 259 throw new RSIllegalArgumentException( 260 "16 bit integer source does not match allocation type " + mType.mElement.mType); 261 } 262 263 private void validateIsInt8() { 264 if ((mType.mElement.mType == Element.DataType.SIGNED_8) || 265 (mType.mElement.mType == Element.DataType.UNSIGNED_8)) { 266 return; 267 } 268 throw new RSIllegalArgumentException( 269 "8 bit integer source does not match allocation type " + mType.mElement.mType); 270 } 271 272 private void validateIsFloat32() { 273 if (mType.mElement.mType == Element.DataType.FLOAT_32) { 274 return; 275 } 276 throw new RSIllegalArgumentException( 277 "32 bit float source does not match allocation type " + mType.mElement.mType); 278 } 279 280 private void validateIsObject() { 281 if ((mType.mElement.mType == Element.DataType.RS_ELEMENT) || 282 (mType.mElement.mType == Element.DataType.RS_TYPE) || 283 (mType.mElement.mType == Element.DataType.RS_ALLOCATION) || 284 (mType.mElement.mType == Element.DataType.RS_SAMPLER) || 285 (mType.mElement.mType == Element.DataType.RS_SCRIPT) || 286 (mType.mElement.mType == Element.DataType.RS_MESH) || 287 (mType.mElement.mType == Element.DataType.RS_PROGRAM_FRAGMENT) || 288 (mType.mElement.mType == Element.DataType.RS_PROGRAM_VERTEX) || 289 (mType.mElement.mType == Element.DataType.RS_PROGRAM_RASTER) || 290 (mType.mElement.mType == Element.DataType.RS_PROGRAM_STORE)) { 291 return; 292 } 293 throw new RSIllegalArgumentException( 294 "Object source does not match allocation type " + mType.mElement.mType); 295 } 296 297 @Override 298 void updateFromNative() { 299 super.updateFromNative(); 300 int typeID = mRS.nAllocationGetType(getID()); 301 if(typeID != 0) { 302 mType = new Type(typeID, mRS); 303 mType.updateFromNative(); 304 updateCacheInfo(mType); 305 } 306 } 307 308 public Type getType() { 309 return mType; 310 } 311 312 public void syncAll(int srcLocation) { 313 switch (srcLocation) { 314 case USAGE_SCRIPT: 315 case USAGE_GRAPHICS_CONSTANTS: 316 case USAGE_GRAPHICS_TEXTURE: 317 case USAGE_GRAPHICS_VERTEX: 318 break; 319 default: 320 throw new RSIllegalArgumentException("Source must be exactly one usage type."); 321 } 322 mRS.validate(); 323 mRS.nAllocationSyncAll(getIDSafe(), srcLocation); 324 } 325 326 public void copyFrom(BaseObj[] d) { 327 mRS.validate(); 328 validateIsObject(); 329 if (d.length != mCurrentCount) { 330 throw new RSIllegalArgumentException("Array size mismatch, allocation sizeX = " + 331 mCurrentCount + ", array length = " + d.length); 332 } 333 int i[] = new int[d.length]; 334 for (int ct=0; ct < d.length; ct++) { 335 i[ct] = d[ct].getID(); 336 } 337 copy1DRangeFromUnchecked(0, mCurrentCount, i); 338 } 339 340 private void validateBitmapFormat(Bitmap b) { 341 Bitmap.Config bc = b.getConfig(); 342 switch (bc) { 343 case ALPHA_8: 344 if (mType.getElement().mKind != Element.DataKind.PIXEL_A) { 345 throw new RSIllegalArgumentException("Allocation kind is " + 346 mType.getElement().mKind + ", type " + 347 mType.getElement().mType + 348 " of " + mType.getElement().getSizeBytes() + 349 " bytes, passed bitmap was " + bc); 350 } 351 break; 352 case ARGB_8888: 353 if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) || 354 (mType.getElement().getSizeBytes() != 4)) { 355 throw new RSIllegalArgumentException("Allocation kind is " + 356 mType.getElement().mKind + ", type " + 357 mType.getElement().mType + 358 " of " + mType.getElement().getSizeBytes() + 359 " bytes, passed bitmap was " + bc); 360 } 361 break; 362 case RGB_565: 363 if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGB) || 364 (mType.getElement().getSizeBytes() != 2)) { 365 throw new RSIllegalArgumentException("Allocation kind is " + 366 mType.getElement().mKind + ", type " + 367 mType.getElement().mType + 368 " of " + mType.getElement().getSizeBytes() + 369 " bytes, passed bitmap was " + bc); 370 } 371 break; 372 case ARGB_4444: 373 if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) || 374 (mType.getElement().getSizeBytes() != 2)) { 375 throw new RSIllegalArgumentException("Allocation kind is " + 376 mType.getElement().mKind + ", type " + 377 mType.getElement().mType + 378 " of " + mType.getElement().getSizeBytes() + 379 " bytes, passed bitmap was " + bc); 380 } 381 break; 382 383 } 384 } 385 386 private void validateBitmapSize(Bitmap b) { 387 if((mCurrentDimX != b.getWidth()) || (mCurrentDimY != b.getHeight())) { 388 throw new RSIllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch"); 389 } 390 } 391 392 /** 393 * Copy an allocation from an array. This variant is not type 394 * checked which allows an application to fill in structured 395 * data from an array. 396 * 397 * @param d the source data array 398 */ 399 public void copyFromUnchecked(int[] d) { 400 mRS.validate(); 401 copy1DRangeFromUnchecked(0, mCurrentCount, d); 402 } 403 /** 404 * Copy an allocation from an array. This variant is not type 405 * checked which allows an application to fill in structured 406 * data from an array. 407 * 408 * @param d the source data array 409 */ 410 public void copyFromUnchecked(short[] d) { 411 mRS.validate(); 412 copy1DRangeFromUnchecked(0, mCurrentCount, d); 413 } 414 /** 415 * Copy an allocation from an array. This variant is not type 416 * checked which allows an application to fill in structured 417 * data from an array. 418 * 419 * @param d the source data array 420 */ 421 public void copyFromUnchecked(byte[] d) { 422 mRS.validate(); 423 copy1DRangeFromUnchecked(0, mCurrentCount, d); 424 } 425 /** 426 * Copy an allocation from an array. This variant is not type 427 * checked which allows an application to fill in structured 428 * data from an array. 429 * 430 * @param d the source data array 431 */ 432 public void copyFromUnchecked(float[] d) { 433 mRS.validate(); 434 copy1DRangeFromUnchecked(0, mCurrentCount, d); 435 } 436 437 /** 438 * Copy an allocation from an array. This variant is type 439 * checked and will generate exceptions if the Allocation type 440 * is not a 32 bit integer type. 441 * 442 * @param d the source data array 443 */ 444 public void copyFrom(int[] d) { 445 mRS.validate(); 446 copy1DRangeFrom(0, mCurrentCount, d); 447 } 448 449 /** 450 * Copy an allocation from an array. This variant is type 451 * checked and will generate exceptions if the Allocation type 452 * is not a 16 bit integer type. 453 * 454 * @param d the source data array 455 */ 456 public void copyFrom(short[] d) { 457 mRS.validate(); 458 copy1DRangeFrom(0, mCurrentCount, d); 459 } 460 461 /** 462 * Copy an allocation from an array. This variant is type 463 * checked and will generate exceptions if the Allocation type 464 * is not a 8 bit integer type. 465 * 466 * @param d the source data array 467 */ 468 public void copyFrom(byte[] d) { 469 mRS.validate(); 470 copy1DRangeFrom(0, mCurrentCount, d); 471 } 472 473 /** 474 * Copy an allocation from an array. This variant is type 475 * checked and will generate exceptions if the Allocation type 476 * is not a 32 bit float type. 477 * 478 * @param d the source data array 479 */ 480 public void copyFrom(float[] d) { 481 mRS.validate(); 482 copy1DRangeFrom(0, mCurrentCount, d); 483 } 484 485 /** 486 * Copy an allocation from a bitmap. The height, width, and 487 * format of the bitmap must match the existing allocation. 488 * 489 * @param b the source bitmap 490 */ 491 public void copyFrom(Bitmap b) { 492 mRS.validate(); 493 validateBitmapSize(b); 494 validateBitmapFormat(b); 495 mRS.nAllocationCopyFromBitmap(getID(), b); 496 } 497 498 /** 499 * This is only intended to be used by auto-generate code reflected from the 500 * renderscript script files. 501 * 502 * @param xoff 503 * @param fp 504 */ 505 public void setFromFieldPacker(int xoff, FieldPacker fp) { 506 int eSize = mType.mElement.getSizeBytes(); 507 final byte[] data = fp.getData(); 508 509 int count = data.length / eSize; 510 if ((eSize * count) != data.length) { 511 throw new RSIllegalArgumentException("Field packer length " + data.length + 512 " not divisible by element size " + eSize + "."); 513 } 514 copy1DRangeFromUnchecked(xoff, count, data); 515 } 516 517 /** 518 * This is only intended to be used by auto-generate code reflected from the 519 * renderscript script files. 520 * 521 * @param xoff 522 * @param component_number 523 * @param fp 524 */ 525 public void setFromFieldPacker(int xoff, int component_number, FieldPacker fp) { 526 if (component_number >= mType.mElement.mElements.length) { 527 throw new RSIllegalArgumentException("Component_number " + component_number + " out of range."); 528 } 529 if(xoff < 0) { 530 throw new RSIllegalArgumentException("Offset must be >= 0."); 531 } 532 533 final byte[] data = fp.getData(); 534 int eSize = mType.mElement.mElements[component_number].getSizeBytes(); 535 eSize *= mType.mElement.mArraySizes[component_number]; 536 537 if (data.length != eSize) { 538 throw new RSIllegalArgumentException("Field packer sizelength " + data.length + 539 " does not match component size " + eSize + "."); 540 } 541 542 mRS.nAllocationElementData1D(getIDSafe(), xoff, mSelectedLOD, 543 component_number, data, data.length); 544 } 545 546 private void data1DChecks(int off, int count, int len, int dataSize) { 547 mRS.validate(); 548 if(off < 0) { 549 throw new RSIllegalArgumentException("Offset must be >= 0."); 550 } 551 if(count < 1) { 552 throw new RSIllegalArgumentException("Count must be >= 1."); 553 } 554 if((off + count) > mCurrentCount) { 555 throw new RSIllegalArgumentException("Overflow, Available count " + mCurrentCount + 556 ", got " + count + " at offset " + off + "."); 557 } 558 if(len < dataSize) { 559 throw new RSIllegalArgumentException("Array too small for allocation type."); 560 } 561 } 562 563 /** 564 * Generate a mipmap chain. Requires the type of the allocation 565 * include mipmaps. 566 * 567 * This function will generate a complete set of mipmaps from 568 * the top level lod and place them into the script memoryspace. 569 * 570 * If the allocation is also using other memory spaces a 571 * followup sync will be required. 572 */ 573 public void generateMipmaps() { 574 mRS.nAllocationGenerateMipmaps(getID()); 575 } 576 577 /** 578 * Copy part of an allocation from an array. This variant is 579 * not type checked which allows an application to fill in 580 * structured data from an array. 581 * 582 * @param off The offset of the first element to be copied. 583 * @param count The number of elements to be copied. 584 * @param d the source data array 585 */ 586 public void copy1DRangeFromUnchecked(int off, int count, int[] d) { 587 int dataSize = mType.mElement.getSizeBytes() * count; 588 data1DChecks(off, count, d.length * 4, dataSize); 589 mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize); 590 } 591 /** 592 * Copy part of an allocation from an array. This variant is 593 * not type checked which allows an application to fill in 594 * structured data from an array. 595 * 596 * @param off The offset of the first element to be copied. 597 * @param count The number of elements to be copied. 598 * @param d the source data array 599 */ 600 public void copy1DRangeFromUnchecked(int off, int count, short[] d) { 601 int dataSize = mType.mElement.getSizeBytes() * count; 602 data1DChecks(off, count, d.length * 2, dataSize); 603 mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize); 604 } 605 /** 606 * Copy part of an allocation from an array. This variant is 607 * not type checked which allows an application to fill in 608 * structured data from an array. 609 * 610 * @param off The offset of the first element to be copied. 611 * @param count The number of elements to be copied. 612 * @param d the source data array 613 */ 614 public void copy1DRangeFromUnchecked(int off, int count, byte[] d) { 615 int dataSize = mType.mElement.getSizeBytes() * count; 616 data1DChecks(off, count, d.length, dataSize); 617 mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize); 618 } 619 /** 620 * Copy part of an allocation from an array. This variant is 621 * not type checked which allows an application to fill in 622 * structured data from an array. 623 * 624 * @param off The offset of the first element to be copied. 625 * @param count The number of elements to be copied. 626 * @param d the source data array 627 */ 628 public void copy1DRangeFromUnchecked(int off, int count, float[] d) { 629 int dataSize = mType.mElement.getSizeBytes() * count; 630 data1DChecks(off, count, d.length * 4, dataSize); 631 mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize); 632 } 633 634 /** 635 * Copy part of an allocation from an array. This variant is 636 * type checked and will generate exceptions if the Allocation 637 * type is not a 32 bit integer type. 638 * 639 * @param off The offset of the first element to be copied. 640 * @param count The number of elements to be copied. 641 * @param d the source data array 642 */ 643 public void copy1DRangeFrom(int off, int count, int[] d) { 644 validateIsInt32(); 645 copy1DRangeFromUnchecked(off, count, d); 646 } 647 648 /** 649 * Copy part of an allocation from an array. This variant is 650 * type checked and will generate exceptions if the Allocation 651 * type is not a 16 bit integer type. 652 * 653 * @param off The offset of the first element to be copied. 654 * @param count The number of elements to be copied. 655 * @param d the source data array 656 */ 657 public void copy1DRangeFrom(int off, int count, short[] d) { 658 validateIsInt16(); 659 copy1DRangeFromUnchecked(off, count, d); 660 } 661 662 /** 663 * Copy part of an allocation from an array. This variant is 664 * type checked and will generate exceptions if the Allocation 665 * type is not a 8 bit integer type. 666 * 667 * @param off The offset of the first element to be copied. 668 * @param count The number of elements to be copied. 669 * @param d the source data array 670 */ 671 public void copy1DRangeFrom(int off, int count, byte[] d) { 672 validateIsInt8(); 673 copy1DRangeFromUnchecked(off, count, d); 674 } 675 676 /** 677 * Copy part of an allocation from an array. This variant is 678 * type checked and will generate exceptions if the Allocation 679 * type is not a 32 bit float type. 680 * 681 * @param off The offset of the first element to be copied. 682 * @param count The number of elements to be copied. 683 * @param d the source data array. 684 */ 685 public void copy1DRangeFrom(int off, int count, float[] d) { 686 validateIsFloat32(); 687 copy1DRangeFromUnchecked(off, count, d); 688 } 689 690 /** 691 * Copy part of an allocation from another allocation. 692 * 693 * @param off The offset of the first element to be copied. 694 * @param count The number of elements to be copied. 695 * @param data the source data allocation. 696 * @param dataOff off The offset of the first element in data to 697 * be copied. 698 */ 699 public void copy1DRangeFrom(int off, int count, Allocation data, int dataOff) { 700 mRS.nAllocationData2D(getIDSafe(), off, 0, 701 mSelectedLOD, mSelectedFace.mID, 702 count, 1, data.getID(), dataOff, 0, 703 data.mSelectedLOD, data.mSelectedFace.mID); 704 } 705 706 private void validate2DRange(int xoff, int yoff, int w, int h) { 707 if (mAdaptedAllocation != null) { 708 709 } else { 710 711 if (xoff < 0 || yoff < 0) { 712 throw new RSIllegalArgumentException("Offset cannot be negative."); 713 } 714 if (h < 0 || w < 0) { 715 throw new RSIllegalArgumentException("Height or width cannot be negative."); 716 } 717 if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY)) { 718 throw new RSIllegalArgumentException("Updated region larger than allocation."); 719 } 720 } 721 } 722 723 /** 724 * Copy a rectangular region from the array into the allocation. 725 * The incoming array is assumed to be tightly packed. 726 * 727 * @param xoff X offset of the region to update 728 * @param yoff Y offset of the region to update 729 * @param w Width of the incoming region to update 730 * @param h Height of the incoming region to update 731 * @param data to be placed into the allocation 732 */ 733 public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] data) { 734 mRS.validate(); 735 validate2DRange(xoff, yoff, w, h); 736 mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, 737 w, h, data, data.length); 738 } 739 740 public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) { 741 mRS.validate(); 742 validate2DRange(xoff, yoff, w, h); 743 mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, 744 w, h, data, data.length * 2); 745 } 746 747 public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] data) { 748 mRS.validate(); 749 validate2DRange(xoff, yoff, w, h); 750 mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, 751 w, h, data, data.length * 4); 752 } 753 754 public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] data) { 755 mRS.validate(); 756 validate2DRange(xoff, yoff, w, h); 757 mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, 758 w, h, data, data.length * 4); 759 } 760 761 /** 762 * Copy a rectangular region into the allocation from another 763 * allocation. 764 * 765 * @param xoff X offset of the region to update. 766 * @param yoff Y offset of the region to update. 767 * @param w Width of the incoming region to update. 768 * @param h Height of the incoming region to update. 769 * @param data source allocation. 770 * @param dataXoff X offset in data of the region to update. 771 * @param dataYoff Y offset in data of the region to update. 772 */ 773 public void copy2DRangeFrom(int xoff, int yoff, int w, int h, 774 Allocation data, int dataXoff, int dataYoff) { 775 mRS.validate(); 776 validate2DRange(xoff, yoff, w, h); 777 mRS.nAllocationData2D(getIDSafe(), xoff, yoff, 778 mSelectedLOD, mSelectedFace.mID, 779 w, h, data.getID(), dataXoff, dataYoff, 780 data.mSelectedLOD, data.mSelectedFace.mID); 781 } 782 783 /** 784 * Copy a bitmap into an allocation. The height and width of 785 * the update will use the height and width of the incoming 786 * bitmap. 787 * 788 * @param xoff X offset of the region to update 789 * @param yoff Y offset of the region to update 790 * @param data the bitmap to be copied 791 */ 792 public void copy2DRangeFrom(int xoff, int yoff, Bitmap data) { 793 mRS.validate(); 794 validateBitmapFormat(data); 795 validate2DRange(xoff, yoff, data.getWidth(), data.getHeight()); 796 mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, data); 797 } 798 799 800 /** 801 * Copy from the Allocation into a Bitmap. The bitmap must 802 * match the dimensions of the Allocation. 803 * 804 * @param b The bitmap to be set from the Allocation. 805 */ 806 public void copyTo(Bitmap b) { 807 mRS.validate(); 808 validateBitmapFormat(b); 809 validateBitmapSize(b); 810 mRS.nAllocationCopyToBitmap(getID(), b); 811 } 812 813 /** 814 * Copy from the Allocation into a byte array. The array must 815 * be at least as large as the Allocation. The allocation must 816 * be of an 8 bit elemental type. 817 * 818 * @param d The array to be set from the Allocation. 819 */ 820 public void copyTo(byte[] d) { 821 validateIsInt8(); 822 mRS.validate(); 823 mRS.nAllocationRead(getID(), d); 824 } 825 826 /** 827 * Copy from the Allocation into a short array. The array must 828 * be at least as large as the Allocation. The allocation must 829 * be of an 16 bit elemental type. 830 * 831 * @param d The array to be set from the Allocation. 832 */ 833 public void copyTo(short[] d) { 834 validateIsInt16(); 835 mRS.validate(); 836 mRS.nAllocationRead(getID(), d); 837 } 838 839 /** 840 * Copy from the Allocation into a int array. The array must be 841 * at least as large as the Allocation. The allocation must be 842 * of an 32 bit elemental type. 843 * 844 * @param d The array to be set from the Allocation. 845 */ 846 public void copyTo(int[] d) { 847 validateIsInt32(); 848 mRS.validate(); 849 mRS.nAllocationRead(getID(), d); 850 } 851 852 /** 853 * Copy from the Allocation into a float array. The array must 854 * be at least as large as the Allocation. The allocation must 855 * be of an 32 bit float elemental type. 856 * 857 * @param d The array to be set from the Allocation. 858 */ 859 public void copyTo(float[] d) { 860 validateIsFloat32(); 861 mRS.validate(); 862 mRS.nAllocationRead(getID(), d); 863 } 864 865 /** 866 * Resize a 1D allocation. The contents of the allocation are 867 * preserved. If new elements are allocated objects are created 868 * with null contents and the new region is otherwise undefined. 869 * 870 * If the new region is smaller the references of any objects 871 * outside the new region will be released. 872 * 873 * A new type will be created with the new dimension. 874 * 875 * @param dimX The new size of the allocation. 876 */ 877 public synchronized void resize(int dimX) { 878 if ((mType.getY() > 0)|| (mType.getZ() > 0) || mType.hasFaces() || mType.hasMipmaps()) { 879 throw new RSInvalidStateException("Resize only support for 1D allocations at this time."); 880 } 881 mRS.nAllocationResize1D(getID(), dimX); 882 mRS.finish(); // Necessary because resize is fifoed and update is async. 883 884 int typeID = mRS.nAllocationGetType(getID()); 885 mType = new Type(typeID, mRS); 886 mType.updateFromNative(); 887 updateCacheInfo(mType); 888 } 889 890 /* 891 public void resize(int dimX, int dimY) { 892 if ((mType.getZ() > 0) || mType.getFaces() || mType.getLOD()) { 893 throw new RSIllegalStateException("Resize only support for 2D allocations at this time."); 894 } 895 if (mType.getY() == 0) { 896 throw new RSIllegalStateException("Resize only support for 2D allocations at this time."); 897 } 898 mRS.nAllocationResize2D(getID(), dimX, dimY); 899 } 900 */ 901 902 903 904 // creation 905 906 static BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options(); 907 static { 908 mBitmapOptions.inScaled = false; 909 } 910 911 /** 912 * 913 * @param type renderscript type describing data layout 914 * @param mips specifies desired mipmap behaviour for the 915 * allocation 916 * @param usage bit field specifying how the allocation is 917 * utilized 918 */ 919 static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips, int usage) { 920 rs.validate(); 921 if (type.getID() == 0) { 922 throw new RSInvalidStateException("Bad Type"); 923 } 924 int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage); 925 if (id == 0) { 926 throw new RSRuntimeException("Allocation creation failed."); 927 } 928 return new Allocation(id, rs, type, usage); 929 } 930 931 /** 932 * Creates a renderscript allocation with the size specified by 933 * the type and no mipmaps generated by default 934 * 935 * @param rs Context to which the allocation will belong. 936 * @param type renderscript type describing data layout 937 * @param usage bit field specifying how the allocation is 938 * utilized 939 * 940 * @return allocation 941 */ 942 static public Allocation createTyped(RenderScript rs, Type type, int usage) { 943 return createTyped(rs, type, MipmapControl.MIPMAP_NONE, usage); 944 } 945 946 /** 947 * Creates a renderscript allocation for use by the script with 948 * the size specified by the type and no mipmaps generated by 949 * default 950 * 951 * @param rs Context to which the allocation will belong. 952 * @param type renderscript type describing data layout 953 * 954 * @return allocation 955 */ 956 static public Allocation createTyped(RenderScript rs, Type type) { 957 return createTyped(rs, type, MipmapControl.MIPMAP_NONE, USAGE_SCRIPT); 958 } 959 960 /** 961 * Creates a renderscript allocation with a specified number of 962 * given elements 963 * 964 * @param rs Context to which the allocation will belong. 965 * @param e describes what each element of an allocation is 966 * @param count specifies the number of element in the allocation 967 * @param usage bit field specifying how the allocation is 968 * utilized 969 * 970 * @return allocation 971 */ 972 static public Allocation createSized(RenderScript rs, Element e, 973 int count, int usage) { 974 rs.validate(); 975 Type.Builder b = new Type.Builder(rs, e); 976 b.setX(count); 977 Type t = b.create(); 978 979 int id = rs.nAllocationCreateTyped(t.getID(), MipmapControl.MIPMAP_NONE.mID, usage); 980 if (id == 0) { 981 throw new RSRuntimeException("Allocation creation failed."); 982 } 983 return new Allocation(id, rs, t, usage); 984 } 985 986 /** 987 * Creates a renderscript allocation with a specified number of 988 * given elements 989 * 990 * @param rs Context to which the allocation will belong. 991 * @param e describes what each element of an allocation is 992 * @param count specifies the number of element in the allocation 993 * 994 * @return allocation 995 */ 996 static public Allocation createSized(RenderScript rs, Element e, int count) { 997 return createSized(rs, e, count, USAGE_SCRIPT); 998 } 999 1000 static Element elementFromBitmap(RenderScript rs, Bitmap b) { 1001 final Bitmap.Config bc = b.getConfig(); 1002 if (bc == Bitmap.Config.ALPHA_8) { 1003 return Element.A_8(rs); 1004 } 1005 if (bc == Bitmap.Config.ARGB_4444) { 1006 return Element.RGBA_4444(rs); 1007 } 1008 if (bc == Bitmap.Config.ARGB_8888) { 1009 return Element.RGBA_8888(rs); 1010 } 1011 if (bc == Bitmap.Config.RGB_565) { 1012 return Element.RGB_565(rs); 1013 } 1014 throw new RSInvalidStateException("Bad bitmap type: " + bc); 1015 } 1016 1017 static Type typeFromBitmap(RenderScript rs, Bitmap b, 1018 MipmapControl mip) { 1019 Element e = elementFromBitmap(rs, b); 1020 Type.Builder tb = new Type.Builder(rs, e); 1021 tb.setX(b.getWidth()); 1022 tb.setY(b.getHeight()); 1023 tb.setMipmaps(mip == MipmapControl.MIPMAP_FULL); 1024 return tb.create(); 1025 } 1026 1027 /** 1028 * Creates a renderscript allocation from a bitmap 1029 * 1030 * @param rs Context to which the allocation will belong. 1031 * @param b bitmap source for the allocation data 1032 * @param mips specifies desired mipmap behaviour for the 1033 * allocation 1034 * @param usage bit field specifying how the allocation is 1035 * utilized 1036 * 1037 * @return renderscript allocation containing bitmap data 1038 * 1039 */ 1040 static public Allocation createFromBitmap(RenderScript rs, Bitmap b, 1041 MipmapControl mips, 1042 int usage) { 1043 rs.validate(); 1044 Type t = typeFromBitmap(rs, b, mips); 1045 1046 int id = rs.nAllocationCreateFromBitmap(t.getID(), mips.mID, b, usage); 1047 if (id == 0) { 1048 throw new RSRuntimeException("Load failed."); 1049 } 1050 return new Allocation(id, rs, t, usage); 1051 } 1052 1053 /** 1054 * 1055 * 1056 * @hide 1057 * 1058 */ 1059 public SurfaceTexture getSurfaceTexture() { 1060 if ((mUsage & USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE) == 0) { 1061 throw new RSInvalidStateException("Allocation is not a surface texture."); 1062 } 1063 1064 int id = mRS.nAllocationGetSurfaceTextureID(getID()); 1065 return new SurfaceTexture(id); 1066 1067 } 1068 1069 1070 /** 1071 * Creates a non-mipmapped renderscript allocation to use as a 1072 * graphics texture 1073 * 1074 * @param rs Context to which the allocation will belong. 1075 * @param b bitmap source for the allocation data 1076 * 1077 * @return renderscript allocation containing bitmap data 1078 * 1079 */ 1080 static public Allocation createFromBitmap(RenderScript rs, Bitmap b) { 1081 return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE, 1082 USAGE_GRAPHICS_TEXTURE); 1083 } 1084 1085 /** 1086 * Creates a cubemap allocation from a bitmap containing the 1087 * horizontal list of cube faces. Each individual face must be 1088 * the same size and power of 2 1089 * 1090 * @param rs Context to which the allocation will belong. 1091 * @param b bitmap with cubemap faces layed out in the following 1092 * format: right, left, top, bottom, front, back 1093 * @param mips specifies desired mipmap behaviour for the cubemap 1094 * @param usage bit field specifying how the cubemap is utilized 1095 * 1096 * @return allocation containing cubemap data 1097 * 1098 */ 1099 static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b, 1100 MipmapControl mips, 1101 int usage) { 1102 rs.validate(); 1103 1104 int height = b.getHeight(); 1105 int width = b.getWidth(); 1106 1107 if (width % 6 != 0) { 1108 throw new RSIllegalArgumentException("Cubemap height must be multiple of 6"); 1109 } 1110 if (width / 6 != height) { 1111 throw new RSIllegalArgumentException("Only square cube map faces supported"); 1112 } 1113 boolean isPow2 = (height & (height - 1)) == 0; 1114 if (!isPow2) { 1115 throw new RSIllegalArgumentException("Only power of 2 cube faces supported"); 1116 } 1117 1118 Element e = elementFromBitmap(rs, b); 1119 Type.Builder tb = new Type.Builder(rs, e); 1120 tb.setX(height); 1121 tb.setY(height); 1122 tb.setFaces(true); 1123 tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL); 1124 Type t = tb.create(); 1125 1126 int id = rs.nAllocationCubeCreateFromBitmap(t.getID(), mips.mID, b, usage); 1127 if(id == 0) { 1128 throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e); 1129 } 1130 return new Allocation(id, rs, t, usage); 1131 } 1132 1133 /** 1134 * Creates a non-mipmapped cubemap allocation for use as a 1135 * graphics texture from a bitmap containing the horizontal list 1136 * of cube faces. Each individual face must be the same size and 1137 * power of 2 1138 * 1139 * @param rs Context to which the allocation will belong. 1140 * @param b bitmap with cubemap faces layed out in the following 1141 * format: right, left, top, bottom, front, back 1142 * 1143 * @return allocation containing cubemap data 1144 * 1145 */ 1146 static public Allocation createCubemapFromBitmap(RenderScript rs, 1147 Bitmap b) { 1148 return createCubemapFromBitmap(rs, b, MipmapControl.MIPMAP_NONE, 1149 USAGE_GRAPHICS_TEXTURE); 1150 } 1151 1152 /** 1153 * Creates a cubemap allocation from 6 bitmaps containing 1154 * the cube faces. All the faces must be the same size and 1155 * power of 2 1156 * 1157 * @param rs Context to which the allocation will belong. 1158 * @param xpos cubemap face in the positive x direction 1159 * @param xneg cubemap face in the negative x direction 1160 * @param ypos cubemap face in the positive y direction 1161 * @param yneg cubemap face in the negative y direction 1162 * @param zpos cubemap face in the positive z direction 1163 * @param zneg cubemap face in the negative z direction 1164 * @param mips specifies desired mipmap behaviour for the cubemap 1165 * @param usage bit field specifying how the cubemap is utilized 1166 * 1167 * @return allocation containing cubemap data 1168 * 1169 */ 1170 static public Allocation createCubemapFromCubeFaces(RenderScript rs, 1171 Bitmap xpos, 1172 Bitmap xneg, 1173 Bitmap ypos, 1174 Bitmap yneg, 1175 Bitmap zpos, 1176 Bitmap zneg, 1177 MipmapControl mips, 1178 int usage) { 1179 int height = xpos.getHeight(); 1180 if (xpos.getWidth() != height || 1181 xneg.getWidth() != height || xneg.getHeight() != height || 1182 ypos.getWidth() != height || ypos.getHeight() != height || 1183 yneg.getWidth() != height || yneg.getHeight() != height || 1184 zpos.getWidth() != height || zpos.getHeight() != height || 1185 zneg.getWidth() != height || zneg.getHeight() != height) { 1186 throw new RSIllegalArgumentException("Only square cube map faces supported"); 1187 } 1188 boolean isPow2 = (height & (height - 1)) == 0; 1189 if (!isPow2) { 1190 throw new RSIllegalArgumentException("Only power of 2 cube faces supported"); 1191 } 1192 1193 Element e = elementFromBitmap(rs, xpos); 1194 Type.Builder tb = new Type.Builder(rs, e); 1195 tb.setX(height); 1196 tb.setY(height); 1197 tb.setFaces(true); 1198 tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL); 1199 Type t = tb.create(); 1200 Allocation cubemap = Allocation.createTyped(rs, t, mips, usage); 1201 1202 AllocationAdapter adapter = AllocationAdapter.create2D(rs, cubemap); 1203 adapter.setFace(Type.CubemapFace.POSITIVE_X); 1204 adapter.copyFrom(xpos); 1205 adapter.setFace(Type.CubemapFace.NEGATIVE_X); 1206 adapter.copyFrom(xneg); 1207 adapter.setFace(Type.CubemapFace.POSITIVE_Y); 1208 adapter.copyFrom(ypos); 1209 adapter.setFace(Type.CubemapFace.NEGATIVE_Y); 1210 adapter.copyFrom(yneg); 1211 adapter.setFace(Type.CubemapFace.POSITIVE_Z); 1212 adapter.copyFrom(zpos); 1213 adapter.setFace(Type.CubemapFace.NEGATIVE_Z); 1214 adapter.copyFrom(zneg); 1215 1216 return cubemap; 1217 } 1218 1219 /** 1220 * Creates a non-mipmapped cubemap allocation for use as a 1221 * graphics texture from 6 bitmaps containing 1222 * the cube faces. All the faces must be the same size and 1223 * power of 2 1224 * 1225 * @param rs Context to which the allocation will belong. 1226 * @param xpos cubemap face in the positive x direction 1227 * @param xneg cubemap face in the negative x direction 1228 * @param ypos cubemap face in the positive y direction 1229 * @param yneg cubemap face in the negative y direction 1230 * @param zpos cubemap face in the positive z direction 1231 * @param zneg cubemap face in the negative z direction 1232 * 1233 * @return allocation containing cubemap data 1234 * 1235 */ 1236 static public Allocation createCubemapFromCubeFaces(RenderScript rs, 1237 Bitmap xpos, 1238 Bitmap xneg, 1239 Bitmap ypos, 1240 Bitmap yneg, 1241 Bitmap zpos, 1242 Bitmap zneg) { 1243 return createCubemapFromCubeFaces(rs, xpos, xneg, ypos, yneg, 1244 zpos, zneg, MipmapControl.MIPMAP_NONE, 1245 USAGE_GRAPHICS_TEXTURE); 1246 } 1247 1248 /** 1249 * Creates a renderscript allocation from the bitmap referenced 1250 * by resource id 1251 * 1252 * @param rs Context to which the allocation will belong. 1253 * @param res application resources 1254 * @param id resource id to load the data from 1255 * @param mips specifies desired mipmap behaviour for the 1256 * allocation 1257 * @param usage bit field specifying how the allocation is 1258 * utilized 1259 * 1260 * @return renderscript allocation containing resource data 1261 * 1262 */ 1263 static public Allocation createFromBitmapResource(RenderScript rs, 1264 Resources res, 1265 int id, 1266 MipmapControl mips, 1267 int usage) { 1268 1269 rs.validate(); 1270 Bitmap b = BitmapFactory.decodeResource(res, id); 1271 Allocation alloc = createFromBitmap(rs, b, mips, usage); 1272 b.recycle(); 1273 return alloc; 1274 } 1275 1276 /** 1277 * Creates a non-mipmapped renderscript allocation to use as a 1278 * graphics texture from the bitmap referenced by resource id 1279 * 1280 * @param rs Context to which the allocation will belong. 1281 * @param res application resources 1282 * @param id resource id to load the data from 1283 * 1284 * @return renderscript allocation containing resource data 1285 * 1286 */ 1287 static public Allocation createFromBitmapResource(RenderScript rs, 1288 Resources res, 1289 int id) { 1290 return createFromBitmapResource(rs, res, id, 1291 MipmapControl.MIPMAP_NONE, 1292 USAGE_GRAPHICS_TEXTURE); 1293 } 1294 1295 /** 1296 * Creates a renderscript allocation containing string data 1297 * encoded in UTF-8 format 1298 * 1299 * @param rs Context to which the allocation will belong. 1300 * @param str string to create the allocation from 1301 * @param usage bit field specifying how the allocaiton is 1302 * utilized 1303 * 1304 */ 1305 static public Allocation createFromString(RenderScript rs, 1306 String str, 1307 int usage) { 1308 rs.validate(); 1309 byte[] allocArray = null; 1310 try { 1311 allocArray = str.getBytes("UTF-8"); 1312 Allocation alloc = Allocation.createSized(rs, Element.U8(rs), allocArray.length, usage); 1313 alloc.copyFrom(allocArray); 1314 return alloc; 1315 } 1316 catch (Exception e) { 1317 throw new RSRuntimeException("Could not convert string to utf-8."); 1318 } 1319 } 1320} 1321 1322 1323