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