blob: 3324783eb47de0405047d9616cefcd5c6ae15c42 [file] [log] [blame]
/*
* Copyright 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.camera2.cts.rs;
import static android.hardware.camera2.cts.helpers.Preconditions.*;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.util.Size;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.Type;
import android.util.Log;
/**
* Abstract the information necessary to create new {@link Allocation allocations} with
* their size, element, type, and usage.
*
* <p>This also includes convenience functions for printing to a string, something RenderScript
* lacks at the time of writing.</p>
*
* <p>Note that when creating a new {@link AllocationInfo} the usage flags <b>always</b> get ORd
* to {@link Allocation#USAGE_IO_SCRIPT}.</p>
*/
public class AllocationInfo {
private final RenderScript mRS = RenderScriptSingleton.getRS();
private final Size mSize;
private final Element mElement;
private final Type mType;
private final int mUsage;
private static final String TAG = "AllocationInfo";
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
/**
* Create a new {@link AllocationInfo} holding the element, size, and usage
* from an existing {@link Allocation}.
*
* @param allocation {@link Allocation}
*
* @return A new {@link AllocationInfo}
*
* @throws NullPointerException if allocation was {@code null}.
*/
public static AllocationInfo newInstance(Allocation allocation) {
checkNotNull("allocation", allocation);
return new AllocationInfo(allocation.getElement(),
new Size(allocation.getType().getX(), allocation.getType().getY()),
allocation.getUsage());
}
/**
* Create a new {@link AllocationInfo} holding the specified format, {@link Size},
* and {@link Allocation#USAGE_SCRIPT usage}.
*
* <p>The usage is always ORd with {@link Allocation#USAGE_SCRIPT}.</p>
*
* <p>The closest {@link Element} possible is created from the format.</p>
*
* @param size {@link Size}
* @param format An int format
* @param usage Usage flags
*
* @return A new {@link AllocationInfo} holding the given arguments.
*
* @throws NullPointerException if size was {@code null}.
*
* @see ImageFormat
* @see PixelFormat
*/
public static AllocationInfo newInstance(Size size, int format, int usage) {
RenderScript rs = RenderScriptSingleton.getRS();
Element element;
switch (format) {
case ImageFormat.YUV_420_888:
element = Element.YUV(rs);
break;
case PixelFormat.RGBA_8888:
element = Element.RGBA_8888(rs);
break;
// TODO: map more formats here
default:
throw new UnsupportedOperationException("Unsupported format " + format);
}
return new AllocationInfo(element, size, usage);
}
/**
* Create a new {@link AllocationInfo} holding the specified format, {@link Size},
* with the default usage.
*
* <p>The default usage is always {@link Allocation#USAGE_SCRIPT}.</p>
*
* <p>The closest {@link Element} possible is created from the format.</p>
*
* @param size {@link Size}
* @param format An int format
*
* @return A new {@link AllocationInfo} holding the given arguments.
*
* @throws NullPointerException if size was {@code null}.
*
* @see ImageFormat
* @see PixelFormat
*/
public static AllocationInfo newInstance(Size size, int format) {
return newInstance(size, format, Allocation.USAGE_SCRIPT);
}
/**
* Create a new {@link AllocationInfo} holding the specified {@link Element}, {@link Size},
* with the default usage.
*
* <p>The default usage is always {@link Allocation#USAGE_SCRIPT}.</p>
*
* @param element {@link Element}
* @param size {@link Size}
*
* @return A new {@link AllocationInfo} holding the given arguments.
*
* @throws NullPointerException if size was {@code null}.
* @throws NullPointerException if element was {@code null}.
*/
public static AllocationInfo newInstance(Element element, Size size) {
return new AllocationInfo(element, size, Allocation.USAGE_SCRIPT);
}
/**
* Create a new {@link AllocationInfo} holding the specified {@link Element}, {@link Size},
* and {@link Allocation#USAGE_SCRIPT usage}.
*
* <p>The usage is always ORd with {@link Allocation#USAGE_SCRIPT}.</p>
*
* @param element {@link Element}
* @param size {@link Size}
* @param usage usage flags
*
* @return A new {@link AllocationInfo} holding the given arguments.
*
* @throws NullPointerException if size was {@code null}.
* @throws NullPointerException if element was {@code null}.
*/
public static AllocationInfo newInstance(Element element, Size size, int usage) {
return new AllocationInfo(element, size, usage);
}
/**
* Create a new {@link AllocationInfo} by copying the existing data but appending
* the new usage flags to the old usage flags.
*
* @param usage usage flags
*
* @return A new {@link AllocationInfo} with new usage flags ORd to the old ones.
*/
public AllocationInfo addExtraUsage(int usage) {
return new AllocationInfo(mElement, mSize, mUsage | usage);
}
/**
* Create a new {@link AllocationInfo} by copying the existing data but changing the format,
* and appending the new usage flags to the old usage flags.
*
* @param format Format
* @param usage usage flags
*
* @return A new {@link AllocationInfo} with new format/usage.
*
* @see ImageFormat
* @see PixelFormat
*/
public AllocationInfo changeFormatAndUsage(int format, int usage) {
return newInstance(getSize(), format, usage);
}
/**
* Create a new {@link AllocationInfo} by copying the existing data but replacing the old
* usage with the new usage flags.
*
* @param usage usage flags
*
* @return A new {@link AllocationInfo} with new format/usage.
*
* @see ImageFormat
* @see PixelFormat
*/
public AllocationInfo changeElementWithDefaultUsage(Element element) {
return newInstance(element, getSize());
}
/**
* Create a new {@link AllocationInfo} by copying the existing data but changing the format,
* and replacing the old usage flags with default usage flags.
*
* @param format Format
*
* @return A new {@link AllocationInfo} with new format/usage.
*
* @see ImageFormat
* @see PixelFormat
*/
public AllocationInfo changeFormatWithDefaultUsage(int format) {
return newInstance(getSize(), format, Allocation.USAGE_SCRIPT);
}
private AllocationInfo(Element element, Size size, int usage) {
checkNotNull("element", element);
checkNotNull("size", size);
mElement = element;
mSize = size;
mUsage = usage;
Type.Builder typeBuilder = typeBuilder(element, size);
if (element.equals(Element.YUV(mRS))) {
typeBuilder.setYuvFormat(ImageFormat.YUV_420_888);
}
mType = typeBuilder.create();
}
/**
* Get the {@link Type type} for this info.
*
* <p>Note that this is the same type that would get used by the {@link Allocation}
* created with {@link #createAllocation()}.
*
* @return The type (never {@code null}).
*/
public Type getType() {
return mType;
}
/**
* Get the usage.
*
* <p>The bit for {@link Allocation#USAGE_SCRIPT} will always be set to 1.</p>
*
* @return usage flags
*/
public int getUsage() {
return mUsage;
}
/**
* Get the size.
*
* @return The size (never {@code null}).
*/
public Size getSize() {
return mSize;
}
/**
* Get the {@link Element}.
*
* @return The element (never {@code null}).
*/
public Element getElement() {
return mElement;
}
/**
* Convenience enum to represent commonly-used elements without needing a RenderScript object.
*/
public enum ElementInfo {
YUV,
RGBA_8888,
U8_3,
U8_4;
private static final String TAG = "ElementInfo";
/**
* Create an {@link ElementInfo} by converting it from a {@link Element}.
*
* @param element The element for which you want to get an enum for.
*
* @return The element info is a corresponding one exists, or {@code null} otherwise.
*/
public static ElementInfo fromElement(Element element) {
checkNotNull("element", element);
if (element.equals(Element.YUV(RenderScriptSingleton.getRS()))) {
return YUV;
} else if (element.equals(Element.RGBA_8888(RenderScriptSingleton.getRS()))) {
return RGBA_8888;
} else if (element.equals(Element.U8_3(RenderScriptSingleton.getRS()))) {
return U8_3;
} else if (element.equals(Element.U8_4(RenderScriptSingleton.getRS()))) {
return U8_4;
}
// TODO: add more comparisons here as necessary
Log.w(TAG, "Unknown element of data kind " + element.getDataKind());
return null;
}
}
/**
* Compare the current element against the suggested element (info).
*
* @param element The other element to compare against.
*
* @return true if the elements are equal, false otherwise.
*/
public boolean isElementEqualTo(ElementInfo element) {
checkNotNull("element", element);
Element comparison;
switch (element) {
case YUV:
comparison = Element.YUV(mRS);
break;
case RGBA_8888:
comparison = Element.RGBA_8888(mRS);
break;
case U8_3:
comparison = Element.U8_3(mRS);
break;
case U8_4:
comparison = Element.U8_4(mRS);
break;
default:
// TODO: add more comparisons here as necessary
comparison = null;
}
return mElement.equals(comparison);
}
/**
* Human-readable representation of this info.
*/
@Override
public String toString() {
return String.format("Size: %s, Element: %s, Usage: %x", mSize,
ElementInfo.fromElement(mElement), mUsage);
}
/**
* Compare against another object.
*
* <p>Comparisons against objects that are not instances of {@link AllocationInfo}
* always return {@code false}.</p>
*
* <p>Two {@link AllocationInfo infos} are considered equal only if their elements,
* sizes, and usage flags are also equal.</p>
*
* @param other Another info object
*
* @return true if this is equal to other
*/
@Override
public boolean equals(Object other) {
if (other instanceof AllocationInfo) {
return equals((AllocationInfo)other);
} else {
return false;
}
}
/**
* Compare against another object.
*
* <p>Two {@link AllocationInfo infos} are considered equal only if their elements,
* sizes, and usage flags are also equal.</p>
*
* @param other Another info object
*
* @return true if this is equal to other
*/
public boolean equals(AllocationInfo other) {
if (other == null) {
return false;
}
// Element, Size equality is already incorporated into Type equality
return mType.equals(other.mType) && mUsage == other.mUsage;
}
/**
* Create a new {@link Allocation} using the {@link #getType type} and {@link #getUsage usage}
* from this info object.
*
* <p>The allocation is always created from a {@link AllocationCache cache}. If possible,
* return it to the cache once done (although this is not necessary).</p>
*
* @return a new {@link Allocation}
*/
public Allocation createAllocation() {
if (VERBOSE) Log.v(TAG, "createAllocation - for info =" + toString());
return RenderScriptSingleton.getCache().getOrCreateTyped(mType, mUsage);
}
/**
* Create a new {@link Allocation} using the {@link #getType type} and {@link #getUsage usage}
* from this info object; immediately wrap inside a new {@link BlockingInputAllocation}.
*
* <p>The allocation is always created from a {@link AllocationCache cache}. If possible,
* return it to the cache once done (although this is not necessary).</p>
*
* @return a new {@link Allocation}
*
* @throws IllegalArgumentException
* If the usage did not have one of {@code USAGE_IO_INPUT} or {@code USAGE_IO_OUTPUT}
*/
public BlockingInputAllocation createBlockingInputAllocation() {
Allocation alloc = createAllocation();
return BlockingInputAllocation.wrap(alloc);
}
private static Type.Builder typeBuilder(Element element, Size size) {
Type.Builder builder = (new Type.Builder(RenderScriptSingleton.getRS(), element))
.setX(size.getWidth())
.setY(size.getHeight());
return builder;
}
}