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