diff --git a/Android.mk b/Android.mk index 373fbfc..565ddf1 100644 --- a/Android.mk +++ b/Android.mk @@ -1,4 +1,5 @@ #Enables the listed display HAL modules display-hals := libhwcomposer liboverlay libgralloc libgenlock libcopybit libtilerenderer +display-hals += libqcomui include $(call all-named-subdir-makefiles,$(display-hals)) diff --git a/liboverlay/overlayLib.cpp b/liboverlay/overlayLib.cpp index 5245fc2..6f2c604 100755 --- a/liboverlay/overlayLib.cpp +++ b/liboverlay/overlayLib.cpp @@ -256,8 +256,21 @@ bool overlay::enableBarrier (unsigned int orientation) { int overlay::getColorFormat(int format) { - return (format == HAL_PIXEL_FORMAT_YV12) ? - format : COLOR_FORMAT(format); + if (format == HAL_PIXEL_FORMAT_YV12) + return format; + else if (format & INTERLACE_MASK) + return format ^ HAL_PIXEL_FORMAT_INTERLACE; + else + return COLOR_FORMAT(format); +} + +bool overlay::isInterlacedContent(int format) +{ + if ((format != HAL_PIXEL_FORMAT_YV12) && + (format & INTERLACE_MASK)) + return true; + + return false; } unsigned int overlay::getOverlayConfig (unsigned int format3D, bool poll, @@ -970,8 +983,8 @@ bool OverlayControlChannel::setOverlayInformation(const overlay_buffer_info& inf mOVInfo.z_order = zorder; mOVInfo.alpha = 0xff; mOVInfo.transp_mask = 0xffffffff; - mOVInfo.flags = flags; } + mOVInfo.flags = flags; if (!ignoreFB) mOVInfo.flags |= MDP_OV_PLAY_NOWAIT; else @@ -1051,7 +1064,9 @@ bool OverlayControlChannel::updateOverlaySource(const overlay_buffer_info& info, ovBufInfo.height = info.height; ovBufInfo.format = hw_format; - if (!setOverlayInformation(ovBufInfo, 0, orientation, 0, waitForVsync, UPDATE_REQUEST)) + int flags = isInterlacedContent(info.format) ? MDP_DEINTERLACE : 0; + if (!setOverlayInformation(ovBufInfo, flags, orientation, 0, waitForVsync, + UPDATE_REQUEST)) return false; return startOVRotatorSessions(ovBufInfo, orientation, UPDATE_REQUEST); @@ -1072,7 +1087,7 @@ bool OverlayControlChannel::startControlChannel(int w, int h, int colorFormat = format; // The interlace mask is part of the HAL_PIXEL_FORMAT_YV12 value. Add // an explicit check for the format - if ((format != HAL_PIXEL_FORMAT_YV12) && (format & INTERLACE_MASK)) { + if (isInterlacedContent(format)) { flags |= MDP_DEINTERLACE; // Get the actual format diff --git a/liboverlay/overlayLib.h b/liboverlay/overlayLib.h index 0a502ea..1448f83 100755 --- a/liboverlay/overlayLib.h +++ b/liboverlay/overlayLib.h @@ -144,6 +144,7 @@ bool enableBarrier(unsigned int orientation); unsigned int getOverlayConfig (unsigned int format3D, bool poll = true, bool isHDMI = false); int getColorFormat(int format); +bool isInterlacedContent(int format); int get_mdp_format(int format); int get_size(int format, int w, int h); int get_rot_output_format(int format); diff --git a/libqcomui/Android.mk b/libqcomui/Android.mk new file mode 100644 index 0000000..2b786d9 --- /dev/null +++ b/libqcomui/Android.mk @@ -0,0 +1,17 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + qcom_ui.cpp + +LOCAL_SHARED_LIBRARIES := \ + libutils \ + libcutils \ + libmemalloc \ + libui + +LOCAL_C_INCLUDES := $(TOP)/hardware/qcom/display/libgralloc \ +LOCAL_CFLAGS := -DLOG_TAG=\"libQcomUI\" +LOCAL_MODULE := libQcomUI +LOCAL_MODULE_TAGS := optional +include $(BUILD_SHARED_LIBRARY) diff --git a/libqcomui/qcom_ui.cpp b/libqcomui/qcom_ui.cpp new file mode 100644 index 0000000..9de00e7 --- /dev/null +++ b/libqcomui/qcom_ui.cpp @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +using gralloc::IMemAlloc; +using gralloc::IonController; +using gralloc::alloc_data; +using android::sp; + +namespace { + + static android::sp sAlloc = 0; + + int reallocate_memory(native_handle_t *buffer_handle, int mReqSize, int usage) + { + int ret = 0; + if (sAlloc == 0) { + sAlloc = gralloc::IAllocController::getInstance(true); + } + if (sAlloc == 0) { + LOGE("sAlloc is still NULL"); + return -EINVAL; + } + + // Dealloc the old memory + private_handle_t *hnd = (private_handle_t *)buffer_handle; + sp memalloc = sAlloc->getAllocator(hnd->flags); + ret = memalloc->free_buffer((void*)hnd->base, hnd->size, hnd->offset, hnd->fd); + + if (ret) { + LOGE("%s: free_buffer failed", __FUNCTION__); + return -1; + } + + // Realloc new memory + alloc_data data; + data.base = 0; + data.fd = -1; + data.offset = 0; + data.size = mReqSize; + data.align = getpagesize(); + data.uncached = true; + int allocFlags = usage; + + switch (hnd->format) { + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: + case (HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED^HAL_PIXEL_FORMAT_INTERLACE): { + data.align = 8192; + } break; + default: break; + } + ret = sAlloc->allocate(data, allocFlags, 0); + if (ret == 0) { + hnd->fd = data.fd; + hnd->base = (int)data.base; + hnd->offset = data.offset; + hnd->size = data.size; + } else { + LOGE("%s: allocate failed", __FUNCTION__); + return -EINVAL; + } + return ret; + } +}; // ANONYNMOUS NAMESPACE + +/* + * Gets the number of arguments required for this operation. + * + * @param: operation whose argument count is required. + * + * @return -EINVAL if the operation is invalid. + */ +int getNumberOfArgsForOperation(int operation) { + int num_args = -EINVAL; + switch(operation) { + case NATIVE_WINDOW_SET_BUFFERS_SIZE: + num_args = 1; + break; + case NATIVE_WINDOW_UPDATE_BUFFERS_GEOMETRY: + num_args = 3; + break; + default: LOGE("%s: invalid operation(0x%x)", __FUNCTION__, operation); + break; + }; + return num_args; +} + +/* + * Checks if the format is supported by the GPU. + * + * @param: format to check + * + * @return true if the format is supported by the GPU. + */ +bool isGPUSupportedFormat(int format) { + bool isSupportedFormat = true; + switch(format) { + case (HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED^HAL_PIXEL_FORMAT_INTERLACE): + case (HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED|HAL_3D_OUT_SIDE_BY_SIDE + |HAL_3D_IN_SIDE_BY_SIDE_R_L): + case (HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED|HAL_3D_OUT_SIDE_BY_SIDE + |HAL_3D_IN_SIDE_BY_SIDE_L_R): + isSupportedFormat = false; + break; + default: break; + } + return isSupportedFormat; +} + +/* + * Function to check if the allocated buffer is of the correct size. + * Reallocate the buffer with the correct size, if the size doesn't + * match + * + * @param: handle of the allocated buffer + * @param: requested size for the buffer + * @param: usage flags + * + * return 0 on success + */ +int checkBuffer(native_handle_t *buffer_handle, int size, int usage) +{ + // If the client hasn't set a size, return + if (0 == size) { + return 0; + } + + // Validate the handle + if (private_handle_t::validate(buffer_handle)) { + LOGE("%s: handle is invalid", __FUNCTION__); + return -EINVAL; + } + + // Obtain the private_handle from the native handle + private_handle_t *hnd = reinterpret_cast(buffer_handle); + if (hnd->size < size) { + return reallocate_memory(hnd, size, usage); + } + + return 0; +} + +/* + * Checks if memory needs to be reallocated for this buffer. + * + * @param: Geometry of the current buffer. + * @param: Required Geometry. + * @param: Geometry of the updated buffer. + * + * @return True if a memory reallocation is required. + */ +bool needNewBuffer(const qBufGeometry currentGeometry, + const qBufGeometry requiredGeometry, + const qBufGeometry updatedGeometry) +{ + // If the current buffer info matches the updated info, + // we do not require any memory allocation. + if (updatedGeometry.width && updatedGeometry.height && + updatedGeometry.format) { + return false; + } + if (currentGeometry.width != requiredGeometry.width || + currentGeometry.height != requiredGeometry.height || + currentGeometry.format != requiredGeometry.format) { + // Current and required geometry do not match. Allocation + // required. + return true; + } + return false; +} + +/* + * Update the geometry of this buffer without reallocation. + * + * @param: buffer whose geometry needs to be updated. + * @param: Updated width + * @param: Updated height + * @param: Updated format + */ +int updateBufferGeometry(sp buffer, const qBufGeometry updatedGeometry) +{ + if (buffer == 0) { + LOGE("%s: graphic buffer is NULL", __FUNCTION__); + return -EINVAL; + } + + if (!updatedGeometry.width || !updatedGeometry.height || + !updatedGeometry.format) { + // No update required. Return. + return 0; + } + if (buffer->width == updatedGeometry.width && + buffer->height == updatedGeometry.height && + buffer->format == updatedGeometry.format) { + // The buffer has already been updated. Return. + return 0; + } + + // Validate the handle + if (private_handle_t::validate(buffer->handle)) { + LOGE("%s: handle is invalid", __FUNCTION__); + return -EINVAL; + } + buffer->width = updatedGeometry.width; + buffer->height = updatedGeometry.height; + buffer->format = updatedGeometry.format; + private_handle_t *hnd = (private_handle_t*)(buffer->handle); + if (hnd) { + hnd->width = updatedGeometry.width; + hnd->height = updatedGeometry.height; + hnd->format = updatedGeometry.format; + } else { + LOGE("%s: hnd is NULL", __FUNCTION__); + return -EINVAL; + } + + return 0; +} + +/* + * Updates the flags for the layer + * + * @param: Attribute + * @param: Identifies if the attribute was enabled or disabled. + * + * @return: -EINVAL if the attribute is invalid + */ +int updateLayerQcomFlags(eLayerAttrib attribute, bool enable, int& currentFlags) +{ + int ret = 0; + switch (attribute) { + case LAYER_UPDATE_STATUS: { + if (enable) + currentFlags |= LAYER_UPDATING; + else + currentFlags &= ~LAYER_UPDATING; + } break; + default: LOGE("%s: invalid attribute(0x%x)", __FUNCTION__, attribute); + break; + } + return ret; +} + +/* + * Gets the per frame HWC flags for this layer. + * + * @param: current hwcl flags + * @param: current layerFlags + * + * @return: the per frame flags. + */ +int getPerFrameFlags(int hwclFlags, int layerFlags) { + int flags = hwclFlags; + if (layerFlags & LAYER_UPDATING) + flags &= ~HWC_LAYER_NOT_UPDATING; + else + flags |= HWC_LAYER_NOT_UPDATING; + + return flags; +} + diff --git a/libqcomui/qcom_ui.h b/libqcomui/qcom_ui.h new file mode 100644 index 0000000..6744edf --- /dev/null +++ b/libqcomui/qcom_ui.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef INCLUDE_LIBQCOM_UI +#define INCLUDE_LIBQCOM_UI + +#include +#include + +using android::sp; +using android::GraphicBuffer; + +/* + * Qcom specific Native Window perform operations + */ +enum { + NATIVE_WINDOW_SET_BUFFERS_SIZE = 0x10000000, + NATIVE_WINDOW_UPDATE_BUFFERS_GEOMETRY = 0x20000000, +}; + +/* + * Layer Attributes + */ +enum eLayerAttrib { + LAYER_UPDATE_STATUS, +}; + +/* + * Layer Flags + */ +enum { + LAYER_UPDATING = 1<<0, +}; + +/* + * Flags set by the layer and sent to HWC + */ +enum { + HWC_LAYER_NOT_UPDATING = 0x00000002, + HWC_USE_ORIGINAL_RESOLUTION = 0x10000000, + HWC_DO_NOT_USE_OVERLAY = 0x20000000, + HWC_COMP_BYPASS = 0x40000000, +}; + +/* + * Structure to hold the buffer geometry + */ +struct qBufGeometry { + int width; + int height; + int format; + void set(int w, int h, int f) { + width = w; + height = h; + format = f; + } +}; + +/* + * Function to check if the allocated buffer is of the correct size. + * Reallocate the buffer with the correct size, if the size doesn't + * match + * + * @param: handle of the allocated buffer + * @param: requested size for the buffer + * @param: usage flags + * + * return 0 on success + */ +int checkBuffer(native_handle_t *buffer_handle, int size, int usage); + +/* + * Checks if the format is supported by the GPU. + * + * @param: format to check + * + * @return true if the format is supported by the GPU. + */ +bool isGPUSupportedFormat(int format); + +/* + * Gets the number of arguments required for this operation. + * + * @param: operation whose argument count is required. + * + * @return -EINVAL if the operation is invalid. + */ +int getNumberOfArgsForOperation(int operation); + +/* + * Checks if memory needs to be reallocated for this buffer. + * + * @param: Geometry of the current buffer. + * @param: Required Geometry. + * @param: Geometry of the updated buffer. + * + * @return True if a memory reallocation is required. + */ +bool needNewBuffer(const qBufGeometry currentGeometry, + const qBufGeometry requiredGeometry, + const qBufGeometry updatedGeometry); + +/* + * Update the geometry of this buffer without reallocation. + * + * @param: buffer whose geometry needs to be updated. + * @param: Updated buffer geometry + */ +int updateBufferGeometry(sp buffer, const qBufGeometry bufGeometry); + +/* + * Updates the flags for the layer + * + * @param: Attribute + * @param: Identifies if the attribute was enabled or disabled. + * @param: current Layer flags. + * + * @return: Flags for the layer + */ +int updateLayerQcomFlags(eLayerAttrib attribute, bool enable, int& currentFlags); + +/* + * Gets the per frame HWC flags for this layer. + * + * @param: current hwcl flags + * @param: current layerFlags + * + * @return: the per frame flags. + */ +int getPerFrameFlags(int hwclFlags, int layerFlags); + +#endif // INCLUDE_LIBQCOM_UI