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