Allocation.java revision dcc231955d81c66309ce97cca05a25f79ee7d5ea
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 * Memory allocation class for renderscript. An allocation combines a Type with 30 * memory to provide storage for user data and objects. 31 * 32 * Allocations may exist in one or more memory spaces. Currently those are 33 * Script: accessable by RS scripts. 34 * Graphics Texture: accessable as a graphics texture. 35 * Graphics Vertex: accessable as graphical vertex data. 36 * Graphics Constants: Accessable as constants in user shaders 37 * 38 * By default java side updates are always applied to the script accessable 39 * memory. If this is not present they are then applied to the various HW 40 * memory types. A syncAll call is necessary after the script data is update to 41 * keep the other memory spaces in sync. 42 * 43 **/ 44public class Allocation extends BaseObj { 45 Type mType; 46 Bitmap mBitmap; 47 int mUsage; 48 49 public static final int USAGE_SCRIPT = 0x0001; 50 public static final int USAGE_GRAPHICS_TEXTURE = 0x0002; 51 public static final int USAGE_GRAPHICS_VERTEX = 0x0004; 52 public static final int USAGE_GRAPHICS_CONSTANTS = 0x0008; 53 54 55 public enum MipmapControl { 56 MIPMAP_NONE(0), 57 MIPMAP_FULL(1), 58 MIPMAP_ON_SYNC_TO_TEXTURE(2); 59 60 int mID; 61 MipmapControl(int id) { 62 mID = id; 63 } 64 } 65 66 Allocation(int id, RenderScript rs, Type t, int usage) { 67 super(id, rs); 68 if ((usage & ~(USAGE_SCRIPT | 69 USAGE_GRAPHICS_TEXTURE | 70 USAGE_GRAPHICS_VERTEX | 71 USAGE_GRAPHICS_CONSTANTS)) != 0) { 72 throw new RSIllegalArgumentException("Unknown usage specified."); 73 } 74 mType = t; 75 } 76 77 @Override 78 void updateFromNative() { 79 super.updateFromNative(); 80 int typeID = mRS.nAllocationGetType(getID()); 81 if(typeID != 0) { 82 mType = new Type(typeID, mRS); 83 mType.updateFromNative(); 84 } 85 } 86 87 public Type getType() { 88 return mType; 89 } 90 91 public void syncAll(int srcLocation) { 92 switch (srcLocation) { 93 case USAGE_SCRIPT: 94 case USAGE_GRAPHICS_CONSTANTS: 95 case USAGE_GRAPHICS_TEXTURE: 96 case USAGE_GRAPHICS_VERTEX: 97 break; 98 default: 99 throw new RSIllegalArgumentException("Source must be exactly one usage type."); 100 } 101 mRS.validate(); 102 mRS.nAllocationSyncAll(getID(), srcLocation); 103 } 104 105 public void copyFrom(BaseObj[] d) { 106 mRS.validate(); 107 if (d.length != mType.getCount()) { 108 throw new RSIllegalArgumentException("Array size mismatch, allocation sizeX = " + 109 mType.getCount() + ", array length = " + d.length); 110 } 111 int i[] = new int[d.length]; 112 for (int ct=0; ct < d.length; ct++) { 113 i[ct] = d[ct].getID(); 114 } 115 copy1DRangeFrom(0, mType.getCount(), i); 116 } 117 118 private void validateBitmap(Bitmap b) { 119 mRS.validate(); 120 if(mType.getX() != b.getWidth() || 121 mType.getY() != b.getHeight()) { 122 throw new RSIllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch"); 123 } 124 } 125 126 public void copyFrom(int[] d) { 127 mRS.validate(); 128 copy1DRangeFrom(0, mType.getCount(), d); 129 } 130 public void copyFrom(short[] d) { 131 mRS.validate(); 132 copy1DRangeFrom(0, mType.getCount(), d); 133 } 134 public void copyFrom(byte[] d) { 135 mRS.validate(); 136 copy1DRangeFrom(0, mType.getCount(), d); 137 } 138 public void copyFrom(float[] d) { 139 mRS.validate(); 140 copy1DRangeFrom(0, mType.getCount(), d); 141 } 142 public void copyFrom(Bitmap b) { 143 validateBitmap(b); 144 mRS.nAllocationCopyFromBitmap(getID(), b); 145 } 146 147 /** 148 * @hide 149 * 150 * This is only intended to be used by auto-generate code reflected from the 151 * renderscript script files. 152 * 153 * @param xoff 154 * @param fp 155 */ 156 public void setOneElement(int xoff, FieldPacker fp) { 157 int eSize = mType.mElement.getSizeBytes(); 158 final byte[] data = fp.getData(); 159 160 int count = data.length / eSize; 161 if ((eSize * count) != data.length) { 162 throw new RSIllegalArgumentException("Field packer length " + data.length + 163 " not divisible by element size " + eSize + "."); 164 } 165 data1DChecks(xoff, count, data.length, data.length); 166 mRS.nAllocationData1D(getID(), xoff, 0, count, data, data.length); 167 } 168 169 170 /** 171 * @hide 172 * 173 * This is only intended to be used by auto-generate code reflected from the 174 * renderscript script files. 175 * 176 * @param xoff 177 * @param component_number 178 * @param fp 179 */ 180 public void setOneComponent(int xoff, int component_number, FieldPacker fp) { 181 if (component_number >= mType.mElement.mElements.length) { 182 throw new RSIllegalArgumentException("Component_number " + component_number + " out of range."); 183 } 184 if(xoff < 0) { 185 throw new RSIllegalArgumentException("Offset must be >= 0."); 186 } 187 188 final byte[] data = fp.getData(); 189 int eSize = mType.mElement.mElements[component_number].getSizeBytes(); 190 191 if (data.length != eSize) { 192 throw new RSIllegalArgumentException("Field packer sizelength " + data.length + 193 " does not match component size " + eSize + "."); 194 } 195 196 mRS.nAllocationElementData1D(getID(), xoff, 0, component_number, data, data.length); 197 } 198 199 private void data1DChecks(int off, int count, int len, int dataSize) { 200 mRS.validate(); 201 if(off < 0) { 202 throw new RSIllegalArgumentException("Offset must be >= 0."); 203 } 204 if(count < 1) { 205 throw new RSIllegalArgumentException("Count must be >= 1."); 206 } 207 if((off + count) > mType.getCount()) { 208 throw new RSIllegalArgumentException("Overflow, Available count " + mType.getCount() + 209 ", got " + count + " at offset " + off + "."); 210 } 211 if((len) < dataSize) { 212 throw new RSIllegalArgumentException("Array too small for allocation type."); 213 } 214 } 215 216 public void copy1DRangeFrom(int off, int count, int[] d) { 217 int dataSize = mType.mElement.getSizeBytes() * count; 218 data1DChecks(off, count, d.length * 4, dataSize); 219 mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize); 220 } 221 public void copy1DRangeFrom(int off, int count, short[] d) { 222 int dataSize = mType.mElement.getSizeBytes() * count; 223 data1DChecks(off, count, d.length * 2, dataSize); 224 mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize); 225 } 226 public void copy1DRangeFrom(int off, int count, byte[] d) { 227 int dataSize = mType.mElement.getSizeBytes() * count; 228 data1DChecks(off, count, d.length, dataSize); 229 mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize); 230 } 231 public void copy1DRangeFrom(int off, int count, float[] d) { 232 int dataSize = mType.mElement.getSizeBytes() * count; 233 data1DChecks(off, count, d.length * 4, dataSize); 234 mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize); 235 } 236 237 238 public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] d) { 239 mRS.validate(); 240 mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, d, d.length); 241 } 242 243 public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] d) { 244 mRS.validate(); 245 mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, d, d.length * 2); 246 } 247 248 public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] d) { 249 mRS.validate(); 250 mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, d, d.length * 4); 251 } 252 253 public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] d) { 254 mRS.validate(); 255 mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, d, d.length * 4); 256 } 257 258 public void copy2DRangeFrom(int xoff, int yoff, Bitmap b) { 259 mRS.validate(); 260 mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, b); 261 } 262 263 264 public void copyTo(Bitmap b) { 265 validateBitmap(b); 266 mRS.nAllocationCopyToBitmap(getID(), b); 267 } 268 269 public void copyTo(byte[] d) { 270 mRS.validate(); 271 mRS.nAllocationRead(getID(), d); 272 } 273 274 public void copyTo(short[] d) { 275 mRS.validate(); 276 mRS.nAllocationRead(getID(), d); 277 } 278 279 public void copyTo(int[] d) { 280 mRS.validate(); 281 mRS.nAllocationRead(getID(), d); 282 } 283 284 public void copyTo(float[] d) { 285 mRS.validate(); 286 mRS.nAllocationRead(getID(), d); 287 } 288 289 public synchronized void resize(int dimX) { 290 if ((mType.getY() > 0)|| (mType.getZ() > 0) || mType.hasFaces() || mType.hasMipmaps()) { 291 throw new RSInvalidStateException("Resize only support for 1D allocations at this time."); 292 } 293 mRS.nAllocationResize1D(getID(), dimX); 294 mRS.finish(); // Necessary because resize is fifoed and update is async. 295 296 int typeID = mRS.nAllocationGetType(getID()); 297 mType = new Type(typeID, mRS); 298 mType.updateFromNative(); 299 } 300 301 /* 302 public void resize(int dimX, int dimY) { 303 if ((mType.getZ() > 0) || mType.getFaces() || mType.getLOD()) { 304 throw new RSIllegalStateException("Resize only support for 2D allocations at this time."); 305 } 306 if (mType.getY() == 0) { 307 throw new RSIllegalStateException("Resize only support for 2D allocations at this time."); 308 } 309 mRS.nAllocationResize2D(getID(), dimX, dimY); 310 } 311 */ 312 313 314 315 // creation 316 317 static BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options(); 318 static { 319 mBitmapOptions.inScaled = false; 320 } 321 322 static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mc, int usage) { 323 rs.validate(); 324 if (type.getID() == 0) { 325 throw new RSInvalidStateException("Bad Type"); 326 } 327 int id = rs.nAllocationCreateTyped(type.getID(), mc.mID, usage); 328 if (id == 0) { 329 throw new RSRuntimeException("Allocation creation failed."); 330 } 331 return new Allocation(id, rs, type, usage); 332 } 333 334 static public Allocation createTyped(RenderScript rs, Type type, int usage) { 335 return createTyped(rs, type, MipmapControl.MIPMAP_NONE, usage); 336 } 337 338 static public Allocation createTyped(RenderScript rs, Type type) { 339 return createTyped(rs, type, MipmapControl.MIPMAP_NONE, USAGE_SCRIPT); 340 } 341 342 static public Allocation createSized(RenderScript rs, Element e, 343 int count, int usage) { 344 rs.validate(); 345 Type.Builder b = new Type.Builder(rs, e); 346 b.setX(count); 347 Type t = b.create(); 348 349 int id = rs.nAllocationCreateTyped(t.getID(), MipmapControl.MIPMAP_NONE.mID, usage); 350 if (id == 0) { 351 throw new RSRuntimeException("Allocation creation failed."); 352 } 353 return new Allocation(id, rs, t, usage); 354 } 355 356 static public Allocation createSized(RenderScript rs, Element e, int count) { 357 return createSized(rs, e, count, USAGE_SCRIPT); 358 } 359 360 static Element elementFromBitmap(RenderScript rs, Bitmap b) { 361 final Bitmap.Config bc = b.getConfig(); 362 if (bc == Bitmap.Config.ALPHA_8) { 363 return Element.A_8(rs); 364 } 365 if (bc == Bitmap.Config.ARGB_4444) { 366 return Element.RGBA_4444(rs); 367 } 368 if (bc == Bitmap.Config.ARGB_8888) { 369 return Element.RGBA_8888(rs); 370 } 371 if (bc == Bitmap.Config.RGB_565) { 372 return Element.RGB_565(rs); 373 } 374 throw new RSInvalidStateException("Bad bitmap type: " + bc); 375 } 376 377 static Type typeFromBitmap(RenderScript rs, Bitmap b, 378 MipmapControl mip) { 379 Element e = elementFromBitmap(rs, b); 380 Type.Builder tb = new Type.Builder(rs, e); 381 tb.setX(b.getWidth()); 382 tb.setY(b.getHeight()); 383 tb.setMipmaps(mip == MipmapControl.MIPMAP_FULL); 384 return tb.create(); 385 } 386 387 static public Allocation createFromBitmap(RenderScript rs, Bitmap b, 388 MipmapControl mips, 389 int usage) { 390 rs.validate(); 391 Type t = typeFromBitmap(rs, b, mips); 392 393 int id = rs.nAllocationCreateFromBitmap(t.getID(), mips.mID, b, usage); 394 if (id == 0) { 395 throw new RSRuntimeException("Load failed."); 396 } 397 return new Allocation(id, rs, t, usage); 398 } 399 400 static public Allocation createFromBitmap(RenderScript rs, Bitmap b) { 401 return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE, 402 USAGE_GRAPHICS_TEXTURE); 403 } 404 405 /** 406 * Creates a cubemap allocation from a bitmap containing the 407 * horizontal list of cube faces. Each individual face must be 408 * the same size and power of 2 409 * 410 * @param rs 411 * @param b bitmap with cubemap faces layed out in the following 412 * format: right, left, top, bottom, front, back 413 * @param mips specifies desired mipmap behaviour for the cubemap 414 * @param usage bitfield specifying how the cubemap is utilized 415 * 416 **/ 417 static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b, 418 MipmapControl mips, 419 int usage) { 420 rs.validate(); 421 422 int height = b.getHeight(); 423 int width = b.getWidth(); 424 425 if (width % 6 != 0) { 426 throw new RSIllegalArgumentException("Cubemap height must be multiple of 6"); 427 } 428 if (width / 6 != height) { 429 throw new RSIllegalArgumentException("Only square cube map faces supported"); 430 } 431 boolean isPow2 = (height & (height - 1)) == 0; 432 if (!isPow2) { 433 throw new RSIllegalArgumentException("Only power of 2 cube faces supported"); 434 } 435 436 Element e = elementFromBitmap(rs, b); 437 Type.Builder tb = new Type.Builder(rs, e); 438 tb.setX(height); 439 tb.setY(height); 440 tb.setFaces(true); 441 tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL); 442 Type t = tb.create(); 443 444 int id = rs.nAllocationCubeCreateFromBitmap(t.getID(), mips.mID, b, usage); 445 if(id == 0) { 446 throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e); 447 } 448 return new Allocation(id, rs, t, usage); 449 } 450 451 static public Allocation createCubemapFromBitmap(RenderScript rs, 452 Bitmap b) { 453 return createCubemapFromBitmap(rs, b, MipmapControl.MIPMAP_NONE, 454 USAGE_GRAPHICS_TEXTURE); 455 } 456 457 static public Allocation createCubemapFromCubeFaces(RenderScript rs, 458 Bitmap xpos, 459 Bitmap xneg, 460 Bitmap ypos, 461 Bitmap yneg, 462 Bitmap zpos, 463 Bitmap zneg, 464 MipmapControl mips, 465 int usage) { 466 int height = xpos.getHeight(); 467 if (xpos.getWidth() != height || 468 xneg.getWidth() != height || xneg.getHeight() != height || 469 ypos.getWidth() != height || ypos.getHeight() != height || 470 yneg.getWidth() != height || yneg.getHeight() != height || 471 zpos.getWidth() != height || zpos.getHeight() != height || 472 zneg.getWidth() != height || zneg.getHeight() != height) { 473 throw new RSIllegalArgumentException("Only square cube map faces supported"); 474 } 475 boolean isPow2 = (height & (height - 1)) == 0; 476 if (!isPow2) { 477 throw new RSIllegalArgumentException("Only power of 2 cube faces supported"); 478 } 479 480 Element e = elementFromBitmap(rs, xpos); 481 Type.Builder tb = new Type.Builder(rs, e); 482 tb.setX(height); 483 tb.setY(height); 484 tb.setFaces(true); 485 tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL); 486 Type t = tb.create(); 487 Allocation cubemap = Allocation.createTyped(rs, t, mips, usage); 488 489 AllocationAdapter adapter = AllocationAdapter.create2D(rs, cubemap); 490 adapter.setFace(Type.CubemapFace.POSITVE_X); 491 adapter.copyFrom(xpos); 492 adapter.setFace(Type.CubemapFace.NEGATIVE_X); 493 adapter.copyFrom(xneg); 494 adapter.setFace(Type.CubemapFace.POSITVE_Y); 495 adapter.copyFrom(ypos); 496 adapter.setFace(Type.CubemapFace.NEGATIVE_Y); 497 adapter.copyFrom(yneg); 498 adapter.setFace(Type.CubemapFace.POSITVE_Z); 499 adapter.copyFrom(zpos); 500 adapter.setFace(Type.CubemapFace.NEGATIVE_Z); 501 adapter.copyFrom(zneg); 502 503 return cubemap; 504 } 505 506 static public Allocation createCubemapFromCubeFaces(RenderScript rs, 507 Bitmap xpos, 508 Bitmap xneg, 509 Bitmap ypos, 510 Bitmap yneg, 511 Bitmap zpos, 512 Bitmap zneg) { 513 return createCubemapFromCubeFaces(rs, xpos, xneg, ypos, yneg, 514 zpos, zneg, MipmapControl.MIPMAP_NONE, 515 USAGE_GRAPHICS_TEXTURE); 516 } 517 518 static public Allocation createFromBitmapResource(RenderScript rs, 519 Resources res, 520 int id, 521 MipmapControl mips, 522 int usage) { 523 524 rs.validate(); 525 Bitmap b = BitmapFactory.decodeResource(res, id); 526 Allocation alloc = createFromBitmap(rs, b, mips, usage); 527 b.recycle(); 528 return alloc; 529 } 530 531 static public Allocation createFromBitmapResource(RenderScript rs, 532 Resources res, 533 int id) { 534 return createFromBitmapResource(rs, res, id, 535 MipmapControl.MIPMAP_NONE, 536 USAGE_GRAPHICS_TEXTURE); 537 } 538 539 static public Allocation createFromString(RenderScript rs, 540 String str, 541 int usage) { 542 rs.validate(); 543 byte[] allocArray = null; 544 try { 545 allocArray = str.getBytes("UTF-8"); 546 Allocation alloc = Allocation.createSized(rs, Element.U8(rs), allocArray.length, usage); 547 alloc.copyFrom(allocArray); 548 return alloc; 549 } 550 catch (Exception e) { 551 throw new RSRuntimeException("Could not convert string to utf-8."); 552 } 553 } 554} 555 556 557