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