Home | History | Annotate | Download | only in rs
      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      */
     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      */
     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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    222     public AllocationInfo changeFormatWithDefaultUsage(int format) {
    223         return newInstance(getSize(), format, Allocation.USAGE_SCRIPT);
    224     }
    225 
    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      */
    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      */
    262     public int getUsage() {
    263         return mUsage;
    264     }
    265 
    266     /**
    267      * Get the size.
    268      *
    269      * @return The size (never {@code null}).
    270      */
    271     public Size getSize() {
    272         return mSize;
    273     }
    274 
    275     /**
    276      * Get the {@link Element}.
    277      *
    278      * @return The element (never {@code null}).
    279      */
    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          */
    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      */
    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
    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
    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      */
    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      */
    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      */
    429     public BlockingInputAllocation createBlockingInputAllocation() {
    430         Allocation alloc = createAllocation();
    431         return BlockingInputAllocation.wrap(alloc);
    432     }
    433 
    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