1 /* 2 * Copyright 2014 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.hardware.camera2.cts.rs; 18 19 import static android.hardware.camera2.cts.helpers.Preconditions.*; 20 21 import android.graphics.ImageFormat; 22 import android.graphics.PixelFormat; 23 import android.util.Size; 24 import android.renderscript.Allocation; 25 import android.renderscript.Element; 26 import android.renderscript.RenderScript; 27 import android.renderscript.Type; 28 import android.util.Log; 29 30 /** 31 * Abstract the information necessary to create new {@link Allocation allocations} with 32 * their size, element, type, and usage. 33 * 34 * <p>This also includes convenience functions for printing to a string, something RenderScript 35 * lacks at the time of writing.</p> 36 * 37 * <p>Note that when creating a new {@link AllocationInfo} the usage flags <b>always</b> get ORd 38 * to {@link Allocation#USAGE_IO_SCRIPT}.</p> 39 */ 40 public class AllocationInfo { 41 42 private final RenderScript mRS = RenderScriptSingleton.getRS(); 43 44 private final Size mSize; 45 private final Element mElement; 46 private final Type mType; 47 private final int mUsage; 48 49 private static final String TAG = "AllocationInfo"; 50 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 51 52 /** 53 * Create a new {@link AllocationInfo} holding the element, size, and usage 54 * from an existing {@link Allocation}. 55 * 56 * @param allocation {@link Allocation} 57 * 58 * @return A new {@link AllocationInfo} 59 * 60 * @throws NullPointerException if allocation was {@code null}. 61 */ newInstance(Allocation allocation)62 public static AllocationInfo newInstance(Allocation allocation) { 63 checkNotNull("allocation", allocation); 64 65 return new AllocationInfo(allocation.getElement(), 66 new Size(allocation.getType().getX(), allocation.getType().getY()), 67 allocation.getUsage()); 68 } 69 70 /** 71 * Create a new {@link AllocationInfo} holding the specified format, {@link Size}, 72 * and {@link Allocation#USAGE_SCRIPT usage}. 73 * 74 * <p>The usage is always ORd with {@link Allocation#USAGE_SCRIPT}.</p> 75 * 76 * <p>The closest {@link Element} possible is created from the format.</p> 77 * 78 * @param size {@link Size} 79 * @param format An int format 80 * @param usage Usage flags 81 * 82 * @return A new {@link AllocationInfo} holding the given arguments. 83 * 84 * @throws NullPointerException if size was {@code null}. 85 * 86 * @see ImageFormat 87 * @see PixelFormat 88 */ newInstance(Size size, int format, int usage)89 public static AllocationInfo newInstance(Size size, int format, int usage) { 90 RenderScript rs = RenderScriptSingleton.getRS(); 91 92 Element element; 93 switch (format) { 94 case ImageFormat.YUV_420_888: 95 element = Element.YUV(rs); 96 break; 97 case PixelFormat.RGBA_8888: 98 element = Element.RGBA_8888(rs); 99 break; 100 // TODO: map more formats here 101 default: 102 throw new UnsupportedOperationException("Unsupported format " + format); 103 } 104 105 return new AllocationInfo(element, size, usage); 106 } 107 108 109 /** 110 * Create a new {@link AllocationInfo} holding the specified format, {@link Size}, 111 * with the default usage. 112 * 113 * <p>The default usage is always {@link Allocation#USAGE_SCRIPT}.</p> 114 * 115 * <p>The closest {@link Element} possible is created from the format.</p> 116 * 117 * @param size {@link Size} 118 * @param format An int format 119 * 120 * @return A new {@link AllocationInfo} holding the given arguments. 121 * 122 * @throws NullPointerException if size was {@code null}. 123 * 124 * @see ImageFormat 125 * @see PixelFormat 126 */ newInstance(Size size, int format)127 public static AllocationInfo newInstance(Size size, int format) { 128 return newInstance(size, format, Allocation.USAGE_SCRIPT); 129 } 130 131 /** 132 * Create a new {@link AllocationInfo} holding the specified {@link Element}, {@link Size}, 133 * with the default usage. 134 * 135 * <p>The default usage is always {@link Allocation#USAGE_SCRIPT}.</p> 136 * 137 * @param element {@link Element} 138 * @param size {@link Size} 139 * 140 * @return A new {@link AllocationInfo} holding the given arguments. 141 * 142 * @throws NullPointerException if size was {@code null}. 143 * @throws NullPointerException if element was {@code null}. 144 */ newInstance(Element element, Size size)145 public static AllocationInfo newInstance(Element element, Size size) { 146 return new AllocationInfo(element, size, Allocation.USAGE_SCRIPT); 147 } 148 149 /** 150 * Create a new {@link AllocationInfo} holding the specified {@link Element}, {@link Size}, 151 * and {@link Allocation#USAGE_SCRIPT usage}. 152 * 153 * <p>The usage is always ORd with {@link Allocation#USAGE_SCRIPT}.</p> 154 * 155 * @param element {@link Element} 156 * @param size {@link Size} 157 * @param usage usage flags 158 * 159 * @return A new {@link AllocationInfo} holding the given arguments. 160 * 161 * @throws NullPointerException if size was {@code null}. 162 * @throws NullPointerException if element was {@code null}. 163 */ newInstance(Element element, Size size, int usage)164 public static AllocationInfo newInstance(Element element, Size size, int usage) { 165 return new AllocationInfo(element, size, usage); 166 } 167 168 /** 169 * Create a new {@link AllocationInfo} by copying the existing data but appending 170 * the new usage flags to the old usage flags. 171 * 172 * @param usage usage flags 173 * 174 * @return A new {@link AllocationInfo} with new usage flags ORd to the old ones. 175 */ addExtraUsage(int usage)176 public AllocationInfo addExtraUsage(int usage) { 177 return new AllocationInfo(mElement, mSize, mUsage | usage); 178 } 179 180 /** 181 * Create a new {@link AllocationInfo} by copying the existing data but changing the format, 182 * and appending the new usage flags to the old usage flags. 183 * 184 * @param format Format 185 * @param usage usage flags 186 * 187 * @return A new {@link AllocationInfo} with new format/usage. 188 * 189 * @see ImageFormat 190 * @see PixelFormat 191 */ changeFormatAndUsage(int format, int usage)192 public AllocationInfo changeFormatAndUsage(int format, int usage) { 193 return newInstance(getSize(), format, usage); 194 } 195 196 /** 197 * Create a new {@link AllocationInfo} by copying the existing data but replacing the old 198 * usage with the new usage flags. 199 * 200 * @param usage usage flags 201 * 202 * @return A new {@link AllocationInfo} with new format/usage. 203 * 204 * @see ImageFormat 205 * @see PixelFormat 206 */ changeElementWithDefaultUsage(Element element)207 public AllocationInfo changeElementWithDefaultUsage(Element element) { 208 return newInstance(element, getSize()); 209 } 210 211 /** 212 * Create a new {@link AllocationInfo} by copying the existing data but changing the format, 213 * and replacing the old usage flags with default usage flags. 214 * 215 * @param format Format 216 * 217 * @return A new {@link AllocationInfo} with new format/usage. 218 * 219 * @see ImageFormat 220 * @see PixelFormat 221 */ changeFormatWithDefaultUsage(int format)222 public AllocationInfo changeFormatWithDefaultUsage(int format) { 223 return newInstance(getSize(), format, Allocation.USAGE_SCRIPT); 224 } 225 AllocationInfo(Element element, Size size, int usage)226 private AllocationInfo(Element element, Size size, int usage) { 227 checkNotNull("element", element); 228 checkNotNull("size", size); 229 230 mElement = element; 231 mSize = size; 232 mUsage = usage; 233 234 Type.Builder typeBuilder = typeBuilder(element, size); 235 236 if (element.equals(Element.YUV(mRS))) { 237 typeBuilder.setYuvFormat(ImageFormat.YUV_420_888); 238 } 239 240 mType = typeBuilder.create(); 241 } 242 243 /** 244 * Get the {@link Type type} for this info. 245 * 246 * <p>Note that this is the same type that would get used by the {@link Allocation} 247 * created with {@link #createAllocation()}. 248 * 249 * @return The type (never {@code null}). 250 */ getType()251 public Type getType() { 252 return mType; 253 } 254 255 /** 256 * Get the usage. 257 * 258 * <p>The bit for {@link Allocation#USAGE_SCRIPT} will always be set to 1.</p> 259 * 260 * @return usage flags 261 */ getUsage()262 public int getUsage() { 263 return mUsage; 264 } 265 266 /** 267 * Get the size. 268 * 269 * @return The size (never {@code null}). 270 */ getSize()271 public Size getSize() { 272 return mSize; 273 } 274 275 /** 276 * Get the {@link Element}. 277 * 278 * @return The element (never {@code null}). 279 */ getElement()280 public Element getElement() { 281 return mElement; 282 } 283 284 /** 285 * Convenience enum to represent commonly-used elements without needing a RenderScript object. 286 */ 287 public enum ElementInfo { 288 YUV, 289 RGBA_8888, 290 U8_3, 291 U8_4; 292 293 private static final String TAG = "ElementInfo"; 294 295 /** 296 * Create an {@link ElementInfo} by converting it from a {@link Element}. 297 * 298 * @param element The element for which you want to get an enum for. 299 * 300 * @return The element info is a corresponding one exists, or {@code null} otherwise. 301 */ fromElement(Element element)302 public static ElementInfo fromElement(Element element) { 303 checkNotNull("element", element); 304 305 if (element.equals(Element.YUV(RenderScriptSingleton.getRS()))) { 306 return YUV; 307 } else if (element.equals(Element.RGBA_8888(RenderScriptSingleton.getRS()))) { 308 return RGBA_8888; 309 } else if (element.equals(Element.U8_3(RenderScriptSingleton.getRS()))) { 310 return U8_3; 311 } else if (element.equals(Element.U8_4(RenderScriptSingleton.getRS()))) { 312 return U8_4; 313 } 314 // TODO: add more comparisons here as necessary 315 316 Log.w(TAG, "Unknown element of data kind " + element.getDataKind()); 317 return null; 318 } 319 } 320 321 /** 322 * Compare the current element against the suggested element (info). 323 * 324 * @param element The other element to compare against. 325 * 326 * @return true if the elements are equal, false otherwise. 327 */ isElementEqualTo(ElementInfo element)328 public boolean isElementEqualTo(ElementInfo element) { 329 checkNotNull("element", element); 330 331 Element comparison; 332 switch (element) { 333 case YUV: 334 comparison = Element.YUV(mRS); 335 break; 336 case RGBA_8888: 337 comparison = Element.RGBA_8888(mRS); 338 break; 339 case U8_3: 340 comparison = Element.U8_3(mRS); 341 break; 342 case U8_4: 343 comparison = Element.U8_4(mRS); 344 break; 345 default: 346 // TODO: add more comparisons here as necessary 347 comparison = null; 348 } 349 350 return mElement.equals(comparison); 351 } 352 353 /** 354 * Human-readable representation of this info. 355 */ 356 @Override toString()357 public String toString() { 358 return String.format("Size: %s, Element: %s, Usage: %x", mSize, 359 ElementInfo.fromElement(mElement), mUsage); 360 } 361 362 /** 363 * Compare against another object. 364 * 365 * <p>Comparisons against objects that are not instances of {@link AllocationInfo} 366 * always return {@code false}.</p> 367 * 368 * <p>Two {@link AllocationInfo infos} are considered equal only if their elements, 369 * sizes, and usage flags are also equal.</p> 370 * 371 * @param other Another info object 372 * 373 * @return true if this is equal to other 374 */ 375 @Override equals(Object other)376 public boolean equals(Object other) { 377 if (other instanceof AllocationInfo) { 378 return equals((AllocationInfo)other); 379 } else { 380 return false; 381 } 382 } 383 384 /** 385 * Compare against another object. 386 * 387 * <p>Two {@link AllocationInfo infos} are considered equal only if their elements, 388 * sizes, and usage flags are also equal.</p> 389 * 390 * @param other Another info object 391 * 392 * @return true if this is equal to other 393 */ equals(AllocationInfo other)394 public boolean equals(AllocationInfo other) { 395 if (other == null) { 396 return false; 397 } 398 399 // Element, Size equality is already incorporated into Type equality 400 return mType.equals(other.mType) && mUsage == other.mUsage; 401 } 402 403 /** 404 * Create a new {@link Allocation} using the {@link #getType type} and {@link #getUsage usage} 405 * from this info object. 406 * 407 * <p>The allocation is always created from a {@link AllocationCache cache}. If possible, 408 * return it to the cache once done (although this is not necessary).</p> 409 * 410 * @return a new {@link Allocation} 411 */ createAllocation()412 public Allocation createAllocation() { 413 if (VERBOSE) Log.v(TAG, "createAllocation - for info =" + toString()); 414 return RenderScriptSingleton.getCache().getOrCreateTyped(mType, mUsage); 415 } 416 417 /** 418 * Create a new {@link Allocation} using the {@link #getType type} and {@link #getUsage usage} 419 * from this info object; immediately wrap inside a new {@link BlockingInputAllocation}. 420 * 421 * <p>The allocation is always created from a {@link AllocationCache cache}. If possible, 422 * return it to the cache once done (although this is not necessary).</p> 423 * 424 * @return a new {@link Allocation} 425 * 426 * @throws IllegalArgumentException 427 * If the usage did not have one of {@code USAGE_IO_INPUT} or {@code USAGE_IO_OUTPUT} 428 */ createBlockingInputAllocation()429 public BlockingInputAllocation createBlockingInputAllocation() { 430 Allocation alloc = createAllocation(); 431 return BlockingInputAllocation.wrap(alloc); 432 } 433 typeBuilder(Element element, Size size)434 private static Type.Builder typeBuilder(Element element, Size size) { 435 Type.Builder builder = (new Type.Builder(RenderScriptSingleton.getRS(), element)) 436 .setX(size.getWidth()) 437 .setY(size.getHeight()); 438 439 return builder; 440 } 441 } 442