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