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