diff --git a/Android.mk b/Android.mk index 127a6de..73024a0 100644 --- a/Android.mk +++ b/Android.mk @@ -1,11 +1,9 @@ #Enables the listed display HAL modules -#Libs to be built for all targets (including SDK) display-hals := libqcomui - #libs to be built for QCOM targets only #ifeq ($(call is-vendor-board-platform,QCOM),true) -display-hals += libgralloc libgenlock libcopybit +display-hals += libgralloc libgenlock libcopybit libhwcomposer liboverlay #endif include $(call all-named-subdir-makefiles,$(display-hals)) diff --git a/libcopybit/Android.mk b/libcopybit/Android.mk new file mode 100644 index 0000000..24663b7 --- /dev/null +++ b/libcopybit/Android.mk @@ -0,0 +1,59 @@ +# Copyright (C) 2008 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. + + +LOCAL_PATH:= $(call my-dir) +# HAL module implemenation, not prelinked and stored in +# hw/..so + +ifeq ($(TARGET_USES_C2D_COMPOSITION),true) + include $(CLEAR_VARS) + LOCAL_PRELINK_MODULE := false + LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw + LOCAL_SHARED_LIBRARIES := liblog libdl libcutils libmemalloc libutils + LOCAL_SRC_FILES := copybit_c2d.cpp software_converter.cpp + LOCAL_MODULE := copybit.$(TARGET_BOARD_PLATFORM) + LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc + LOCAL_CFLAGS += -DCOPYBIT_Z180=1 -DC2D_SUPPORT_DISPLAY=1 + LOCAL_MODULE_TAGS := optional + include $(BUILD_SHARED_LIBRARY) +else + ifneq ($(call is-chipset-in-board-platform,msm7630),true) + ifeq ($(call is-board-platform-in-list,$(MSM7K_BOARD_PLATFORMS)),true) + include $(CLEAR_VARS) + ifeq ($(ARCH_ARM_HAVE_NEON),true) + LOCAL_CFLAGS += -D__ARM_HAVE_NEON + endif + ifeq ($(call is-board-platform,msm7627a),true) + LOCAL_CFLAGS += -DTARGET_7x27A + endif + ifeq ($(TARGET_GRALLOC_USES_ASHMEM),true) + LOCAL_CFLAGS += -DUSE_ASHMEM + ifeq ($(call is-chipset-prefix-in-board-platform,msm7627),true) + LOCAL_CFLAGS += -DTARGET_7x27 + endif + endif + + LOCAL_PRELINK_MODULE := false + LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw + LOCAL_SHARED_LIBRARIES := liblog libmemalloc + LOCAL_SRC_FILES := software_converter.cpp copybit.cpp + LOCAL_MODULE := copybit.$(TARGET_BOARD_PLATFORM) + LOCAL_MODULE_TAGS := optional + LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/qcom/display/libgralloc + LOCAL_CFLAGS += -DCOPYBIT_MSM7K=1 + include $(BUILD_SHARED_LIBRARY) + endif + endif +endif diff --git a/libcopybit/MODULE_LICENSE_APACHE2 b/libcopybit/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 diff --git a/libcopybit/NOTICE b/libcopybit/NOTICE new file mode 100644 index 0000000..9c1e63a --- /dev/null +++ b/libcopybit/NOTICE @@ -0,0 +1,189 @@ + + Copyright (c) 2008, 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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/libcopybit/c2d2.h b/libcopybit/c2d2.h new file mode 100644 index 0000000..8c7d05b --- /dev/null +++ b/libcopybit/c2d2.h @@ -0,0 +1,618 @@ +/* Copyright (c) 2010-2012, 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 __c2d2_h_ +#define __c2d2_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef C2D_API +#define C2D_API /* define API export as needed */ +#endif +#if !defined(int32) && !defined(_INT32_DEFINED) +typedef int int32; +#define _INT32_DEFINED +#endif +#if !defined(uint32) && !defined(_UINT32_DEFINED) +typedef unsigned int uint32; +#define _UINT32_DEFINED +#endif + +/*****************************************************************************/ +/*********************** Blit definitions *****************************/ +/*****************************************************************************/ + +/* Status codes, returned by any blit function */ +typedef enum { + C2D_STATUS_OK = 0, + C2D_STATUS_NOT_SUPPORTED = 1, + C2D_STATUS_OUT_OF_MEMORY = 2, + C2D_STATUS_INVALID_PARAM = 3, + C2D_STATUS_SURFACE_IN_USE = 4, +} C2D_STATUS; + + +/* Definitions of color format modes, used together with color formats */ +typedef enum { + C2D_FORMAT_PACK_INTO_32BIT = (1 << 8), /* pack into dword if set */ + C2D_FORMAT_SWAP_ENDIANNESS = (1 << 9), /* swaps the order */ + C2D_FORMAT_LINEAR_SPACE = (1 << 10), /* linear color space */ + C2D_FORMAT_PREMULTIPLIED = (1 << 11), /* alpha premultiplied */ + C2D_FORMAT_INVERT_ALPHA = (1 << 12), /* inverts alpha */ + C2D_FORMAT_DISABLE_ALPHA = (1 << 13), /* disables alpha */ + C2D_FORMAT_INTERLACED = (1 << 14), /* YUV line-interlaced */ + C2D_FORMAT_TRANSPARENT = (1 << 15), /* YUV 1-bit alpha in Y */ + C2D_FORMAT_MACROTILED = (1 << 16), /* tiled in macro level */ + C2D_FORMAT_TILED_4x4 = (1 << 17), /* 4x4 tiled format */ + C2D_FORMAT_SWAP_RB = (1 << 18), /* Swap R & B color components */ +} C2D_FORMAT_MODE; + +/* Definitions of supported RGB formats, used in C2D_RGB_SURFACE_DEF. + * The bits of each color channel are packed into a machine word + * representing a single pixel from left to right (MSB to LSB) in the + * order indicated by format name. For the sub-byte formats the pixels + * are packed into bytes from left to right (MSbit to LSBit). + * If the C2D_FORMAT_PACK_INTO_32BIT bit is set, the minimal + * machine word used for pixel storage is 32-bit and the whole word + * is reversed if endianness is swapped. + * If the C2D_FORMAT_SWAP_ENDIANNESS bit is set, the order within a + * minimal machine word representing a pixel + * is reversed for both sub-byte and multi-byte formats. + * If the C2D_FORMAT_LINEAR_SPACE bit is set, the color space of + * the formats below is considered linear, if applicable. + * If the C2D_FORMAT_PREMULTIPLIED bit is set, the color channels + * are premultiplied with the alpha, if applicable. + * If the C2D_FORMAT_INVERT_ALPHA bit is set, the alpha interpretation + * is inverted: 0 - opaque, 1 - transparent, if applicable. + * If the C2D_FORMAT_DISABLE_ALPHA bit is set, the alpha channel serves + * as a placeholder and is ignored during blit, if applicable. + * If the C2D_FORMAT_MACROTILED bit is set, the surface is in the + * tiled format : 64x32 for 8bpp, 32x32 for 16bpp formats */ +typedef enum { + C2D_COLOR_FORMAT_1 = 0, /* 1-bit alpha/color expansion */ + + C2D_COLOR_FORMAT_2_PALETTE = 1, /* 2-bit indices for palette */ + C2D_COLOR_FORMAT_4_PALETTE = 2, /* 4-bit indices for palette */ + C2D_COLOR_FORMAT_8_PALETTE = 3, /* 8-bit indices for palette */ + + C2D_COLOR_FORMAT_2_L = 4, /* 2-bit grayscale */ + C2D_COLOR_FORMAT_4_L = 5, /* 4-bit grayscale */ + C2D_COLOR_FORMAT_8_L = 6, /* 8-bit grayscale */ + + C2D_COLOR_FORMAT_2_A = 7, /* 2-bit alpha only */ + C2D_COLOR_FORMAT_4_A = 8, /* 4-bit alpha only */ + C2D_COLOR_FORMAT_8_A = 9, /* 8-bit alpha only */ + + C2D_COLOR_FORMAT_444_RGB = 10, /* 12-bit colors */ + C2D_COLOR_FORMAT_565_RGB = 11, /* 16-bit colors */ + C2D_COLOR_FORMAT_888_RGB = 12, /* 24-bit colors */ + + C2D_COLOR_FORMAT_1555_ARGB = 13, /* 16-bit colors (1-bit alpha) */ + C2D_COLOR_FORMAT_4444_ARGB = 14, /* 16-bit colors (4-bit alpha) */ + C2D_COLOR_FORMAT_8565_ARGB = 15, /* 24-bit colors (8-bit alpha) */ + C2D_COLOR_FORMAT_8888_ARGB = 16, /* 32-bit colors (8-bit alpha) */ + + C2D_COLOR_FORMAT_5551_RGBA = 17, /* 16-bit colors (1-bit alpha) */ + C2D_COLOR_FORMAT_4444_RGBA = 18, /* 16-bit colors (4-bit alpha) */ + C2D_COLOR_FORMAT_5658_RGBA = 19, /* 24-bit colors (8-bit alpha) */ + C2D_COLOR_FORMAT_8888_RGBA = 20, /* 32-bit colors (8-bit alpha) */ + + /* derived RGB color formats (base format + mode bits) */ + +} C2D_RGB_FORMAT; + +/* Definitions of supported YUV formats, used in C2D_YUV_SURFACE_DEF. + * Each of Y,U,V channels usually takes 1 byte and therefore is + * individually addressable. The definitions below show how Y,U,V + * channels are packed into macropixels for each particular format. + * The order is from left (smaller byte addresses) to right (larger + * byte addresses). The first three digits (4xx) denote the chroma + * subsampling in standard YUV notation. The digits in the macropixel + * denote that the whole block (from the previous digit or from the + * beginning) has to be repeated the number of times. Underscores + * between Y,U,V channels are used to describe separate planes for + * planar YUV formats. Formats are mapped to numbers so that future + * versions with various YUV permutations are easy to add. + * If the C2D_FORMAT_INTERLACED bit is set, the line order is + * interlaced: 0,2,4,...1,3,5... if applicable. + * If the C2D_FORMAT_TRANSPARENT bit is set, the least significant + * bit of Y channel serves as alpha: 0 - transparent, 1 - opaque. */ +typedef enum { + C2D_COLOR_FORMAT_411_YYUYYV = 110, /* packed, 12-bit */ + C2D_COLOR_FORMAT_411_YUYYVY = 111, /* packed, 12-bit */ + C2D_COLOR_FORMAT_411_UYYVYY = 112, /* packed, 12-bit, "Y411" */ + C2D_COLOR_FORMAT_411_YUYV2Y4 = 116, /* packed, 12-bit */ + C2D_COLOR_FORMAT_411_UYVY2Y4 = 117, /* packed, 12-bit, "Y41P" */ + + C2D_COLOR_FORMAT_422_YUYV = 120, /* packed, 16-bit, "YUY2" */ + C2D_COLOR_FORMAT_422_UYVY = 121, /* packed, 16-bit, "UYVY" */ + C2D_COLOR_FORMAT_422_YVYU = 122, /* packed, 16-bit, "YVYU" */ + C2D_COLOR_FORMAT_422_VYUY = 123, /* packed, 16-bit */ + + C2D_COLOR_FORMAT_444_YUV = 130, /* packed, 24-bit */ + C2D_COLOR_FORMAT_444_UYV = 131, /* packed, 24-bit, "IYU2" */ + C2D_COLOR_FORMAT_444_AYUV = 136, /* packed, 24-bit, "AYUV" */ + + C2D_COLOR_FORMAT_410_Y_UV = 150, /* planar, Y + interleaved UV */ + C2D_COLOR_FORMAT_411_Y_UV = 151, /* planar, Y + interleaved UV */ + C2D_COLOR_FORMAT_420_Y_UV = 152, /* planar, Y + interleaved UV */ + C2D_COLOR_FORMAT_422_Y_UV = 153, /* planar, Y + interleaved UV */ + C2D_COLOR_FORMAT_444_Y_UV = 154, /* planar, Y + interleaved UV */ + + C2D_COLOR_FORMAT_410_Y_VU = 160, /* planar, Y + interleaved VU */ + C2D_COLOR_FORMAT_411_Y_VU = 161, /* planar, Y + interleaved VU */ + C2D_COLOR_FORMAT_420_Y_VU = 162, /* planar, Y + interleaved VU */ + C2D_COLOR_FORMAT_422_Y_VU = 163, /* planar, Y + interleaved VU */ + C2D_COLOR_FORMAT_444_Y_VU = 164, /* planar, Y + interleaved VU */ + + C2D_COLOR_FORMAT_410_Y_U_V = 170, /* planar, Y + U + V separate */ + C2D_COLOR_FORMAT_411_Y_U_V = 171, /* planar, Y + U + V separate */ + C2D_COLOR_FORMAT_420_Y_V_U = 172, /* planar, Y + V + U separate */ + C2D_COLOR_FORMAT_420_Y_U_V = 173, /* planar, Y + U + V separate */ + C2D_COLOR_FORMAT_422_Y_U_V = 174, /* planar, Y + U + V separate */ + C2D_COLOR_FORMAT_444_Y_U_V = 175, /* planar, Y + U + V separate */ + + C2D_COLOR_FORMAT_800_Y = 190, /* planar, Y only, grayscale */ + + /* derived YUV color formats (base format + mode bits), FOURCC */ + + C2D_COLOR_FORMAT_411_Y411 = 112, + C2D_COLOR_FORMAT_411_Y41P = 117, + C2D_COLOR_FORMAT_411_IY41 = 117 | (1 << 14), + C2D_COLOR_FORMAT_411_Y41T = 117 | (1 << 15), + + C2D_COLOR_FORMAT_422_YUY2 = 120, + C2D_COLOR_FORMAT_422_IUYV = 121 | (1 << 14), + C2D_COLOR_FORMAT_422_Y42T = 121 | (1 << 15), + C2D_COLOR_FORMAT_444_IYU2 = 131, + + C2D_COLOR_FORMAT_420_NV12 = 152, + C2D_COLOR_FORMAT_420_NV21 = 162, + + C2D_COLOR_FORMAT_410_YUV9 = 170, + C2D_COLOR_FORMAT_410_YVU9 = 170, + C2D_COLOR_FORMAT_411_Y41B = 171, + C2D_COLOR_FORMAT_420_YV12 = 172, + C2D_COLOR_FORMAT_420_IYUV = 173, + C2D_COLOR_FORMAT_420_I420 = 173, + C2D_COLOR_FORMAT_422_YV16 = 174, + C2D_COLOR_FORMAT_422_Y42B = 174, + + C2D_COLOR_FORMAT_800_Y800 = 190, + +} C2D_YUV_FORMAT; + + +/* Configuration bits, used in the config_mask field of C2D_OBJECT struct */ +typedef enum { + C2D_SOURCE_RECT_BIT = (1 << 0), /* enables source_rect field */ + C2D_MIRROR_H_BIT = (1 << 1), /* enables horizontal flipping */ + C2D_MIRROR_V_BIT = (1 << 2), /* enables vertical flipping */ + C2D_SOURCE_TILE_BIT = (1 << 3), /* enables source surface tiling */ + C2D_TARGET_RECT_BIT = (1 << 4), /* enables target_rect field */ + C2D_ROTATE_BIT = (1 << 5), /* enables all rotation fields */ + C2D_SCISSOR_RECT_BIT = (1 << 6), /* enables scissor_rect field */ + C2D_MASK_SURFACE_BIT = (1 << 7), /* enables mask_surface_id field */ + C2D_MASK_ALIGN_BIT = (1 << 8), /* aligns mask to source_rect */ + C2D_MASK_SCALE_BIT = (1 << 9), /* enables mask surface scaling */ + C2D_MASK_TILE_BIT = (1 << 10), /* enables mask surface tiling */ + C2D_GLOBAL_ALPHA_BIT = (1 << 11), /* enables global_alpha field */ + C2D_COLOR_KEY_BIT = (1 << 12), /* enables color_key field */ + C2D_NO_PIXEL_ALPHA_BIT = (1 << 13), /* disables source alpha channel */ + C2D_NO_BILINEAR_BIT = (1 << 14), /* disables bilinear on scaling */ + C2D_NO_ANTIALIASING_BIT = (1 << 15), /* disables antialiasing on edges */ + C2D_DRAW_LINE_BIT = (1 << 16), /* enables line drawing with source rectangle */ + C2D_DRAW_LINE_NOLAST = (1 << 17), /* disable last pixel draw for line */ +} C2D_SOURCE_CONFIG; + +/* Target configuration bits, defines rotation + mirroring. + * Mirror is applied prior to rotation if enabled. */ +typedef enum { + C2D_TARGET_MIRROR_H = (1 << 0), /* horizontal flip */ + C2D_TARGET_MIRROR_V = (1 << 1), /* vertical flip */ + C2D_TARGET_ROTATE_0 = (0 << 2), /* no rotation */ + C2D_TARGET_ROTATE_90 = (1 << 2), /* 90 degree rotation */ + C2D_TARGET_ROTATE_180 = (2 << 2), /* 180 degree rotation */ + C2D_TARGET_ROTATE_270 = (3 << 2), /* 270 degree rotation, 90 + 180 */ + C2D_TARGET_MASK_ALIGN = (1 << 4), /* aligns mask to target scissor */ + C2D_TARGET_MASK_SCALE = (1 << 5), /* enables mask scaling */ + C2D_TARGET_MASK_TILE = (1 << 6), /* enables mask tiling */ + C2D_TARGET_COLOR_KEY = (1 << 7), /* enables target_color_key */ + C2D_TARGET_NO_PIXEL_ALPHA = (1 << 8), /* disables target alpha channel */ +} C2D_TARGET_CONFIG; + +#define C2D_TARGET_ROTATION_MASK (C2D_TARGET_ROTATE_90*3) + +/* Additional blend modes, can be used with both source and target configs. + If none of the below is set, the default "SRC over DST" is applied. */ +typedef enum { + C2D_ALPHA_BLEND_SRC_OVER = (0 << 20), /* Default, Porter-Duff "SRC over DST" */ + C2D_ALPHA_BLEND_SRC = (1 << 20), /* Porter-Duff "SRC" */ + C2D_ALPHA_BLEND_SRC_IN = (2 << 20), /* Porter-Duff "SRC in DST" */ + C2D_ALPHA_BLEND_DST_IN = (3 << 20), /* Porter-Duff "DST in SRC" */ + C2D_ALPHA_BLEND_SRC_OUT = (4 << 20), /* Porter-Duff "SRC out DST" */ + C2D_ALPHA_BLEND_DST_OUT = (5 << 20), /* Porter-Duff "DST out SRC" */ + C2D_ALPHA_BLEND_DST_OVER = (6 << 20), /* Porter-Duff "DST over SRC" */ + C2D_ALPHA_BLEND_SRC_ATOP = (7 << 20), /* Porter-Duff "SRC ATOP" */ + C2D_ALPHA_BLEND_DST_ATOP = (8 << 20), /* Porter-Duff "DST ATOP" */ + C2D_ALPHA_BLEND_XOR = (9 << 20), /* Xor */ + C2D_ALPHA_BLEND_MULTIPLY = (10 << 20), /* OpenVG "MULTIPLY" */ + C2D_ALPHA_BLEND_SCREEN = (11 << 20), /* OpenVG "SCREEN" */ + C2D_ALPHA_BLEND_DARKEN = (12 << 20), /* OpenVG "DARKEN" */ + C2D_ALPHA_BLEND_LIGHTEN = (13 << 20), /* OpenVG "LIGHTEN" */ + C2D_ALPHA_BLEND_ADDITIVE = (14 << 20), /* OpenVG "ADDITIVE" */ + C2D_ALPHA_BLEND_DIRECT = (15 << 20), /* Direct alpha blitting */ + C2D_ALPHA_BLEND_INVERTC = (16 << 20), /* Invert color */ + C2D_ALPHA_BLEND_NONE = (1 << 25), /* disables alpha blending */ +} C2D_ALPHA_BLEND_MODE; + + +/* Surface caps enumeration */ +typedef enum { + C2D_SOURCE = (1 << 0), /* allows to use as a source */ + C2D_TARGET = (1 << 1), /* allows to use as a target */ + C2D_MASK = (1 << 2), /* allows to use as a mask */ + C2D_PALETTE = (1 << 3), /* allows to use as a palette */ +} C2D_SURFACE_BITS; + +/* Surface type enumeration */ +typedef enum { + C2D_SURFACE_RGB_HOST = 1, /* Host memory RGB surface */ + C2D_SURFACE_RGB_EXT = 2, /* External memory RGB surface */ + C2D_SURFACE_YUV_HOST = 3, /* Host memory YUV surface */ + C2D_SURFACE_YUV_EXT = 4, /* External memory YUV surface */ + C2D_SURFACE_WITH_PHYS = (1<<3), /* physical address already mapped */ + /* this bit is valid with HOST types */ + C2D_SURFACE_WITH_PHYS_DUMMY = (1<<4), /* physical address already mapped */ + /* this bit is valid with HOST types */ +} C2D_SURFACE_TYPE; + +/* Structure for registering a RGB buffer as a blit surface */ +typedef struct { + uint32 format; /* RGB color format plus additional mode bits */ + uint32 width; /* defines width in pixels */ + uint32 height; /* defines height in pixels */ + void *buffer; /* pointer to the RGB buffer */ + void *phys; /* physical address */ + int32 stride; /* defines stride in bytes, negative stride is allowed */ +} C2D_RGB_SURFACE_DEF; + +/* Structure for registering a YUV plane(s) as a blit surface */ +typedef struct { + uint32 format; /* YUV color format plus additional mode bits */ + uint32 width; /* defines width in pixels */ + uint32 height; /* defines height in pixels */ + void *plane0; /* holds the whole buffer if YUV format is not planar */ + void *phys0; /* physical address */ + int32 stride0; /* stride in bytes if YUV format is not planar */ + void *plane1; /* holds UV or VU plane for planar interleaved */ + void *phys1; /* physical address */ + int32 stride1; /* stride for UV or VU plane for planar interleaved */ + void *plane2; /* holds the 3. plane, ignored if YUV format is not planar */ + void *phys2; /* physical address */ + int32 stride2; /* stride for the 3. plane, ignored if YUV format is not planar */ +} C2D_YUV_SURFACE_DEF; + + +/* Rectangle definition */ +typedef struct { + int32 x; /* upper-left x */ + int32 y; /* upper-left y */ + int32 width; /* width */ + int32 height; /* height */ +} C2D_RECT; + +/* C2D_OBJECT encapsulates the blit parameters for a source surface. + * The fg_color defines color in target format for bits equal to 1 + * in the source C2D_COLOR_FORMAT_1 format. It also defines rendering + * color for all alpha-only source formats. If the surface_id is 0 + * the fg_color defines a constant fill color used instead of the surface. + * The bg_color defines color in target format for bits equal to 0 + * in the source C2D_COLOR_FORMAT_1 format, otherwise both are ignored. + * The palette_id is used for all palette source formats, otherwise ignored. + + * The source_rect first defines the content of the source surface, + * it is then horizontally/vertically flipped if C2D_MIRROR_*_BIT is set, + * then scaled with bilinear interpolation to exactly fit target_rect + * or repeated across target_rect if C2D_SOURCE_TILE_BIT is set, + * target_rect is then rotated clockwise by an arbitrary angle in degrees + * around the rot_orig_x/y, defined relative to target_rect's top left point, + * and then clipped to scissor_rect defined in target coordinate system. + + * Finally alpha blending is applied before pixels get written into the target. + * Surface's pixel alpha is combined with mask alpha and with global alpha. + * Mask surface follows all transformations applied to the source surface. + * Source color key defines transparent color, applied together with alpha. */ +typedef struct C2D_OBJECT_STR { + uint32 surface_id; /* source surface */ + + uint32 fg_color; /* foreground color */ + uint32 bg_color; /* background color */ + uint32 palette_id; /* one-dimensional horizontal palette surface */ + + uint32 config_mask; /* defines which fields below are enabled */ + + C2D_RECT source_rect; /* region of the source surface, 16.16 fp */ + C2D_RECT target_rect; /* position and scaling in target, 16.16 fp */ + + int32 rot_orig_x; /* rotation origin relative to target_rect's... */ + int32 rot_orig_y; /* ...top left point, both are 16.16 fp */ + int32 rotation; /* clock-wise rotation in degrees, 16.16 fp */ + + C2D_RECT scissor_rect; /* defines the clip rectangle in target surface */ + + uint32 mask_surface_id; /* source alpha-mask surface */ + uint32 global_alpha; /* 0 = fully transparent, 255 = fully opaque */ + uint32 color_key; /* transparent color for the source surface */ + + struct C2D_OBJECT_STR *next; /* pointer to the next object or NULL */ +} C2D_OBJECT; + + +/*****************************************************************************/ +/**************************** C2D API 2.0 ********************************/ +/*****************************************************************************/ + +/****************************************************************************** + * Functions to create/destroy surfaces */ + +/* Creates a generic blit surface according to its type. + * Pass a combination of desired surface bits according to planned usage. + * Accepted values for surface_bits may include bits from C2D_SURFACE_BITS, + * and also from C2D_DISPLAY for compatibility with HW display controller. + * For host memory types the memory is preallocated outside the API + * and should remain valid until surface is destroyed. + * For external memory types the memory is allocated within API. + * On success, the non-zero surface identifier is returned. + * All numbers greater that 0 are valid surface identifiers, 0 is invalid. + + * Host memory RGB surface: + * surface_type = C2D_SURFACE_RGB_HOST + * surface_definition = C2D_RGB_SURFACE_DEF + * all fields in definition structure should be set + + * External memory RGB surface: + * surface_type = C2D_SURFACE_RGB_EXT + * surface_definition = C2D_RGB_SURFACE_DEF + * buffer field in definition structure is ignored + + * Host memory YUV surface: + * surface_type = C2D_SURFACE_YUV_HOST + * surface_definition = C2D_YUV_SURFACE_DEF + * one or all plane and stride fields in definition structure + * should be set depending on whether the format is planar or not + + * External memory YUV surface: + * surface_type = C2D_SURFACE_YUV_EXT + * surface_definition = C2D_YUV_SURFACE_DEF + * all plane and stride fields in definition structure are ignored */ +C2D_API C2D_STATUS c2dCreateSurface( uint32 *surface_id, + uint32 surface_bits, + C2D_SURFACE_TYPE surface_type, + void *surface_definition ); + +/* Requests properties of the specified surface. */ +C2D_API C2D_STATUS c2dQuerySurface( uint32 surface_id, + uint32 *surface_bits, + C2D_SURFACE_TYPE *surface_type, + uint32 *width, uint32 *height, + uint32 *format ); + +/* Destroys a generic blit surface. + * For external memory surfaces also deallocates the memory. + * It is safe to free any external resources associated with a given + * surface on c2dCreateSurface call after this function returns. */ +C2D_API C2D_STATUS c2dDestroySurface( uint32 surface_id ); + + +/****************************************************************************** + * Functions to modify/exchange surface data */ + +/* The format of fill_color is the same as color format being used + * for specified surface. If fill_rect is NULL the whole surface is filled. + * Alpha-blending is not performed while filling. + * The operation is complete when function returns. */ +C2D_API C2D_STATUS c2dFillSurface( uint32 surface_id, + uint32 fill_color, + C2D_RECT *fill_rect ); + +/* Writes data located in host memory into the specified surface. + * The chunk of host memory is identified with surface_type and + * surface_definition, no surface registration needed in this case. + * Only C2D_SURFACE_RGB_HOST, C2D_SURFACE_YUV_HOST are accepted. + * If only part of the host memory buffer should be loaded, it should + * be configured in surface_definition using width, height and stride. + * The x and y are defined in target surface coordinate space. + * Color conversion has to be done, if color formats differ. + * Alpha-blending is not performed while writing. + * The operation is complete when function returns. */ +C2D_API C2D_STATUS c2dWriteSurface( uint32 surface_id, + C2D_SURFACE_TYPE surface_type, + void *surface_definition, + int32 x, int32 y ); + +/* Reads data from the specified surface into the host memory. + * The chunk of host memory is identified with surface_type and + * surface_definition, no surface registration needed in this case. + * Only C2D_SURFACE_RGB_HOST, C2D_SURFACE_YUV_HOST are accepted. + * If only part of the surface should be read, it should + * be configured in surface_definition using width, height and stride. + * The x and y are defined in source surface coordinate space. + * Color conversion has to be done, if color formats differ. + * Alpha-blending is not performed while reading. + * The operation is complete when function returns. */ +C2D_API C2D_STATUS c2dReadSurface( uint32 surface_id, + C2D_SURFACE_TYPE surface_type, + void *surface_definition, + int32 x, int32 y ); + +/* Notifies c2d imlementation that surface has been updated from outside the API, + * if updated_rect is NULL then the whole surface has been updated. */ +C2D_API C2D_STATUS c2dSurfaceUpdated( uint32 surface_id, + C2D_RECT *updated_rect ); + +/* Updates surface information. + * Could be called only for host surfaces set with parameter "C2D_SURFACE_WITH_PHYS". + * Count for surface planes have to be same than for already allocated surface */ +C2D_API C2D_STATUS c2dUpdateSurface( uint32 surface_id, + uint32 surface_bits, + C2D_SURFACE_TYPE surface_type, + void *surface_definition ); + +/****************************************************************************** + * Functions to do actual blit */ + +/* Draw a list of blit objects into the given target. + * The target_config is a bitwise OR of values from C2D_TARGET_CONFIG. + * The target transformation creates the effect that target surface + * is transformed before the blit and then transformed back + * after blit, however no physical target transform is performed. + * The objects_list is a linked list of blit objects, no more + * than num_objects is drawn from the given list. + * If num_objects is 0, the whole list is drawn. + * The blit is not guaranteed to complete after function returns. */ +C2D_API C2D_STATUS c2dDraw( uint32 target_id, + uint32 target_config, C2D_RECT *target_scissor, + uint32 target_mask_id, uint32 target_color_key, + C2D_OBJECT *objects_list, uint32 num_objects ); + + +/* timstamp set in the blit commands flush */ +typedef void* c2d_ts_handle; + +/* Forces any pending blit to complete for a given target. + * Non-blocking. All input surfaces for this target except those + * which are shared with other targets are expected to be immediately + * writable after client has been waiting returned timestamp with + * c2dWaitTimestamp funtion or c2dFinish has been called for same target */ +C2D_API C2D_STATUS c2dFlush( uint32 target_id, c2d_ts_handle *timestamp); + + +/* Waits the pending timestamp */ +C2D_API C2D_STATUS c2dWaitTimestamp( c2d_ts_handle timestamp ); + + +/* Forces any pending blit to complete for a given target. + * Blocking version, returns when blit is done. + * All input surfaces for this target except those which are shared with + * other targets are expected to be immediately + * writable after this function returns. */ +C2D_API C2D_STATUS c2dFinish( uint32 target_id ); + + +/*****************************************************************************/ +/****************************** Display API **********************************/ +/*****************************************************************************/ + + +/* Display input enumeration */ +typedef enum { + C2D_DISPLAY_INPUT_0 = 0, /*!< default input */ + C2D_DISPLAY_INPUT_1 = (1<<16), /*!< Overlay 1 */ + C2D_DISPLAY_INPUT_2 = (1<<17), /*!< Overlay 2... */ +} C2D_DISPLAY_INPUT; + + +/****************************************************************************** + * Functions for display output. */ + +/* Functionality described in this section is optional and is + * provided only for the cases when blit HW + * is tightly bound to the display controller. */ + +/* Display enumeration, may also be used in surface caps */ +typedef enum { + C2D_DISPLAY_MAIN = (1 << 10), /* main display */ + C2D_DISPLAY_SECONDARY = (1 << 11), /* secondary display */ + C2D_DISPLAY_TV_OUT = (1 << 12), /* tv-out */ +} C2D_DISPLAY; + +/* Display window enumeration */ +typedef enum { + C2D_DISPLAY_OVERLAY = C2D_DISPLAY_INPUT_1, /*!< Overlay window bit. This defines display input. + When defined the surface is set on the overlay window + otherwise the surface is set on the background window. */ +} C2D_DISPLAY_WINDOW; /*!< Window bit set with display parameter */ + + +/* Display update modes */ +typedef enum { + C2D_DISPLAY_MODE_TEAR_SYNC = (1 << 0), /* enables tearing sync */ + C2D_DISPLAY_MODE_SURF_REMOVE = (1 << 1), /* Remove surface from given display + input */ +} C2D_DISPLAY_MODE; + + +/* Sets the given surface as a current display front buffer. + * Several displays can be specified as an output if supported. + * Still only one input can be specified at a time fro display/displays. + * The surface remains shown until it gets replaced with another one. */ +C2D_API C2D_STATUS c2dDisplaySetSurface( uint32 display, + uint32 surface_id, uint32 mode ); + +/* Returns the current surface for a particular display. + * Only one display can be specified at a time. + * The latest surface set with compDisplaySetSurface or + * the default pre-allocated surface is returned. */ +C2D_API C2D_STATUS c2dDisplayGetSurface( uint32 display, + uint32 *surface_id ); + +/* Returns the properties for a particular display. + * Only one display can be specified at a time. */ +C2D_API C2D_STATUS c2dDisplayGetProperties( uint32 display, + uint32 *width, uint32 *height, + uint32 *format ); + +/* Sets the properties for a particular display input. + * Only one display + input can be specified at a time. + * C2D_OBJECT used to set input rect(target rect), + * blending operations, rotation...etc for display source */ +C2D_API C2D_STATUS c2dDisplaySetObject( uint32 display, + uint32 target_config, uint32 target_color_key, + C2D_OBJECT * c2dObject, uint32 mode); + +/* allows user to map a memory region to the gpu. only supported on linux + * mem_fd is the fd of the memory region, hostptr is the host pointer to the region, + * len and offset are the size and offset of the memory. + * flags is one of the memory types supported by gsl + * gpaddr is passed by refernce back to the user + */ +C2D_API C2D_STATUS c2dMapAddr ( int mem_fd, void * hostptr, uint32 len, uint32 offset, uint32 flags, void ** gpuaddr); + +/* allows user to unmap memory region mapped by c2dMapAddr. + * gpaddr is the gpuaddr to unmap */ +C2D_API C2D_STATUS c2dUnMapAddr (void * gpuaddr); + +/*****************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* __c2d2_h_ */ diff --git a/libcopybit/copybit.cpp b/libcopybit/copybit.cpp new file mode 100644 index 0000000..886d12b --- /dev/null +++ b/libcopybit/copybit.cpp @@ -0,0 +1,553 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * Copyright (c) 2010 - 2011, Code Aurora Forum. All rights reserved. + * + * 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. + */ + + +#define LOG_TAG "copybit" + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "gralloc_priv.h" +#include "software_converter.h" + +#define DEBUG_MDP_ERRORS 1 + +/******************************************************************************/ + +#if defined(COPYBIT_MSM7K) +#define MAX_SCALE_FACTOR (4) +#define MAX_DIMENSION (4096) +#elif defined(COPYBIT_QSD8K) +#define MAX_SCALE_FACTOR (8) +#define MAX_DIMENSION (2048) +#else +#error "Unsupported MDP version" +#endif + +/******************************************************************************/ + +/** State information for each device instance */ +struct copybit_context_t { + struct copybit_device_t device; + int mFD; + uint8_t mAlpha; + int mFlags; +}; + +/** + * Common hardware methods + */ + +static int open_copybit(const struct hw_module_t* module, const char* name, + struct hw_device_t** device); + +static struct hw_module_methods_t copybit_module_methods = { +open: open_copybit +}; + +/* + * The COPYBIT Module + */ +struct copybit_module_t HAL_MODULE_INFO_SYM = { +common: { +tag: HARDWARE_MODULE_TAG, + version_major: 1, + version_minor: 0, + id: COPYBIT_HARDWARE_MODULE_ID, + name: "QCT MSM7K COPYBIT Module", + author: "Google, Inc.", + methods: ©bit_module_methods + } +}; + +/******************************************************************************/ + +/** min of int a, b */ +static inline int min(int a, int b) { + return (ab) ? a : b; +} + +/** scale each parameter by mul/div. Assume div isn't 0 */ +static inline void MULDIV(uint32_t *a, uint32_t *b, int mul, int div) { + if (mul != div) { + *a = (mul * *a) / div; + *b = (mul * *b) / div; + } +} + +/** Determine the intersection of lhs & rhs store in out */ +static void intersect(struct copybit_rect_t *out, + const struct copybit_rect_t *lhs, + const struct copybit_rect_t *rhs) { + out->l = max(lhs->l, rhs->l); + out->t = max(lhs->t, rhs->t); + out->r = min(lhs->r, rhs->r); + out->b = min(lhs->b, rhs->b); +} + +/** convert COPYBIT_FORMAT to MDP format */ +static int get_format(int format) { + switch (format) { + case HAL_PIXEL_FORMAT_RGB_565: return MDP_RGB_565; + case HAL_PIXEL_FORMAT_RGBX_8888: return MDP_RGBX_8888; + case HAL_PIXEL_FORMAT_RGB_888: return MDP_RGB_888; + case HAL_PIXEL_FORMAT_RGBA_8888: return MDP_RGBA_8888; + case HAL_PIXEL_FORMAT_BGRA_8888: return MDP_BGRA_8888; + case HAL_PIXEL_FORMAT_YCrCb_422_SP: return MDP_Y_CBCR_H2V1; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: return MDP_Y_CBCR_H2V2; + case HAL_PIXEL_FORMAT_YCbCr_422_SP: return MDP_Y_CRCB_H2V1; + case HAL_PIXEL_FORMAT_YCbCr_420_SP: return MDP_Y_CRCB_H2V2; + case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: return MDP_Y_CBCR_H2V2_ADRENO; + } + return -1; +} + +/** convert from copybit image to mdp image structure */ +static void set_image(struct mdp_img *img, const struct copybit_image_t *rhs) +{ + private_handle_t* hnd = (private_handle_t*)rhs->handle; + if(hnd == NULL){ + ALOGE("copybit: Invalid handle"); + return; + } + img->width = rhs->w; + img->height = rhs->h; + img->format = get_format(rhs->format); + img->offset = hnd->offset; + img->memory_id = hnd->fd; +} +/** setup rectangles */ +static void set_rects(struct copybit_context_t *dev, + struct mdp_blit_req *e, + const struct copybit_rect_t *dst, + const struct copybit_rect_t *src, + const struct copybit_rect_t *scissor, + uint32_t horiz_padding, + uint32_t vert_padding) { + struct copybit_rect_t clip; + intersect(&clip, scissor, dst); + + e->dst_rect.x = clip.l; + e->dst_rect.y = clip.t; + e->dst_rect.w = clip.r - clip.l; + e->dst_rect.h = clip.b - clip.t; + + uint32_t W, H, delta_x, delta_y; + if (dev->mFlags & COPYBIT_TRANSFORM_ROT_90) { + delta_x = (clip.t - dst->t); + delta_y = (dst->r - clip.r); + e->src_rect.w = (clip.b - clip.t); + e->src_rect.h = (clip.r - clip.l); + W = dst->b - dst->t; + H = dst->r - dst->l; + } else { + delta_x = (clip.l - dst->l); + delta_y = (clip.t - dst->t); + e->src_rect.w = (clip.r - clip.l); + e->src_rect.h = (clip.b - clip.t); + W = dst->r - dst->l; + H = dst->b - dst->t; + } + + MULDIV(&delta_x, &e->src_rect.w, src->r - src->l, W); + MULDIV(&delta_y, &e->src_rect.h, src->b - src->t, H); + + e->src_rect.x = delta_x + src->l; + e->src_rect.y = delta_y + src->t; + + if (dev->mFlags & COPYBIT_TRANSFORM_FLIP_V) { + if (dev->mFlags & COPYBIT_TRANSFORM_ROT_90) { + e->src_rect.x = (src->l + src->r) - (e->src_rect.x + e->src_rect.w); + }else{ + e->src_rect.y = (src->t + src->b) - (e->src_rect.y + e->src_rect.h); + } + } + + if (dev->mFlags & COPYBIT_TRANSFORM_FLIP_H) { + if (dev->mFlags & COPYBIT_TRANSFORM_ROT_90) { + e->src_rect.y = (src->t + src->b) - (e->src_rect.y + e->src_rect.h); + }else{ + e->src_rect.x = (src->l + src->r) - (e->src_rect.x + e->src_rect.w); + } + } +} + +/** setup mdp request */ +static void set_infos(struct copybit_context_t *dev, + struct mdp_blit_req *req, int flags) +{ + req->alpha = dev->mAlpha; + req->transp_mask = MDP_TRANSP_NOP; + req->flags = dev->mFlags | flags; +#if defined(COPYBIT_QSD8K) + req->flags |= MDP_BLEND_FG_PREMULT; +#endif +} + +/** copy the bits */ +static int msm_copybit(struct copybit_context_t *dev, void const *list) +{ + int err = ioctl(dev->mFD, MSMFB_BLIT, + (struct mdp_blit_req_list const*)list); + ALOGE_IF(err<0, "copyBits failed (%s)", strerror(errno)); + if (err == 0) { + return 0; + } else { +#if DEBUG_MDP_ERRORS + struct mdp_blit_req_list const* l = + (struct mdp_blit_req_list const*)list; + for (int i=0 ; icount ; i++) { + ALOGE("%d: src={w=%d, h=%d, f=%d, rect={%d,%d,%d,%d}}\n" + " dst={w=%d, h=%d, f=%d, rect={%d,%d,%d,%d}}\n" + " flags=%08lx" + , + i, + l->req[i].src.width, + l->req[i].src.height, + l->req[i].src.format, + l->req[i].src_rect.x, + l->req[i].src_rect.y, + l->req[i].src_rect.w, + l->req[i].src_rect.h, + l->req[i].dst.width, + l->req[i].dst.height, + l->req[i].dst.format, + l->req[i].dst_rect.x, + l->req[i].dst_rect.y, + l->req[i].dst_rect.w, + l->req[i].dst_rect.h, + l->req[i].flags + ); + } +#endif + return -errno; + } +} + +/*****************************************************************************/ + +/** Set a parameter to value */ +static int set_parameter_copybit( + struct copybit_device_t *dev, + int name, + int value) +{ + struct copybit_context_t* ctx = (struct copybit_context_t*)dev; + int status = 0; + if (ctx) { + switch(name) { + case COPYBIT_ROTATION_DEG: + switch (value) { + case 0: + ctx->mFlags &= ~0x7; + break; + case 90: + ctx->mFlags &= ~0x7; + ctx->mFlags |= MDP_ROT_90; + break; + case 180: + ctx->mFlags &= ~0x7; + ctx->mFlags |= MDP_ROT_180; + break; + case 270: + ctx->mFlags &= ~0x7; + ctx->mFlags |= MDP_ROT_270; + break; + default: + ALOGE("Invalid value for COPYBIT_ROTATION_DEG"); + status = -EINVAL; + break; + } + break; + case COPYBIT_PLANE_ALPHA: + if (value < 0) value = MDP_ALPHA_NOP; + if (value >= 256) value = 255; + ctx->mAlpha = value; + break; + case COPYBIT_DITHER: + if (value == COPYBIT_ENABLE) { + ctx->mFlags |= MDP_DITHER; + } else if (value == COPYBIT_DISABLE) { + ctx->mFlags &= ~MDP_DITHER; + } + break; + case COPYBIT_BLUR: + if (value == COPYBIT_ENABLE) { + ctx->mFlags |= MDP_BLUR; + } else if (value == COPYBIT_DISABLE) { + ctx->mFlags &= ~MDP_BLUR; + } + break; + case COPYBIT_PREMULTIPLIED_ALPHA: + if(value == COPYBIT_ENABLE) { + ctx->mFlags |= MDP_BLEND_FG_PREMULT; + } else if (value == COPYBIT_DISABLE) { + ctx->mFlags &= ~MDP_BLEND_FG_PREMULT; + } + break; + case COPYBIT_TRANSFORM: + ctx->mFlags &= ~0x7; + ctx->mFlags |= value & 0x7; + break; + default: + status = -EINVAL; + break; + } + } else { + status = -EINVAL; + } + return status; +} + +/** Get a static info value */ +static int get(struct copybit_device_t *dev, int name) +{ + struct copybit_context_t* ctx = (struct copybit_context_t*)dev; + int value; + if (ctx) { + switch(name) { + case COPYBIT_MINIFICATION_LIMIT: + value = MAX_SCALE_FACTOR; + break; + case COPYBIT_MAGNIFICATION_LIMIT: + value = MAX_SCALE_FACTOR; + break; + case COPYBIT_SCALING_FRAC_BITS: + value = 32; + break; + case COPYBIT_ROTATION_STEP_DEG: + value = 90; + break; + default: + value = -EINVAL; + } + } else { + value = -EINVAL; + } + return value; +} + +/** do a stretch blit type operation */ +static int stretch_copybit( + struct copybit_device_t *dev, + struct copybit_image_t const *dst, + struct copybit_image_t const *src, + struct copybit_rect_t const *dst_rect, + struct copybit_rect_t const *src_rect, + struct copybit_region_t const *region) +{ + struct copybit_context_t* ctx = (struct copybit_context_t*)dev; + int status = 0; + private_handle_t *yv12_handle = NULL; + if (ctx) { + struct { + uint32_t count; + struct mdp_blit_req req[12]; + } list; + + if (ctx->mAlpha < 255) { + switch (src->format) { + // we don't support plane alpha with RGBA formats + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: + ALOGE ("%s : Unsupported Pixel format %d", __FUNCTION__, + src->format); + return -EINVAL; + } + } + + if (src_rect->l < 0 || src_rect->r > src->w || + src_rect->t < 0 || src_rect->b > src->h) { + // this is always invalid + ALOGE ("%s : Invalid source rectangle : src_rect l %d t %d r %d b %d",\ + __FUNCTION__, src_rect->l, src_rect->t, src_rect->r, src_rect->b); + + return -EINVAL; + } + + if (src->w > MAX_DIMENSION || src->h > MAX_DIMENSION) { + ALOGE ("%s : Invalid source dimensions w %d h %d", __FUNCTION__, src->w, src->h); + return -EINVAL; + } + + if (dst->w > MAX_DIMENSION || dst->h > MAX_DIMENSION) { + ALOGE ("%s : Invalid DST dimensions w %d h %d", __FUNCTION__, dst->w, dst->h); + return -EINVAL; + } + + if(src->format == HAL_PIXEL_FORMAT_YV12) { + int usage = GRALLOC_USAGE_PRIVATE_ADSP_HEAP | + GRALLOC_USAGE_PRIVATE_MM_HEAP; + if (0 == alloc_buffer(&yv12_handle,src->w,src->h, + src->format, usage)){ + if(0 == convertYV12toYCrCb420SP(src,yv12_handle)){ + (const_cast(src))->format = + HAL_PIXEL_FORMAT_YCrCb_420_SP; + (const_cast(src))->handle = + yv12_handle; + (const_cast(src))->base = + (void *)yv12_handle->base; + } + else{ + ALOGE("Error copybit conversion from yv12 failed"); + if(yv12_handle) + free_buffer(yv12_handle); + return -EINVAL; + } + } + else{ + ALOGE("Error:unable to allocate memeory for yv12 software conversion"); + return -EINVAL; + } + } + const uint32_t maxCount = sizeof(list.req)/sizeof(list.req[0]); + const struct copybit_rect_t bounds = { 0, 0, dst->w, dst->h }; + struct copybit_rect_t clip; + list.count = 0; + status = 0; + while ((status == 0) && region->next(region, &clip)) { + intersect(&clip, &bounds, &clip); + mdp_blit_req* req = &list.req[list.count]; + int flags = 0; + + private_handle_t* src_hnd = (private_handle_t*)src->handle; + if(src_hnd != NULL && src_hnd->flags & private_handle_t::PRIV_FLAGS_DO_NOT_FLUSH) { + flags |= MDP_BLIT_NON_CACHED; + } + + set_infos(ctx, req, flags); + set_image(&req->dst, dst); + set_image(&req->src, src); + set_rects(ctx, req, dst_rect, src_rect, &clip, src->horiz_padding, src->vert_padding); + + if (req->src_rect.w<=0 || req->src_rect.h<=0) + continue; + + if (req->dst_rect.w<=0 || req->dst_rect.h<=0) + continue; + + if (++list.count == maxCount) { + status = msm_copybit(ctx, &list); + list.count = 0; + } + } + if ((status == 0) && list.count) { + status = msm_copybit(ctx, &list); + } + } else { + ALOGE ("%s : Invalid COPYBIT context", __FUNCTION__); + status = -EINVAL; + } + if(yv12_handle) + free_buffer(yv12_handle); + return status; +} + +/** Perform a blit type operation */ +static int blit_copybit( + struct copybit_device_t *dev, + struct copybit_image_t const *dst, + struct copybit_image_t const *src, + struct copybit_region_t const *region) +{ + struct copybit_rect_t dr = { 0, 0, dst->w, dst->h }; + struct copybit_rect_t sr = { 0, 0, src->w, src->h }; + return stretch_copybit(dev, dst, src, &dr, &sr, region); +} + +/*****************************************************************************/ + +/** Close the copybit device */ +static int close_copybit(struct hw_device_t *dev) +{ + struct copybit_context_t* ctx = (struct copybit_context_t*)dev; + if (ctx) { + close(ctx->mFD); + free(ctx); + } + return 0; +} + +/** Open a new instance of a copybit device using name */ +static int open_copybit(const struct hw_module_t* module, const char* name, + struct hw_device_t** device) +{ + int status = -EINVAL; + copybit_context_t *ctx; + ctx = (copybit_context_t *)malloc(sizeof(copybit_context_t)); + memset(ctx, 0, sizeof(*ctx)); + + ctx->device.common.tag = HARDWARE_DEVICE_TAG; + ctx->device.common.version = 1; + ctx->device.common.module = const_cast(module); + ctx->device.common.close = close_copybit; + ctx->device.set_parameter = set_parameter_copybit; + ctx->device.get = get; + ctx->device.blit = blit_copybit; + ctx->device.stretch = stretch_copybit; + ctx->mAlpha = MDP_ALPHA_NOP; + ctx->mFlags = 0; + ctx->mFD = open("/dev/graphics/fb0", O_RDWR, 0); + if (ctx->mFD < 0) { + status = errno; + ALOGE("Error opening frame buffer errno=%d (%s)", + status, strerror(status)); + status = -status; + } else { + struct fb_fix_screeninfo finfo; + if (ioctl(ctx->mFD, FBIOGET_FSCREENINFO, &finfo) == 0) { + if (strncmp(finfo.id, "msmfb", 5) == 0) { + /* Success */ + status = 0; + } else { + ALOGE("Error not msm frame buffer"); + status = -EINVAL; + } + } else { + ALOGE("Error executing ioctl for screen info"); + status = -errno; + } + } + + if (status == 0) { + *device = &ctx->device.common; + } else { + close_copybit(&ctx->device.common); + } + return status; +} diff --git a/libcopybit/copybit.h b/libcopybit/copybit.h new file mode 100644 index 0000000..6384dfe --- /dev/null +++ b/libcopybit/copybit.h @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2008 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. + */ + +#ifndef ANDROID_COPYBIT_INTERFACE_H +#define ANDROID_COPYBIT_INTERFACE_H + +#include + +#include +#include +#include + +__BEGIN_DECLS + +/** + * The id of this module + */ +#define COPYBIT_HARDWARE_MODULE_ID "copybit" + +/** + * Name of the graphics device to open + */ +#define COPYBIT_HARDWARE_COPYBIT0 "copybit0" + +/* supported pixel-formats. these must be compatible with + * graphics/PixelFormat.java, ui/PixelFormat.h, pixelflinger/format.h + */ +enum { + COPYBIT_FORMAT_RGBA_8888 = HAL_PIXEL_FORMAT_RGBA_8888, + COPYBIT_FORMAT_RGBX_8888 = HAL_PIXEL_FORMAT_RGBX_8888, + COPYBIT_FORMAT_RGB_888 = HAL_PIXEL_FORMAT_RGB_888, + COPYBIT_FORMAT_RGB_565 = HAL_PIXEL_FORMAT_RGB_565, + COPYBIT_FORMAT_BGRA_8888 = HAL_PIXEL_FORMAT_BGRA_8888, + COPYBIT_FORMAT_RGBA_5551 = HAL_PIXEL_FORMAT_RGBA_5551, + COPYBIT_FORMAT_RGBA_4444 = HAL_PIXEL_FORMAT_RGBA_4444, + COPYBIT_FORMAT_YCbCr_422_SP = 0x10, + COPYBIT_FORMAT_YCrCb_420_SP = 0x11, +}; + +/* name for copybit_set_parameter */ +enum { + /* rotation of the source image in degrees (0 to 359) */ + COPYBIT_ROTATION_DEG = 1, + /* plane alpha value */ + COPYBIT_PLANE_ALPHA = 2, + /* enable or disable dithering */ + COPYBIT_DITHER = 3, + /* transformation applied (this is a superset of COPYBIT_ROTATION_DEG) */ + COPYBIT_TRANSFORM = 4, + /* blurs the copied bitmap. The amount of blurring cannot be changed + * at this time. */ + COPYBIT_BLUR = 5, + /* Informs the copybit that the source and destination contains + premultiplied alpha */ + COPYBIT_PREMULTIPLIED_ALPHA = 6, + /* FB width */ + COPYBIT_FRAMEBUFFER_WIDTH = 7, + /* FB height */ + COPYBIT_FRAMEBUFFER_HEIGHT = 8, +}; + +/* values for copybit_set_parameter(COPYBIT_TRANSFORM) */ +enum { + /* flip source image horizontally */ + COPYBIT_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H, + /* flip source image vertically */ + COPYBIT_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V, + /* rotate source image 90 degres */ + COPYBIT_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90, + /* rotate source image 180 degres */ + COPYBIT_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180, + /* rotate source image 270 degres */ + COPYBIT_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270, +}; + +/* enable/disable value copybit_set_parameter */ +enum { + COPYBIT_DISABLE = 0, + COPYBIT_ENABLE = 1 +}; + +/* use get_static_info() to query static informations about the hardware */ +enum { + /* Maximum amount of minification supported by the hardware*/ + COPYBIT_MINIFICATION_LIMIT = 1, + /* Maximum amount of magnification supported by the hardware */ + COPYBIT_MAGNIFICATION_LIMIT = 2, + /* Number of fractional bits support by the scaling engine */ + COPYBIT_SCALING_FRAC_BITS = 3, + /* Supported rotation step in degres. */ + COPYBIT_ROTATION_STEP_DEG = 4, +}; + +/* Image structure */ +struct copybit_image_t { + /* width */ + uint32_t w; + /* height */ + uint32_t h; + /* format COPYBIT_FORMAT_xxx */ + int32_t format; + /* base of buffer with image */ + void *base; + /* handle to the image */ + native_handle_t* handle; + /* number of pixels added for the stride */ + uint32_t horiz_padding; + /* number of pixels added for the vertical stride */ + uint32_t vert_padding; +}; + +/* Rectangle */ +struct copybit_rect_t { + /* left */ + int l; + /* top */ + int t; + /* right */ + int r; + /* bottom */ + int b; +}; + +/* Region */ +struct copybit_region_t { + int (*next)(struct copybit_region_t const *region, struct copybit_rect_t *rect); +}; + +/** + * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM + * and the fields of this data structure must begin with hw_module_t + * followed by module specific information. + */ +struct copybit_module_t { + struct hw_module_t common; +}; + +/** + * Every device data structure must begin with hw_device_t + * followed by module specific public methods and attributes. + */ +struct copybit_device_t { + struct hw_device_t common; + + /** + * Set a copybit parameter. + * + * @param dev from open + * @param name one for the COPYBIT_NAME_xxx + * @param value one of the COPYBIT_VALUE_xxx + * + * @return 0 if successful + */ + int (*set_parameter)(struct copybit_device_t *dev, int name, int value); + + /** + * Get a static copybit information. + * + * @param dev from open + * @param name one of the COPYBIT_STATIC_xxx + * + * @return value or -EINVAL if error + */ + int (*get)(struct copybit_device_t *dev, int name); + + /** + * Execute the bit blit copy operation + * + * @param dev from open + * @param dst is the destination image + * @param src is the source image + * @param region the clip region + * + * @return 0 if successful + */ + int (*blit)(struct copybit_device_t *dev, + struct copybit_image_t const *dst, + struct copybit_image_t const *src, + struct copybit_region_t const *region); + + /** + * Execute the stretch bit blit copy operation + * + * @param dev from open + * @param dst is the destination image + * @param src is the source image + * @param dst_rect is the destination rectangle + * @param src_rect is the source rectangle + * @param region the clip region + * + * @return 0 if successful + */ + int (*stretch)(struct copybit_device_t *dev, + struct copybit_image_t const *dst, + struct copybit_image_t const *src, + struct copybit_rect_t const *dst_rect, + struct copybit_rect_t const *src_rect, + struct copybit_region_t const *region); +}; + + +/** convenience API for opening and closing a device */ + +static inline int copybit_open(const struct hw_module_t* module, + struct copybit_device_t** device) { + return module->methods->open(module, + COPYBIT_HARDWARE_COPYBIT0, (struct hw_device_t**)device); +} + +static inline int copybit_close(struct copybit_device_t* device) { + return device->common.close(&device->common); +} + + +__END_DECLS + +#endif // ANDROID_COPYBIT_INTERFACE_H diff --git a/libcopybit/copybit_c2d.cpp b/libcopybit/copybit_c2d.cpp new file mode 100644 index 0000000..72aa279 --- /dev/null +++ b/libcopybit/copybit_c2d.cpp @@ -0,0 +1,1477 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. + * + * 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. + */ + +#define LOG_TAG "copybit_c2d" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "c2d2.h" +#include "software_converter.h" + +#include + +using gralloc::IMemAlloc; +using gralloc::IonController; +using gralloc::alloc_data; +using android::sp; + +C2D_STATUS (*LINK_c2dCreateSurface)( uint32 *surface_id, + uint32 surface_bits, + C2D_SURFACE_TYPE surface_type, + void *surface_definition ); + +C2D_STATUS (*LINK_c2dUpdateSurface)( uint32 surface_id, + uint32 surface_bits, + C2D_SURFACE_TYPE surface_type, + void *surface_definition ); + +C2D_STATUS (*LINK_c2dReadSurface)( uint32 surface_id, + C2D_SURFACE_TYPE surface_type, + void *surface_definition, + int32 x, int32 y ); + +C2D_STATUS (*LINK_c2dDraw)( uint32 target_id, + uint32 target_config, C2D_RECT *target_scissor, + uint32 target_mask_id, uint32 target_color_key, + C2D_OBJECT *objects_list, uint32 num_objects ); + +C2D_STATUS (*LINK_c2dFinish)( uint32 target_id); + +C2D_STATUS (*LINK_c2dFlush)( uint32 target_id, c2d_ts_handle *timestamp); + +C2D_STATUS (*LINK_c2dWaitTimestamp)( c2d_ts_handle timestamp ); + +C2D_STATUS (*LINK_c2dDestroySurface)( uint32 surface_id ); + +C2D_STATUS (*LINK_c2dMapAddr) ( int mem_fd, void * hostptr, uint32 len, uint32 offset, uint32 flags, void ** gpuaddr); + +C2D_STATUS (*LINK_c2dUnMapAddr) ( void * gpuaddr); + +/******************************************************************************/ + +#if defined(COPYBIT_Z180) +#define MAX_SCALE_FACTOR (4096) +#define MAX_DIMENSION (4096) +#else +#error "Unsupported HW version" +#endif + +#define NUM_SURFACES 3 + +enum { + RGB_SURFACE, + YUV_SURFACE_2_PLANES, + YUV_SURFACE_3_PLANES +}; + +enum eConversionType { + CONVERT_TO_ANDROID_FORMAT, + CONVERT_TO_C2D_FORMAT +}; + +enum eC2DFlags { + FLAGS_PREMULTIPLIED_ALPHA = 1<<0, + FLAGS_YUV_DESTINATION = 1<<1 +}; + +static android::sp sAlloc = 0; +/******************************************************************************/ + +/** State information for each device instance */ +struct copybit_context_t { + struct copybit_device_t device; + unsigned int src[NUM_SURFACES]; /* src surfaces */ + unsigned int dst[NUM_SURFACES]; /* dst surfaces */ + unsigned int trg_transform; /* target transform */ + C2D_OBJECT blitState; + void *libc2d2; + alloc_data temp_src_buffer; + alloc_data temp_dst_buffer; + int fb_width; + int fb_height; + bool isPremultipliedAlpha; +}; + +struct blitlist{ + uint32_t count; + C2D_OBJECT blitObjects[12]; +}; + +struct bufferInfo { + int width; + int height; + int format; +}; + +struct yuvPlaneInfo { + int yStride; //luma stride + int plane1_stride; + int plane2_stride; + int plane1_offset; + int plane2_offset; +}; + +/** + * Common hardware methods + */ + +static int open_copybit(const struct hw_module_t* module, const char* name, + struct hw_device_t** device); + +static struct hw_module_methods_t copybit_module_methods = { +open: open_copybit +}; + +/* + * The COPYBIT Module + */ +struct copybit_module_t HAL_MODULE_INFO_SYM = { +common: { +tag: HARDWARE_MODULE_TAG, + version_major: 1, + version_minor: 0, + id: COPYBIT_HARDWARE_MODULE_ID, + name: "QCT COPYBIT C2D 2.0 Module", + author: "Qualcomm", + methods: ©bit_module_methods + } +}; + + +/* convert COPYBIT_FORMAT to C2D format */ +static int get_format(int format) { + switch (format) { + case HAL_PIXEL_FORMAT_RGB_565: return C2D_COLOR_FORMAT_565_RGB; + case HAL_PIXEL_FORMAT_RGBX_8888: return C2D_COLOR_FORMAT_8888_ARGB | + C2D_FORMAT_SWAP_RB | + C2D_FORMAT_DISABLE_ALPHA; + case HAL_PIXEL_FORMAT_RGBA_8888: return C2D_COLOR_FORMAT_8888_ARGB | + C2D_FORMAT_SWAP_RB; + case HAL_PIXEL_FORMAT_BGRA_8888: return C2D_COLOR_FORMAT_8888_ARGB; + case HAL_PIXEL_FORMAT_RGBA_5551: return C2D_COLOR_FORMAT_5551_RGBA; + case HAL_PIXEL_FORMAT_RGBA_4444: return C2D_COLOR_FORMAT_4444_RGBA; + case HAL_PIXEL_FORMAT_YCbCr_420_SP: return C2D_COLOR_FORMAT_420_NV12; + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:return C2D_COLOR_FORMAT_420_NV12; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: return C2D_COLOR_FORMAT_420_NV21; + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: return C2D_COLOR_FORMAT_420_NV12 | + C2D_FORMAT_MACROTILED; + default: ALOGE("%s: invalid format (0x%x", __FUNCTION__, format); return -EINVAL; + } + return -EINVAL; +} + +/* Get the C2D formats needed for conversion to YUV */ +static int get_c2d_format_for_yuv_destination(int halFormat) { + switch (halFormat) { + // We do not swap the RB when the target is YUV + case HAL_PIXEL_FORMAT_RGBX_8888: return C2D_COLOR_FORMAT_8888_ARGB | + C2D_FORMAT_DISABLE_ALPHA; + case HAL_PIXEL_FORMAT_RGBA_8888: return C2D_COLOR_FORMAT_8888_ARGB; + // The U and V need to be interchanged when the target is YUV + case HAL_PIXEL_FORMAT_YCbCr_420_SP: return C2D_COLOR_FORMAT_420_NV21; + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:return C2D_COLOR_FORMAT_420_NV21; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: return C2D_COLOR_FORMAT_420_NV12; + default: return get_format(halFormat); + } + return -EINVAL; +} + +/* ------------------------------------------------------------------- *//*! + * \internal + * \brief Get the bpp for a particular color format + * \param color format + * \return bits per pixel + *//* ------------------------------------------------------------------- */ +int c2diGetBpp(int32 colorformat) +{ + + int c2dBpp = 0; + + switch(colorformat&0xFF) + { + case C2D_COLOR_FORMAT_4444_RGBA: + case C2D_COLOR_FORMAT_4444_ARGB: + case C2D_COLOR_FORMAT_1555_ARGB: + case C2D_COLOR_FORMAT_565_RGB: + case C2D_COLOR_FORMAT_5551_RGBA: + c2dBpp = 16; + break; + case C2D_COLOR_FORMAT_8888_RGBA: + case C2D_COLOR_FORMAT_8888_ARGB: + c2dBpp = 32; + break; + case C2D_COLOR_FORMAT_8_L: + case C2D_COLOR_FORMAT_8_A: + c2dBpp = 8; + break; + case C2D_COLOR_FORMAT_4_A: + c2dBpp = 4; + break; + case C2D_COLOR_FORMAT_1: + c2dBpp = 1; + break; + default: + ALOGE("%s ERROR", __func__); + break; + } + return c2dBpp; +} + +static uint32 c2d_get_gpuaddr( struct private_handle_t *handle) +{ + uint32 memtype, *gpuaddr; + C2D_STATUS rc; + + if(!handle) + return 0; + + if (handle->flags & (private_handle_t::PRIV_FLAGS_USES_PMEM | + private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP)) + memtype = KGSL_USER_MEM_TYPE_PMEM; + else if (handle->flags & private_handle_t::PRIV_FLAGS_USES_ASHMEM) + memtype = KGSL_USER_MEM_TYPE_ASHMEM; + else if (handle->flags & private_handle_t::PRIV_FLAGS_USES_ION) + memtype = KGSL_USER_MEM_TYPE_ION; + else { + ALOGE("Invalid handle flags: 0x%x", handle->flags); + return 0; + } + + rc = LINK_c2dMapAddr(handle->fd, (void*)handle->base, handle->size, handle->offset, memtype, (void**)&gpuaddr); + if (rc == C2D_STATUS_OK) { + return (uint32) gpuaddr; + } + return 0; +} + +static int is_supported_rgb_format(int format) +{ + switch(format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: { + return COPYBIT_SUCCESS; + } + default: + return COPYBIT_FAILURE; + } +} + +static int get_num_planes(int format) +{ + switch(format) { + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: { + return 2; + } + case HAL_PIXEL_FORMAT_YV12: { + return 3; + } + default: + return COPYBIT_FAILURE; + } +} + +static int is_supported_yuv_format(int format) +{ + switch(format) { + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: { + return COPYBIT_SUCCESS; + } + default: + return COPYBIT_FAILURE; + } +} + +static int is_valid_destination_format(int format) +{ + if (format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED) { + // C2D does not support NV12Tile as a destination format. + return COPYBIT_FAILURE; + } + return COPYBIT_SUCCESS; +} + +static int calculate_yuv_offset_and_stride(const bufferInfo& info, + yuvPlaneInfo& yuvInfo) +{ + int width = info.width; + int height = info.height; + int format = info.format; + + int aligned_height = 0; + int aligned_width = 0, size = 0; + + switch (format) { + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: { + /* NV12 Tile buffers have their luma height aligned to 32bytes and width + * aligned to 128 bytes. The chroma offset starts at an 8K boundary + */ + aligned_height = ALIGN(height, 32); + aligned_width = ALIGN(width, 128); + size = aligned_width * aligned_height; + yuvInfo.plane1_offset = ALIGN(size,8192); + yuvInfo.yStride = aligned_width; + yuvInfo.plane1_stride = aligned_width; + break; + } + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: { + aligned_width = ALIGN(width, 32); + yuvInfo.yStride = aligned_width; + yuvInfo.plane1_stride = aligned_width; + if (HAL_PIXEL_FORMAT_NV12_ENCODEABLE == format) { + // The encoder requires a 2K aligned chroma offset + yuvInfo.plane1_offset = ALIGN(aligned_width * height, 2048); + } else + yuvInfo.plane1_offset = aligned_width * height; + + break; + } + default: { + return COPYBIT_FAILURE; + } + } + return COPYBIT_SUCCESS; +} + +/** create C2D surface from copybit image */ +static int set_image( uint32 surfaceId, const struct copybit_image_t *rhs, + int *cformat, uint32_t *mapped, const eC2DFlags flags) +{ + struct private_handle_t* handle = (struct private_handle_t*)rhs->handle; + C2D_SURFACE_TYPE surfaceType; + int status = COPYBIT_SUCCESS; + + if (flags & FLAGS_YUV_DESTINATION) { + *cformat = get_c2d_format_for_yuv_destination(rhs->format); + } else { + *cformat = get_format(rhs->format); + } + + if(*cformat == -EINVAL) { + ALOGE("%s: invalid format", __FUNCTION__); + return -EINVAL; + } + + if(handle == NULL) { + ALOGE("%s: invalid handle", __func__); + return -EINVAL; + } + + if (handle->gpuaddr == 0) { + handle->gpuaddr = c2d_get_gpuaddr(handle); + if(!handle->gpuaddr) { + ALOGE("%s: c2d_get_gpuaddr failed", __FUNCTION__); + return COPYBIT_FAILURE; + } + *mapped = 1; + } + + /* create C2D surface */ + if(is_supported_rgb_format(rhs->format) == COPYBIT_SUCCESS) { + /* RGB */ + C2D_RGB_SURFACE_DEF surfaceDef; + + surfaceType = (C2D_SURFACE_TYPE) (C2D_SURFACE_RGB_HOST | C2D_SURFACE_WITH_PHYS); + + surfaceDef.phys = (void*) handle->gpuaddr; + surfaceDef.buffer = (void*) (handle->base); + + surfaceDef.format = *cformat | + ((flags & FLAGS_PREMULTIPLIED_ALPHA) ? C2D_FORMAT_PREMULTIPLIED : 0); + surfaceDef.width = rhs->w; + surfaceDef.height = rhs->h; + int aligned_width = ALIGN(surfaceDef.width,32); + surfaceDef.stride = (aligned_width * c2diGetBpp(surfaceDef.format))>>3; + + if(LINK_c2dUpdateSurface( surfaceId,C2D_TARGET | C2D_SOURCE, surfaceType, &surfaceDef)) { + ALOGE("%s: RGB Surface c2dUpdateSurface ERROR", __FUNCTION__); + goto error; + status = COPYBIT_FAILURE; + } + } else if (is_supported_yuv_format(rhs->format) == COPYBIT_SUCCESS) { + C2D_YUV_SURFACE_DEF surfaceDef; + memset(&surfaceDef, 0, sizeof(surfaceDef)); + surfaceType = (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS); + surfaceDef.format = *cformat; + + bufferInfo info; + info.width = rhs->w; + info.height = rhs->h; + info.format = rhs->format; + + yuvPlaneInfo yuvInfo; + status = calculate_yuv_offset_and_stride(info, yuvInfo); + if(status != COPYBIT_SUCCESS) { + ALOGE("%s: calculate_yuv_offset_and_stride error", __FUNCTION__); + goto error; + } + + surfaceDef.width = rhs->w; + surfaceDef.height = rhs->h; + surfaceDef.plane0 = (void*) (handle->base); + surfaceDef.phys0 = (void*) (handle->gpuaddr); + surfaceDef.stride0 = yuvInfo.yStride; + + surfaceDef.plane1 = (void*) (handle->base + yuvInfo.plane1_offset); + surfaceDef.phys1 = (void*) (handle->gpuaddr + yuvInfo.plane1_offset); + surfaceDef.stride1 = yuvInfo.plane1_stride; + if (3 == get_num_planes(rhs->format)) { + surfaceDef.plane2 = (void*) (handle->base + yuvInfo.plane2_offset); + surfaceDef.phys2 = (void*) (handle->gpuaddr + yuvInfo.plane2_offset); + surfaceDef.stride2 = yuvInfo.plane2_stride; + } + + if(LINK_c2dUpdateSurface( surfaceId,C2D_TARGET | C2D_SOURCE, surfaceType, + &surfaceDef)) { + ALOGE("%s: YUV Surface c2dUpdateSurface ERROR", __FUNCTION__); + goto error; + status = COPYBIT_FAILURE; + } + } else { + ALOGE("%s: invalid format 0x%x", __FUNCTION__, rhs->format); + goto error; + status = COPYBIT_FAILURE; + } + + return status; + +error: + if(*mapped == 1) { + LINK_c2dUnMapAddr( (void*) handle->gpuaddr); + handle->gpuaddr = 0; + *mapped = 0; + } + return status; +} + +static int set_src_image( uint32 *surfaceId, const struct copybit_image_t *rhs, + int *cformat, uint32 *mapped) +{ + struct private_handle_t* handle = (struct private_handle_t*)rhs->handle; + *cformat = get_format(rhs->format); + C2D_SURFACE_TYPE surfaceType; + uint32 gpuaddr = (uint32)handle->gpuaddr; + int status = COPYBIT_SUCCESS; + + if (handle->gpuaddr == 0) + { + handle->gpuaddr = c2d_get_gpuaddr( handle); + if(!handle->gpuaddr) + return COPYBIT_FAILURE; + + *mapped = 1; + } + + /* create C2D surface */ + if(is_supported_rgb_format(rhs->format) == COPYBIT_SUCCESS) { + /* RGB */ + C2D_RGB_SURFACE_DEF surfaceDef; + surfaceType = (C2D_SURFACE_TYPE) (C2D_SURFACE_RGB_HOST | C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY); + + surfaceDef.phys = (void*) handle->gpuaddr; + surfaceDef.buffer = (void*) (handle->base); + surfaceDef.buffer = (void*) (handle->base + handle->offset); + + surfaceDef.format = get_format(rhs->format); + surfaceDef.width = rhs->w; + surfaceDef.height = rhs->h; + surfaceDef.stride = ALIGN(((surfaceDef.width * c2diGetBpp(surfaceDef.format))>>3), 32); + + if(LINK_c2dCreateSurface( surfaceId, C2D_TARGET, surfaceType,(void*)&surfaceDef)) { + ALOGE("%s: LINK_c2dCreateSurface error", __FUNCTION__); + status = COPYBIT_FAILURE; + goto error; + } + } else if(is_supported_yuv_format(rhs->format) == COPYBIT_SUCCESS) { + /* YUV */ + C2D_YUV_SURFACE_DEF surfaceDef; + int offset = 0; + int yStride = 0; + int uvStride = 0; + memset(&surfaceDef, 0, sizeof(surfaceDef)); + + surfaceType = (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY); + surfaceDef.format = get_format(rhs->format); + bufferInfo info; + info.width = rhs->w; + info.height = rhs->h; + info.format = rhs->format; + + yuvPlaneInfo yuvInfo; + status = calculate_yuv_offset_and_stride(info, yuvInfo); + if(status != COPYBIT_SUCCESS) { + ALOGE("%s: calculate_yuv_offset_and_stride error", __FUNCTION__); + goto error; + } + + surfaceDef.width = rhs->w; + surfaceDef.height = rhs->h; + surfaceDef.plane0 = (void*) (handle->base); + surfaceDef.phys0 = (void*) handle->gpuaddr; + surfaceDef.stride0 = yuvInfo.yStride; + + surfaceDef.plane1 = (void*) (handle->base + yuvInfo.plane1_offset); + surfaceDef.phys1 = (void*) (handle->gpuaddr + yuvInfo.plane1_offset); + surfaceDef.stride1 = yuvInfo.plane1_stride; + + if(LINK_c2dCreateSurface( surfaceId, C2D_TARGET | C2D_SOURCE, surfaceType, + (void*)&surfaceDef)) { + ALOGE("%s: YUV surface LINK_c2dCreateSurface error", __func__); + status = COPYBIT_FAILURE; + goto error; + } + } else { + ALOGE("%s: Invalid format 0x%x", __FUNCTION__, rhs->format); + status = COPYBIT_FAILURE; + } + + return COPYBIT_SUCCESS; + +error: + if(*mapped == 1) { + LINK_c2dUnMapAddr( (void*) handle->gpuaddr); + handle->gpuaddr = 0; + *mapped = 0; + } + return status; +} + +void unset_image( uint32 surfaceId, const struct copybit_image_t *rhs, + uint32 mmapped) +{ + struct private_handle_t* handle = (struct private_handle_t*)rhs->handle; + + if (mmapped && handle->gpuaddr) { + // Unmap this gpuaddr + LINK_c2dUnMapAddr( (void*) handle->gpuaddr); + handle->gpuaddr = 0; + } +} + +static int blit_to_target( uint32 surfaceId, const struct copybit_image_t *rhs) +{ + struct private_handle_t* handle = (struct private_handle_t*)rhs->handle; + uint32 cformat = get_format(rhs->format); + C2D_SURFACE_TYPE surfaceType; + uint32 memoryMapped = 0; + int status = COPYBIT_SUCCESS; + + if (!handle->gpuaddr) { + handle->gpuaddr = c2d_get_gpuaddr(handle); + if(!handle->gpuaddr) + return COPYBIT_FAILURE; + + memoryMapped = 1; + } + + /* create C2D surface */ + + if(cformat) { + /* RGB */ + C2D_RGB_SURFACE_DEF surfaceDef; + memset(&surfaceDef, 0, sizeof(surfaceDef)); + + surfaceDef.buffer = (void*) handle->base; + surfaceDef.phys = (void*) handle->gpuaddr; + + surfaceType = C2D_SURFACE_RGB_HOST; + surfaceDef.format = get_format(rhs->format); + surfaceDef.width = rhs->w; + surfaceDef.height = rhs->h; + surfaceDef.stride = ALIGN(((surfaceDef.width * c2diGetBpp(surfaceDef.format))>>3), 32); + + if(LINK_c2dReadSurface(surfaceId, surfaceType, (void*)&surfaceDef, 0, 0)) { + ALOGE("%s: LINK_c2dReadSurface ERROR", __func__); + status = COPYBIT_FAILURE; + goto done; + } + } + else { + /* YUV */ + /* TODO */ + } + +done: + if (memoryMapped) { + LINK_c2dUnMapAddr( (void*) handle->gpuaddr); + handle->gpuaddr = 0; + } + return status; +} + +/** setup rectangles */ +static void set_rects(struct copybit_context_t *ctx, + C2D_OBJECT *c2dObject, + const struct copybit_rect_t *dst, + const struct copybit_rect_t *src, + const struct copybit_rect_t *scissor) +{ + // Set the target rect. + if((ctx->trg_transform & C2D_TARGET_ROTATE_90) && + (ctx->trg_transform & C2D_TARGET_ROTATE_180)) { + /* target rotation is 270 */ + c2dObject->target_rect.x = (dst->t)<<16; + c2dObject->target_rect.y = ctx->fb_width?(ALIGN(ctx->fb_width,32)- dst->r):dst->r; + c2dObject->target_rect.y = c2dObject->target_rect.y<<16; + c2dObject->target_rect.height = ((dst->r) - (dst->l))<<16; + c2dObject->target_rect.width = ((dst->b) - (dst->t))<<16; + } else if(ctx->trg_transform & C2D_TARGET_ROTATE_90) { + c2dObject->target_rect.x = ctx->fb_height?(ctx->fb_height - dst->b):dst->b; + c2dObject->target_rect.x = c2dObject->target_rect.x<<16; + c2dObject->target_rect.y = (dst->l)<<16; + c2dObject->target_rect.height = ((dst->r) - (dst->l))<<16; + c2dObject->target_rect.width = ((dst->b) - (dst->t))<<16; + } else if(ctx->trg_transform & C2D_TARGET_ROTATE_180) { + c2dObject->target_rect.y = ctx->fb_height?(ctx->fb_height - dst->b):dst->b; + c2dObject->target_rect.y = c2dObject->target_rect.y<<16; + c2dObject->target_rect.x = ctx->fb_width?(ALIGN(ctx->fb_width,32) - dst->r):dst->r; + c2dObject->target_rect.x = c2dObject->target_rect.x<<16; + c2dObject->target_rect.height = ((dst->b) - (dst->t))<<16; + c2dObject->target_rect.width = ((dst->r) - (dst->l))<<16; + } else { + c2dObject->target_rect.x = (dst->l)<<16; + c2dObject->target_rect.y = (dst->t)<<16; + c2dObject->target_rect.height = ((dst->b) - (dst->t))<<16; + c2dObject->target_rect.width = ((dst->r) - (dst->l))<<16; + } + c2dObject->config_mask |= C2D_TARGET_RECT_BIT; + + // Set the source rect + c2dObject->source_rect.x = (src->l)<<16; + c2dObject->source_rect.y = (src->t)<<16; + c2dObject->source_rect.height = ((src->b) - (src->t))<<16; + c2dObject->source_rect.width = ((src->r) - (src->l))<<16; + c2dObject->config_mask |= C2D_SOURCE_RECT_BIT; + + // Set the scissor rect + c2dObject->scissor_rect.x = scissor->l; + c2dObject->scissor_rect.y = scissor->t; + c2dObject->scissor_rect.height = (scissor->b) - (scissor->t); + c2dObject->scissor_rect.width = (scissor->r) - (scissor->l); + c2dObject->config_mask |= C2D_SCISSOR_RECT_BIT; +} + +/** copy the bits */ +static int msm_copybit(struct copybit_context_t *dev, blitlist *list, uint32 target) +{ + int objects; + + for(objects = 0; objects < list->count; objects++) { + list->blitObjects[objects].next = &(list->blitObjects[objects+1]); + } + + if(LINK_c2dDraw(target,dev->trg_transform, 0x0, 0, 0, list->blitObjects, + list->count)) { + ALOGE("%s: LINK_c2dDraw ERROR", __FUNCTION__); + return COPYBIT_FAILURE; + } + + return COPYBIT_SUCCESS; +} + +/*****************************************************************************/ + +/** Set a parameter to value */ +static int set_parameter_copybit( + struct copybit_device_t *dev, + int name, + int value) +{ + struct copybit_context_t* ctx = (struct copybit_context_t*)dev; + if (!ctx) { + ALOGE("%s: null context", __FUNCTION__); + return -EINVAL; + } + + switch(name) { + case COPYBIT_ROTATION_DEG: + ctx->blitState.rotation = value<<16; + /* SRC rotation */ + if(!value) + ctx->blitState.config_mask &=~C2D_ROTATE_BIT;; + break; + case COPYBIT_PLANE_ALPHA: + if (value < 0) value = 0; + if (value >= 256) value = 255; + + ctx->blitState.global_alpha = value; + + if(ctx->blitState.global_alpha<255) + ctx->blitState.config_mask |= C2D_GLOBAL_ALPHA_BIT; + else + ctx->blitState.config_mask &=~C2D_GLOBAL_ALPHA_BIT; + break; + case COPYBIT_DITHER: + /* TODO */ + break; + case COPYBIT_BLUR: + /* TODO */ + break; + case COPYBIT_TRANSFORM: + ctx->blitState.config_mask &=~C2D_ROTATE_BIT; + ctx->blitState.config_mask &=~C2D_MIRROR_H_BIT; + ctx->blitState.config_mask &=~C2D_MIRROR_V_BIT; + ctx->trg_transform = C2D_TARGET_ROTATE_0; + + if((value&0x7) == COPYBIT_TRANSFORM_ROT_180) + ctx->trg_transform = C2D_TARGET_ROTATE_180; + else if((value&0x7) == COPYBIT_TRANSFORM_ROT_270) + ctx->trg_transform = C2D_TARGET_ROTATE_90; + else { + if(value©BIT_TRANSFORM_FLIP_H) + ctx->blitState.config_mask |= C2D_MIRROR_H_BIT; + if(value©BIT_TRANSFORM_FLIP_V) + ctx->blitState.config_mask |= C2D_MIRROR_V_BIT; + if(value©BIT_TRANSFORM_ROT_90) + ctx->trg_transform = C2D_TARGET_ROTATE_270; + } + break; + case COPYBIT_PREMULTIPLIED_ALPHA: + (value == COPYBIT_ENABLE) ? ctx->isPremultipliedAlpha = true : + ctx->isPremultipliedAlpha = false; + break; + case COPYBIT_FRAMEBUFFER_WIDTH: + ctx->fb_width = value; + break; + case COPYBIT_FRAMEBUFFER_HEIGHT: + ctx->fb_height = value; + break; + default: + ALOGE("%s: default case param=0x%x", __FUNCTION__, name); + return -EINVAL; + break; + } + + return COPYBIT_SUCCESS; +} + +/** Get a static info value */ +static int get(struct copybit_device_t *dev, int name) +{ + struct copybit_context_t* ctx = (struct copybit_context_t*)dev; + int value; + + if (!ctx) { + ALOGE("%s: null context error", __FUNCTION__); + return -EINVAL; + } + + switch(name) { + case COPYBIT_MINIFICATION_LIMIT: + value = MAX_SCALE_FACTOR; + break; + case COPYBIT_MAGNIFICATION_LIMIT: + value = MAX_SCALE_FACTOR; + break; + case COPYBIT_SCALING_FRAC_BITS: + value = 32; + break; + case COPYBIT_ROTATION_STEP_DEG: + value = 1; + break; + default: + ALOGE("%s: default case param=0x%x", __FUNCTION__, name); + value = -EINVAL; + } + return value; +} + +static int is_alpha(int cformat) +{ + int alpha = 0; + switch (cformat & 0xFF) { + case C2D_COLOR_FORMAT_8888_ARGB: + case C2D_COLOR_FORMAT_8888_RGBA: + case C2D_COLOR_FORMAT_5551_RGBA: + case C2D_COLOR_FORMAT_4444_ARGB: + alpha = 1; + break; + default: + alpha = 0; + break; + } + + if(alpha && (cformat&C2D_FORMAT_DISABLE_ALPHA)) + alpha = 0; + + return alpha; +} + +/* Function to check if we need a temporary buffer for the blit. + * This would happen if the requested destination stride and the + * C2D stride do not match. We ignore RGB buffers, since their + * stride is always aligned to 32. + */ +static bool need_temp_buffer(struct copybit_image_t const *img) +{ + if (COPYBIT_SUCCESS == is_supported_rgb_format(img->format)) + return false; + + struct private_handle_t* handle = (struct private_handle_t*)img->handle; + + // The width parameter in the handle contains the aligned_w. We check if we + // need to convert based on this param. YUV formats have bpp=1, so checking + // if the requested stride is aligned should suffice. + if (0 == (handle->width)%32) { + return false; + } + + return true; +} + +/* Function to extract the information from the copybit image and set the corresponding + * values in the bufferInfo struct. + */ +static void populate_buffer_info(struct copybit_image_t const *img, bufferInfo& info) +{ + info.width = img->w; + info.height = img->h; + info.format = img->format; +} + +/* Function to get the required size for a particular format, inorder for C2D to perform + * the blit operation. + */ +static size_t get_size(const bufferInfo& info) +{ + size_t size = 0; + int w = info.width; + int h = info.height; + int aligned_w = ALIGN(w, 32); + switch(info.format) { + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + { + // Chroma for this format is aligned to 2K. + size = ALIGN((aligned_w*h), 2048) + + ALIGN(w/2, 32) * h/2 *2; + size = ALIGN(size, 4096); + } break; + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + { + size = aligned_w*h + + ALIGN(w/2, 32) * h/2 *2; + size = ALIGN(size, 4096); + } break; + default: break; + } + return size; +} + +/* Function to allocate memory for the temporary buffer. This memory is + * allocated from Ashmem. It is the caller's responsibility to free this + * memory. + */ +static int get_temp_buffer(const bufferInfo& info, alloc_data& data) +{ + ALOGD("%s E", __FUNCTION__); + // Alloc memory from system heap + data.base = 0; + data.fd = -1; + data.offset = 0; + data.size = get_size(info); + data.align = getpagesize(); + data.uncached = true; + int allocFlags = GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP; + + if (sAlloc == 0) { + sAlloc = gralloc::IAllocController::getInstance(false); + } + + if (sAlloc == 0) { + ALOGE("%s: sAlloc is still NULL", __FUNCTION__); + return COPYBIT_FAILURE; + } + + int err = sAlloc->allocate(data, allocFlags, 0); + if (0 != err) { + ALOGE("%s: allocate failed", __FUNCTION__); + return COPYBIT_FAILURE; + } + + ALOGD("%s X", __FUNCTION__); + return err; +} + +/* Function to free the temporary allocated memory.*/ +static void free_temp_buffer(alloc_data &data) +{ + if (-1 != data.fd) { + sp memalloc = sAlloc->getAllocator(data.allocType); + memalloc->free_buffer(data.base, data.size, 0, data.fd); + } +} + +/* Function to perform the software color conversion. Convert the + * C2D compatible format to the Android compatible format + */ +static int copy_image(private_handle_t *src_handle, + struct copybit_image_t const *rhs, + eConversionType conversionType) +{ + if (src_handle->fd == -1) { + ALOGE("%s: src_handle fd is invalid", __FUNCTION__); + return COPYBIT_FAILURE; + } + + // Copy the info. + int ret = COPYBIT_SUCCESS; + switch(rhs->format) { + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + { + if (CONVERT_TO_ANDROID_FORMAT == conversionType) { + return convert_yuv_c2d_to_yuv_android(src_handle, rhs); + } else { + return convert_yuv_android_to_yuv_c2d(src_handle, rhs); + } + + } break; + default: { + ALOGE("%s: invalid format 0x%x", __FUNCTION__, rhs->format); + ret = COPYBIT_FAILURE; + } break; + } + return ret; +} + +static void delete_handle(private_handle_t *handle) +{ + if (handle) { + delete handle; + handle = 0; + } +} +/** do a stretch blit type operation */ +static int stretch_copybit_internal( + struct copybit_device_t *dev, + struct copybit_image_t const *dst, + struct copybit_image_t const *src, + struct copybit_rect_t const *dst_rect, + struct copybit_rect_t const *src_rect, + struct copybit_region_t const *region, + bool enableBlend) +{ + struct copybit_context_t* ctx = (struct copybit_context_t*)dev; + int status = COPYBIT_SUCCESS; + uint32 maxCount; + uint32 src_mapped = 0, trg_mapped = 0; + blitlist list; + C2D_OBJECT *req; + memset(&list, 0, sizeof(list)); + int cformat; + c2d_ts_handle timestamp; + uint32 src_surface_index = 0, dst_surface_index = 0; + + if (!ctx) { + ALOGE("%s: null context error", __FUNCTION__); + return -EINVAL; + } + + if (src->w > MAX_DIMENSION || src->h > MAX_DIMENSION) { + ALOGE("%s: src dimension error", __FUNCTION__); + return -EINVAL; + } + + if (dst->w > MAX_DIMENSION || dst->h > MAX_DIMENSION) { + ALOGE("%s : dst dimension error dst w %d h %d", __FUNCTION__, dst->w, dst->h); + return -EINVAL; + } + + maxCount = sizeof(list.blitObjects)/sizeof(C2D_OBJECT); + + struct copybit_rect_t clip; + list.count = 0; + + if (is_valid_destination_format(dst->format) == COPYBIT_FAILURE) { + ALOGE("%s: Invalid destination format format = 0x%x", __FUNCTION__, dst->format); + return COPYBIT_FAILURE; + } + + bool isYUVDestination = false; + if (is_supported_rgb_format(dst->format) == COPYBIT_SUCCESS) { + dst_surface_index = RGB_SURFACE; + } else if (is_supported_yuv_format(dst->format) == COPYBIT_SUCCESS) { + isYUVDestination = true; + int num_planes = get_num_planes(dst->format); + if (num_planes == 2) { + dst_surface_index = YUV_SURFACE_2_PLANES; + } else if (num_planes == 3) { + dst_surface_index = YUV_SURFACE_3_PLANES; + } else { + ALOGE("%s: dst number of YUV planes is invalid dst format = 0x%x", + __FUNCTION__, dst->format); + return COPYBIT_FAILURE; + } + } else { + ALOGE("%s: Invalid dst surface format 0x%x", __FUNCTION__, dst->format); + return COPYBIT_FAILURE; + } + + copybit_image_t dst_image; + dst_image.w = dst->w; + dst_image.h = dst->h; + dst_image.format = dst->format; + dst_image.handle = dst->handle; + // Check if we need a temp. copy for the destination. We'd need this the destination + // width is not aligned to 32. This case occurs for YUV formats. RGB formats are + // aligned to 32. + bool needTempDestination = need_temp_buffer(dst); + bufferInfo dst_info; + populate_buffer_info(dst, dst_info); + private_handle_t* dst_hnd = new private_handle_t(-1, 0, 0, 0, dst_info.format, + dst_info.width, dst_info.height); + if (dst_hnd == NULL) { + ALOGE("%s: dst_hnd is null", __FUNCTION__); + return COPYBIT_FAILURE; + } + if (needTempDestination) { + if (get_size(dst_info) != ctx->temp_dst_buffer.size) { + free_temp_buffer(ctx->temp_dst_buffer); + // Create a temp buffer and set that as the destination. + if (COPYBIT_FAILURE == get_temp_buffer(dst_info, ctx->temp_dst_buffer)) { + ALOGE("%s: get_temp_buffer(dst) failed", __FUNCTION__); + delete_handle(dst_hnd); + return COPYBIT_FAILURE; + } + } + dst_hnd->fd = ctx->temp_dst_buffer.fd; + dst_hnd->size = ctx->temp_dst_buffer.size; + dst_hnd->flags = ctx->temp_dst_buffer.allocType; + dst_hnd->base = (int)(ctx->temp_dst_buffer.base); + dst_hnd->offset = ctx->temp_dst_buffer.offset; + dst_hnd->gpuaddr = 0; + dst_image.handle = dst_hnd; + } + + int flags = 0; + flags |= (ctx->isPremultipliedAlpha) ? FLAGS_PREMULTIPLIED_ALPHA : 0; + flags |= (isYUVDestination) ? FLAGS_YUV_DESTINATION : 0; + + status = set_image( ctx->dst[dst_surface_index], &dst_image, + &cformat, &trg_mapped, (eC2DFlags)flags); + if(status) { + ALOGE("%s: dst: set_image error", __FUNCTION__); + delete_handle(dst_hnd); + return COPYBIT_FAILURE; + } + + if(is_supported_rgb_format(src->format) == COPYBIT_SUCCESS) { + src_surface_index = RGB_SURFACE; + } else if (is_supported_yuv_format(src->format) == COPYBIT_SUCCESS) { + int num_planes = get_num_planes(src->format); + if (num_planes == 2) { + src_surface_index = YUV_SURFACE_2_PLANES; + } else if (num_planes == 3) { + src_surface_index = YUV_SURFACE_3_PLANES; + } else { + ALOGE("%s: src number of YUV planes is invalid src format = 0x%x", + __FUNCTION__, src->format); + delete_handle(dst_hnd); + return -EINVAL; + } + } else { + ALOGE("%s: Invalid source surface format 0x%x", __FUNCTION__, src->format); + delete_handle(dst_hnd); + return -EINVAL; + } + + copybit_image_t src_image; + src_image.w = src->w; + src_image.h = src->h; + src_image.format = src->format; + src_image.handle = src->handle; + + bool needTempSource = need_temp_buffer(src); + bufferInfo src_info; + populate_buffer_info(src, src_info); + private_handle_t* src_hnd = new private_handle_t(-1, 0, 0, 0, src_info.format, + src_info.width, src_info.height); + if (NULL == src_hnd) { + ALOGE("%s: src_hnd is null", __FUNCTION__); + delete_handle(dst_hnd); + return COPYBIT_FAILURE; + } + if (needTempSource) { + if (get_size(src_info) != ctx->temp_src_buffer.size) { + free_temp_buffer(ctx->temp_src_buffer); + // Create a temp buffer and set that as the destination. + if (COPYBIT_SUCCESS != get_temp_buffer(src_info, ctx->temp_src_buffer)) { + ALOGE("%s: get_temp_buffer(src) failed", __FUNCTION__); + delete_handle(dst_hnd); + delete_handle(src_hnd); + return COPYBIT_FAILURE; + } + } + src_hnd->fd = ctx->temp_src_buffer.fd; + src_hnd->size = ctx->temp_src_buffer.size; + src_hnd->flags = ctx->temp_src_buffer.allocType; + src_hnd->base = (int)(ctx->temp_src_buffer.base); + src_hnd->offset = ctx->temp_src_buffer.offset; + src_hnd->gpuaddr = 0; + src_image.handle = src_hnd; + + // Copy the source. + copy_image((private_handle_t *)src->handle, &src_image, CONVERT_TO_C2D_FORMAT); + + // Flush the cache + sp memalloc = sAlloc->getAllocator(src_hnd->flags); + if (memalloc->clean_buffer((void *)(src_hnd->base), src_hnd->size, + src_hnd->offset, src_hnd->fd)) { + ALOGE("%s: clean_buffer failed", __FUNCTION__); + delete_handle(dst_hnd); + delete_handle(src_hnd); + return COPYBIT_FAILURE; + } + } + + status = set_image( ctx->src[src_surface_index], &src_image, + &cformat, &src_mapped, (eC2DFlags)flags); + if(status) { + ALOGE("%s: set_src_image error", __FUNCTION__); + delete_handle(dst_hnd); + delete_handle(src_hnd); + return COPYBIT_FAILURE; + } + + if (enableBlend) { + if(ctx->blitState.config_mask & C2D_GLOBAL_ALPHA_BIT) { + ctx->blitState.config_mask &= ~C2D_ALPHA_BLEND_NONE; + if(!(ctx->blitState.global_alpha)) { + // src alpha is zero + unset_image( ctx->src[src_surface_index], + &src_image, src_mapped); + unset_image( ctx->dst[dst_surface_index], + &dst_image, trg_mapped); + delete_handle(dst_hnd); + delete_handle(src_hnd); + return status; + } + } else { + if(is_alpha(cformat)) + ctx->blitState.config_mask &= ~C2D_ALPHA_BLEND_NONE; + else + ctx->blitState.config_mask |= C2D_ALPHA_BLEND_NONE; + } + } else { + ctx->blitState.config_mask |= C2D_ALPHA_BLEND_NONE; + } + + ctx->blitState.surface_id = ctx->src[src_surface_index]; + + while ((status == 0) && region->next(region, &clip)) { + req = &(list.blitObjects[list.count]); + memcpy(req,&ctx->blitState,sizeof(C2D_OBJECT)); + + set_rects(ctx, req, dst_rect, src_rect, &clip); + + if (++list.count == maxCount) { + status = msm_copybit(ctx, &list, ctx->dst[dst_surface_index]); + list.count = 0; + } + } + if ((status == 0) && list.count) { + status = msm_copybit(ctx, &list, ctx->dst[dst_surface_index]); + } + + if(LINK_c2dFinish(ctx->dst[dst_surface_index])) { + ALOGE("%s: LINK_c2dFinish ERROR", __FUNCTION__); + } + + unset_image( ctx->src[src_surface_index], &src_image, + src_mapped); + unset_image( ctx->dst[dst_surface_index], &dst_image, + trg_mapped); + if (needTempDestination) { + // copy the temp. destination without the alignment to the actual destination. + copy_image(dst_hnd, dst, CONVERT_TO_ANDROID_FORMAT); + // Invalidate the cache. + sp memalloc = sAlloc->getAllocator(dst_hnd->flags); + memalloc->clean_buffer((void *)(dst_hnd->base), dst_hnd->size, + dst_hnd->offset, dst_hnd->fd); + } + delete_handle(dst_hnd); + delete_handle(src_hnd); + ctx->isPremultipliedAlpha = false; + ctx->fb_width = 0; + ctx->fb_height = 0; + return status; +} + +static int stretch_copybit( + struct copybit_device_t *dev, + struct copybit_image_t const *dst, + struct copybit_image_t const *src, + struct copybit_rect_t const *dst_rect, + struct copybit_rect_t const *src_rect, + struct copybit_region_t const *region) +{ + struct copybit_context_t* ctx = (struct copybit_context_t*)dev; + bool needsBlending = (ctx->blitState.global_alpha != 0); + return stretch_copybit_internal(dev, dst, src, dst_rect, src_rect, + region, needsBlending); +} + +/** Perform a blit type operation */ +static int blit_copybit( + struct copybit_device_t *dev, + struct copybit_image_t const *dst, + struct copybit_image_t const *src, + struct copybit_region_t const *region) +{ + struct copybit_rect_t dr = { 0, 0, dst->w, dst->h }; + struct copybit_rect_t sr = { 0, 0, src->w, src->h }; + return stretch_copybit_internal(dev, dst, src, &dr, &sr, region, false); +} + +/*****************************************************************************/ + +/** Close the copybit device */ +static int close_copybit(struct hw_device_t *dev) +{ + struct copybit_context_t* ctx = (struct copybit_context_t*)dev; + if (ctx) { + for(int i = 0; i dst[i]); + LINK_c2dDestroySurface(ctx->src[i]); + } + + if (ctx->libc2d2) { + ::dlclose(ctx->libc2d2); + ALOGV("dlclose(libc2d2)"); + } + + free_temp_buffer(ctx->temp_src_buffer); + free_temp_buffer(ctx->temp_dst_buffer); + free(ctx); + } + + return 0; +} + +/** Open a new instance of a copybit device using name */ +static int open_copybit(const struct hw_module_t* module, const char* name, + struct hw_device_t** device) +{ + int status = COPYBIT_SUCCESS; + C2D_RGB_SURFACE_DEF surfDefinition = {0}; + C2D_YUV_SURFACE_DEF yuvSurfaceDef = {0} ; + struct copybit_context_t *ctx; + char fbName[64]; + + ctx = (struct copybit_context_t *)malloc(sizeof(struct copybit_context_t)); + if(!ctx) { + ALOGE("%s: malloc failed", __FUNCTION__); + return COPYBIT_FAILURE; + } + + /* initialize drawstate */ + memset(ctx, 0, sizeof(*ctx)); + + for (int i=0; i< NUM_SURFACES; i++) { + ctx->dst[i] = -1; + ctx->src[i] = -1; + } + + ctx->libc2d2 = ::dlopen("libC2D2.so", RTLD_NOW); + if (!ctx->libc2d2) { + ALOGE("FATAL ERROR: could not dlopen libc2d2.so: %s", dlerror()); + goto error; + } + *(void **)&LINK_c2dCreateSurface = ::dlsym(ctx->libc2d2, + "c2dCreateSurface"); + *(void **)&LINK_c2dUpdateSurface = ::dlsym(ctx->libc2d2, + "c2dUpdateSurface"); + *(void **)&LINK_c2dReadSurface = ::dlsym(ctx->libc2d2, + "c2dReadSurface"); + *(void **)&LINK_c2dDraw = ::dlsym(ctx->libc2d2, "c2dDraw"); + *(void **)&LINK_c2dFlush = ::dlsym(ctx->libc2d2, "c2dFlush"); + *(void **)&LINK_c2dFinish = ::dlsym(ctx->libc2d2, "c2dFinish"); + *(void **)&LINK_c2dWaitTimestamp = ::dlsym(ctx->libc2d2, + "c2dWaitTimestamp"); + *(void **)&LINK_c2dDestroySurface = ::dlsym(ctx->libc2d2, + "c2dDestroySurface"); + *(void **)&LINK_c2dMapAddr = ::dlsym(ctx->libc2d2, + "c2dMapAddr"); + *(void **)&LINK_c2dUnMapAddr = ::dlsym(ctx->libc2d2, + "c2dUnMapAddr"); + + if (!LINK_c2dCreateSurface || !LINK_c2dUpdateSurface || !LINK_c2dReadSurface + || !LINK_c2dDraw || !LINK_c2dFlush || !LINK_c2dWaitTimestamp || !LINK_c2dFinish + || !LINK_c2dDestroySurface) { + ALOGE("%s: dlsym ERROR", __FUNCTION__); + goto error; + } + + ctx->device.common.tag = HARDWARE_DEVICE_TAG; + ctx->device.common.version = 1; + ctx->device.common.module = (hw_module_t*)(module); + ctx->device.common.close = close_copybit; + ctx->device.set_parameter = set_parameter_copybit; + ctx->device.get = get; + ctx->device.blit = blit_copybit; + ctx->device.stretch = stretch_copybit; + ctx->blitState.config_mask = C2D_NO_BILINEAR_BIT | C2D_NO_ANTIALIASING_BIT; + ctx->trg_transform = C2D_TARGET_ROTATE_0; + + /* Create RGB Surface */ + surfDefinition.buffer = (void*)0xdddddddd; + surfDefinition.phys = (void*)0xdddddddd; + surfDefinition.stride = 1 * 4; + surfDefinition.width = 1; + surfDefinition.height = 1; + surfDefinition.format = C2D_COLOR_FORMAT_8888_ARGB; + if (LINK_c2dCreateSurface(&(ctx->dst[RGB_SURFACE]), C2D_TARGET | C2D_SOURCE, + (C2D_SURFACE_TYPE)(C2D_SURFACE_RGB_HOST | + C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY ), &surfDefinition)) { + ALOGE("%s: create ctx->dst[RGB_SURFACE] failed", __FUNCTION__); + ctx->dst[RGB_SURFACE] = -1; + goto error; + } + + + if (LINK_c2dCreateSurface(&(ctx->src[RGB_SURFACE]), C2D_TARGET | C2D_SOURCE, + (C2D_SURFACE_TYPE)(C2D_SURFACE_RGB_HOST | + C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY), &surfDefinition)) { + ALOGE("%s: create ctx->src[RGB_SURFACE] failed", __FUNCTION__); + ctx->src[RGB_SURFACE] = -1; + goto error; + } + + /* Create YUV source surface */ + yuvSurfaceDef.format = C2D_COLOR_FORMAT_420_NV12; + + yuvSurfaceDef.width = 4; + yuvSurfaceDef.height = 4; + yuvSurfaceDef.plane0 = (void*)0xaaaaaaaa; + yuvSurfaceDef.phys0 = (void*) 0xaaaaaaaa; + yuvSurfaceDef.stride0 = 4; + + yuvSurfaceDef.plane1 = (void*)0xaaaaaaaa; + yuvSurfaceDef.phys1 = (void*) 0xaaaaaaaa; + yuvSurfaceDef.stride1 = 4; + + if (LINK_c2dCreateSurface(&(ctx->src[YUV_SURFACE_2_PLANES]), + C2D_TARGET | C2D_SOURCE, + (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST|C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY), + &yuvSurfaceDef)) { + ALOGE("%s: create ctx->src[YUV_SURFACE_2_PLANES] failed", __FUNCTION__); + ctx->src[YUV_SURFACE_2_PLANES] = -1; + goto error; + } + + if (LINK_c2dCreateSurface(&(ctx->dst[YUV_SURFACE_2_PLANES]), + C2D_TARGET | C2D_SOURCE, + (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY), + &yuvSurfaceDef)) { + ALOGE("%s: create ctx->dst[YUV_SURFACE_2_PLANES] failed", __FUNCTION__); + ctx->dst[YUV_SURFACE_2_PLANES] = -1; + goto error; + } + + yuvSurfaceDef.format = C2D_COLOR_FORMAT_420_YV12; + yuvSurfaceDef.plane2 = (void*)0xaaaaaaaa; + yuvSurfaceDef.phys2 = (void*) 0xaaaaaaaa; + yuvSurfaceDef.stride2 = 4; + + if (LINK_c2dCreateSurface(&(ctx->src[YUV_SURFACE_3_PLANES]), + C2D_TARGET | C2D_SOURCE, + (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY), + &yuvSurfaceDef)) { + ALOGE("%s: create ctx->src[YUV_SURFACE_3_PLANES] failed", __FUNCTION__); + ctx->src[YUV_SURFACE_3_PLANES] = -1; + goto error; + } + + if (LINK_c2dCreateSurface(&(ctx->dst[YUV_SURFACE_3_PLANES]), + C2D_TARGET | C2D_SOURCE, + (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY), + &yuvSurfaceDef)) { + ALOGE("%s: create ctx->dst[YUV_SURFACE_3_PLANES] failed", __FUNCTION__); + ctx->dst[YUV_SURFACE_3_PLANES] = -1; + goto error; + } + + ctx->temp_src_buffer.fd = -1; + ctx->temp_src_buffer.base = 0; + ctx->temp_src_buffer.size = 0; + + ctx->temp_dst_buffer.fd = -1; + ctx->temp_dst_buffer.base = 0; + ctx->temp_dst_buffer.size = 0; + + ctx->fb_width = 0; + ctx->fb_height = 0; + ctx->isPremultipliedAlpha = false; + + *device = &ctx->device.common; + return status; + +error: + for (int i = 0; isrc[i])) { + LINK_c2dDestroySurface(ctx->src[i]); + ctx->src[i] = -1; + } + if (-1 != (ctx->dst[i])) { + LINK_c2dDestroySurface(ctx->dst[i]); + ctx->dst[i] = -1; + } + } + if (ctx->libc2d2) + ::dlclose(ctx->libc2d2); + if (ctx) + free(ctx); + status = COPYBIT_FAILURE; + *device = NULL; + + return status; +} diff --git a/libcopybit/copybit_priv.h b/libcopybit/copybit_priv.h new file mode 100644 index 0000000..fd1b27e --- /dev/null +++ b/libcopybit/copybit_priv.h @@ -0,0 +1,56 @@ +/* + * 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 +struct copybit_iterator : public copybit_region_t { + copybit_iterator(const copybit_rect_t& rect) { + mRect = rect; + mCount = 1; + this->next = iterate; + } +private: + static int iterate(copybit_region_t const * self, copybit_rect_t* rect) { + if (!self || !rect) { + return 0; + } + + copybit_iterator const* me = static_cast(self); + if (me->mCount) { + rect->l = me->mRect.l; + rect->t = me->mRect.t; + rect->r = me->mRect.r; + rect->b = me->mRect.b; + me->mCount--; + return 1; + } + return 0; + } + copybit_rect_t mRect; + mutable int mCount; +}; diff --git a/libcopybit/software_converter.cpp b/libcopybit/software_converter.cpp new file mode 100644 index 0000000..c9bb674 --- /dev/null +++ b/libcopybit/software_converter.cpp @@ -0,0 +1,263 @@ +/* + * 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. + */ + +#define LOG_TAG "copybit" +#include +#include +#include +#include "software_converter.h" + +/** Convert YV12 to YCrCb_420_SP */ +int convertYV12toYCrCb420SP(const copybit_image_t *src, private_handle_t *yv12_handle) +{ + private_handle_t* hnd = (private_handle_t*)src->handle; + + if(hnd == NULL || yv12_handle == NULL){ + ALOGE("Invalid handle"); + return -1; + } + + // Please refer to the description of YV12 in hardware.h + // for the formulae used to calculate buffer sizes and offsets + + // In a copybit_image_t, w is the stride and + // stride - horiz_padding is the actual width + // vertical stride is the same as height, so not considered + unsigned int stride = src->w; + unsigned int width = src->w - src->horiz_padding; + unsigned int height = src->h; + unsigned int y_size = stride * src->h; + unsigned int c_width = ALIGN(stride/2, 16); + unsigned int c_size = c_width * src->h/2; + unsigned int chromaPadding = c_width - width/2; + unsigned int chromaSize = c_size * 2; + unsigned char* newChroma = (unsigned char *)(yv12_handle->base + y_size); + unsigned char* oldChroma = (unsigned char*)(hnd->base + y_size); + memcpy((char *)yv12_handle->base,(char *)hnd->base,y_size); + +#ifdef __ARM_HAVE_NEON + /* interleave */ + if(!chromaPadding) { + unsigned char * t1 = newChroma; + unsigned char * t2 = oldChroma; + unsigned char * t3 = t2 + chromaSize/2; + for(unsigned int i=0; i < (chromaSize/2)>>3; i++) { + __asm__ __volatile__ ( + "vld1.u8 d0, [%0]! \n" + "vld1.u8 d1, [%1]! \n" + "vst2.u8 {d0, d1}, [%2]! \n" + :"+r"(t2), "+r"(t3), "+r"(t1) + : + :"memory","d0","d1" + ); + + } + } +#else //__ARM_HAVE_NEON + if(!chromaPadding) { + for(unsigned int i = 0; i< chromaSize/2; i++) { + newChroma[i*2] = oldChroma[i]; + newChroma[i*2+1] = oldChroma[i+chromaSize/2]; + } + + } +#endif + // If the image is not aligned to 16 pixels, + // convert using the C routine below + // r1 tracks the row of the source buffer + // r2 tracks the row of the destination buffer + // The width/2 checks are to avoid copying + // from the padding + + if(chromaPadding) { + unsigned int r1 = 0, r2 = 0, i = 0, j = 0; + while(r1 < height/2) { + if(j == width) { + j = 0; + r2++; + continue; + } + if (j+1 == width) { + newChroma[r2*width + j] = oldChroma[r1*c_width+i]; + r2++; + newChroma[r2*width] = oldChroma[r1*c_width+i+c_size]; + j = 1; + } else { + newChroma[r2*width + j] = oldChroma[r1*c_width+i]; + newChroma[r2*width + j + 1] = oldChroma[r1*c_width+i+c_size]; + j+=2; + } + i++; + if (i == width/2 ) { + i = 0; + r1++; + } + } + } + + return 0; +} + +struct copyInfo{ + int width; + int height; + int src_stride; + int dst_stride; + int src_plane1_offset; + int src_plane2_offset; + int dst_plane1_offset; + int dst_plane2_offset; +}; + +/* Internal function to do the actual copy of source to destination */ +static int copy_source_to_destination(const int src_base, const int dst_base, + copyInfo& info) +{ + if (!src_base || !dst_base) { + ALOGE("%s: invalid memory src_base = 0x%x dst_base=0x%x", + __FUNCTION__, src_base, dst_base); + return COPYBIT_FAILURE; + } + + int width = info.width; + int height = info.height; + unsigned char *src = (unsigned char*)src_base; + unsigned char *dst = (unsigned char*)dst_base; + + // Copy the luma + for (int i = 0; i < height; i++) { + memcpy(dst, src, width); + src += info.src_stride; + dst += info.dst_stride; + } + + // Copy plane 1 + src = (unsigned char*)(src_base + info.src_plane1_offset); + dst = (unsigned char*)(dst_base + info.dst_plane1_offset); + width = width/2; + height = height/2; + for (int i = 0; i < height; i++) { + memcpy(dst, src, info.src_stride); + src += info.src_stride; + dst += info.dst_stride; + } + return 0; +} + + +/* + * Function to convert the c2d format into an equivalent Android format + * + * @param: source buffer handle + * @param: destination image + * + * @return: return status + */ +int convert_yuv_c2d_to_yuv_android(private_handle_t *hnd, + struct copybit_image_t const *rhs) +{ + ALOGD("Enter %s", __FUNCTION__); + if (!hnd || !rhs) { + ALOGE("%s: invalid inputs hnd=%p rhs=%p", __FUNCTION__, hnd, rhs); + return COPYBIT_FAILURE; + } + + int ret = COPYBIT_SUCCESS; + private_handle_t *dst_hnd = (private_handle_t *)rhs->handle; + + copyInfo info; + info.width = rhs->w; + info.height = rhs->h; + info.src_stride = ALIGN(info.width, 32); + info.dst_stride = ALIGN(info.width, 16); + switch(rhs->format) { + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: { + info.src_plane1_offset = info.src_stride*info.height; + info.dst_plane1_offset = info.dst_stride*info.height; + } break; + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: { + // Chroma is 2K aligned for the NV12 encodeable format. + info.src_plane1_offset = ALIGN(info.src_stride*info.height, 2048); + info.dst_plane1_offset = ALIGN(info.dst_stride*info.height, 2048); + } break; + default: + ALOGE("%s: unsupported format (format=0x%x)", __FUNCTION__, + rhs->format); + return COPYBIT_FAILURE; + } + + ret = copy_source_to_destination(hnd->base, dst_hnd->base, info); + return ret; +} + +/* + * Function to convert the Android format into an equivalent C2D format + * + * @param: source buffer handle + * @param: destination image + * + * @return: return status + */ +int convert_yuv_android_to_yuv_c2d(private_handle_t *hnd, + struct copybit_image_t const *rhs) +{ + if (!hnd || !rhs) { + ALOGE("%s: invalid inputs hnd=%p rhs=%p", __FUNCTION__, hnd, rhs); + return COPYBIT_FAILURE; + } + + int ret = COPYBIT_SUCCESS; + private_handle_t *dst_hnd = (private_handle_t *)rhs->handle; + + copyInfo info; + info.width = rhs->w; + info.height = rhs->h; + info.src_stride = ALIGN(hnd->width, 16); + info.dst_stride = ALIGN(info.width, 32); + switch(rhs->format) { + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: { + info.src_plane1_offset = info.src_stride*info.height; + info.dst_plane1_offset = info.dst_stride*info.height; + } break; + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: { + // Chroma is 2K aligned for the NV12 encodeable format. + info.src_plane1_offset = ALIGN(info.src_stride*info.height, 2048); + info.dst_plane1_offset = ALIGN(info.dst_stride*info.height, 2048); + } break; + default: + ALOGE("%s: unsupported format (format=0x%x)", __FUNCTION__, + rhs->format); + return -1; + } + + ret = copy_source_to_destination(hnd->base, dst_hnd->base, info); + return ret; +} diff --git a/libcopybit/software_converter.h b/libcopybit/software_converter.h new file mode 100644 index 0000000..54b503d --- /dev/null +++ b/libcopybit/software_converter.h @@ -0,0 +1,62 @@ +/* + * 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 "gralloc_priv.h" +#include "gr.h" + +#define COPYBIT_SUCCESS 0 +#define COPYBIT_FAILURE -1 + +int convertYV12toYCrCb420SP(const copybit_image_t *src,private_handle_t *yv12_handle); + +/* + * Function to convert the c2d format into an equivalent Android format + * + * @param: source buffer handle + * @param: destination image + * + * @return: return status + */ +int convert_yuv_c2d_to_yuv_android(private_handle_t *hnd, + struct copybit_image_t const *rhs); + + +/* + * Function to convert the Android format into an equivalent C2D format + * + * @param: source buffer handle + * @param: destination image + * + * @return: return status + */ +int convert_yuv_android_to_yuv_c2d(private_handle_t *hnd, + struct copybit_image_t const *rhs); diff --git a/libgenlock/Android.mk b/libgenlock/Android.mk index 740d6ce..6ae8909 100644 --- a/libgenlock/Android.mk +++ b/libgenlock/Android.mk @@ -4,8 +4,7 @@ include $(CLEAR_VARS) LOCAL_PRELINK_MODULE := false LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES) LOCAL_SHARED_LIBRARIES := liblog libcutils -LOCAL_C_INCLUDES := -LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc +LOCAL_C_INCLUDES := hardware/qcom/display/libgralloc LOCAL_ADDITIONAL_DEPENDENCIES := LOCAL_SRC_FILES := genlock.cpp LOCAL_CFLAGS:= -DLOG_TAG=\"libgenlock\" diff --git a/libgenlock/genlock.cpp b/libgenlock/genlock.cpp index 5d5536b..bfec641 100644 --- a/libgenlock/genlock.cpp +++ b/libgenlock/genlock.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, 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 @@ -43,7 +43,7 @@ #endif namespace { - /* Internal function to map the userspace locks to the kernel lock types */ +/* Internal function to map the userspace locks to the kernel lock types */ int get_kernel_lock_type(genlock_lock_type lockType) { int kLockType = 0; @@ -62,7 +62,7 @@ namespace { /* Internal function to perform the actual lock/unlock operations */ genlock_status_t perform_lock_unlock_operation(native_handle_t *buffer_handle, - int lockType, int timeout) + int lockType, int timeout) { if (private_handle_t::validate(buffer_handle)) { ALOGE("%s: handle is invalid", __FUNCTION__); @@ -73,7 +73,7 @@ namespace { if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) { if (hnd->genlockPrivFd < 0) { ALOGE("%s: the lock has not been created, or has not been attached", - __FUNCTION__); + __FUNCTION__); return GENLOCK_FAILURE; } @@ -85,7 +85,7 @@ namespace { if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_LOCK, &lock)) { ALOGE("%s: GENLOCK_IOC_LOCK failed (lockType0x%x, err=%s fd=%d)", __FUNCTION__, - lockType, strerror(errno), hnd->fd); + lockType, strerror(errno), hnd->fd); if (ETIMEDOUT == errno) return GENLOCK_TIMEDOUT; @@ -132,7 +132,7 @@ genlock_status_t genlock_create_lock(native_handle_t *buffer_handle) int fd = open(GENLOCK_DEVICE, O_RDWR); if (fd < 0) { ALOGE("%s: open genlock device failed (err=%s)", __FUNCTION__, - strerror(errno)); + strerror(errno)); return GENLOCK_FAILURE; } @@ -140,7 +140,7 @@ genlock_status_t genlock_create_lock(native_handle_t *buffer_handle) genlock_lock lock; if (ioctl(fd, GENLOCK_IOC_NEW, NULL)) { ALOGE("%s: GENLOCK_IOC_NEW failed (error=%s)", __FUNCTION__, - strerror(errno)); + strerror(errno)); close_genlock_fd_and_handle(fd, lock.fd); ret = GENLOCK_FAILURE; } @@ -149,7 +149,7 @@ genlock_status_t genlock_create_lock(native_handle_t *buffer_handle) if (GENLOCK_FAILURE != ret) { if (ioctl(fd, GENLOCK_IOC_EXPORT, &lock)) { ALOGE("%s: GENLOCK_IOC_EXPORT failed (error=%s)", __FUNCTION__, - strerror(errno)); + strerror(errno)); close_genlock_fd_and_handle(fd, lock.fd); ret = GENLOCK_FAILURE; } @@ -219,7 +219,7 @@ genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle) int fd = open(GENLOCK_DEVICE, O_RDWR); if (fd < 0) { ALOGE("%s: open genlock device failed (err=%s)", __FUNCTION__, - strerror(errno)); + strerror(errno)); return GENLOCK_FAILURE; } @@ -228,7 +228,7 @@ genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle) lock.fd = hnd->genlockHandle; if (ioctl(fd, GENLOCK_IOC_ATTACH, &lock)) { ALOGE("%s: GENLOCK_IOC_ATTACH failed (err=%s)", __FUNCTION__, - strerror(errno)); + strerror(errno)); close_genlock_fd_and_handle(fd, lock.fd); ret = GENLOCK_FAILURE; } @@ -253,8 +253,8 @@ genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle) * @return error status. */ genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle, - genlock_lock_type_t lockType, - int timeout) + genlock_lock_type_t lockType, + int timeout) { genlock_status_t ret = GENLOCK_NO_ERROR; #ifdef USE_GENLOCK @@ -280,7 +280,7 @@ genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle, * * @param: handle of the buffer to be unlocked. * @return: error status. -*/ + */ genlock_status_t genlock_unlock_buffer(native_handle_t *buffer_handle) { genlock_status_t ret = GENLOCK_NO_ERROR; diff --git a/libgenlock/genlock.h b/libgenlock/genlock.h index b394410..0995557 100644 --- a/libgenlock/genlock.h +++ b/libgenlock/genlock.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, 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 @@ -36,80 +36,80 @@ extern "C" { #endif -/* Genlock lock types */ -typedef enum genlock_lock_type{ - GENLOCK_READ_LOCK = 1<<0, // Read lock - GENLOCK_WRITE_LOCK = 1<<1, // Write lock -}genlock_lock_type_t; + /* Genlock lock types */ + typedef enum genlock_lock_type{ + GENLOCK_READ_LOCK = 1<<0, // Read lock + GENLOCK_WRITE_LOCK = 1<<1, // Write lock + }genlock_lock_type_t; -/* Genlock return values */ -typedef enum genlock_status{ - GENLOCK_NO_ERROR = 0, - GENLOCK_TIMEDOUT, - GENLOCK_FAILURE, -} genlock_status_t; + /* Genlock return values */ + typedef enum genlock_status{ + GENLOCK_NO_ERROR = 0, + GENLOCK_TIMEDOUT, + GENLOCK_FAILURE, + } genlock_status_t; -/* Genlock defines */ + /* Genlock defines */ #define GENLOCK_MAX_TIMEOUT 1000 // Max 1s timeout -/* - * Create a genlock lock. The genlock lock file descriptor and the lock - * handle are stored in the buffer_handle. - * - * @param: handle of the buffer - * @return error status. - */ -genlock_status_t genlock_create_lock(native_handle_t *buffer_handle); + /* + * Create a genlock lock. The genlock lock file descriptor and the lock + * handle are stored in the buffer_handle. + * + * @param: handle of the buffer + * @return error status. + */ + genlock_status_t genlock_create_lock(native_handle_t *buffer_handle); -/* - * Release a genlock lock associated with the handle. - * - * @param: handle of the buffer - * @return error status. - */ -genlock_status_t genlock_release_lock(native_handle_t *buffer_handle); + /* + * Release a genlock lock associated with the handle. + * + * @param: handle of the buffer + * @return error status. + */ + genlock_status_t genlock_release_lock(native_handle_t *buffer_handle); -/* - * Attach a lock to the buffer handle passed via an IPC. - * - * @param: handle of the buffer - * @return error status. - */ -genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle); + /* + * Attach a lock to the buffer handle passed via an IPC. + * + * @param: handle of the buffer + * @return error status. + */ + genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle); -/* - * Lock the buffer specified by the buffer handle. The lock held by the buffer - * is specified by the lockType. This function will block if a write lock is - * requested on the buffer which has previously been locked for a read or write - * operation. A buffer can be locked by multiple clients for read. An optional - * timeout value can be specified. By default, there is no timeout. - * - * @param: handle of the buffer - * @param: type of lock to be acquired by the buffer. - * @param: timeout value in ms. GENLOCK_MAX_TIMEOUT is the maximum timeout value. - * @return error status. - */ -genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle, - genlock_lock_type_t lockType, - int timeout); + /* + * Lock the buffer specified by the buffer handle. The lock held by the buffer + * is specified by the lockType. This function will block if a write lock is + * requested on the buffer which has previously been locked for a read or write + * operation. A buffer can be locked by multiple clients for read. An optional + * timeout value can be specified. By default, there is no timeout. + * + * @param: handle of the buffer + * @param: type of lock to be acquired by the buffer. + * @param: timeout value in ms. GENLOCK_MAX_TIMEOUT is the maximum timeout value. + * @return error status. + */ + genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle, + genlock_lock_type_t lockType, + int timeout); -/* - * Unlocks a buffer that has previously been locked by the client. - * - * @param: handle of the buffer to be unlocked. - * @return: error status. -*/ -genlock_status_t genlock_unlock_buffer(native_handle_t *buffer_handle); + /* + * Unlocks a buffer that has previously been locked by the client. + * + * @param: handle of the buffer to be unlocked. + * @return: error status. + */ + genlock_status_t genlock_unlock_buffer(native_handle_t *buffer_handle); -/* - * Blocks the calling process until the lock held on the handle is unlocked. - * - * @param: handle of the buffer - * @param: timeout value for the wait. - * return: error status. - */ -genlock_status_t genlock_wait(native_handle_t *buffer_handle, int timeout); + /* + * Blocks the calling process until the lock held on the handle is unlocked. + * + * @param: handle of the buffer + * @param: timeout value for the wait. + * return: error status. + */ + genlock_status_t genlock_wait(native_handle_t *buffer_handle, int timeout); #ifdef __cplusplus } diff --git a/libgralloc/Android.mk b/libgralloc/Android.mk index 5377d86..44108c7 100644 --- a/libgralloc/Android.mk +++ b/libgralloc/Android.mk @@ -11,65 +11,48 @@ # 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. - -# Use this flag until pmem/ashmem is implemented in the new gralloc LOCAL_PATH := $(call my-dir) # HAL module implemenation, not prelinked and stored in # hw/..so include $(CLEAR_VARS) -LOCAL_PRELINK_MODULE := false -LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw -LOCAL_SHARED_LIBRARIES := liblog libcutils libGLESv1_CM libutils libmemalloc libQcomUI -LOCAL_SHARED_LIBRARIES += libgenlock +LOCAL_PRELINK_MODULE := false +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libmemalloc +LOCAL_SHARED_LIBRARIES += libgenlock libQcomUI libGLESv1_CM +LOCAL_C_INCLUDES := hardware/qcom/display/liboverlay/ +LOCAL_C_INCLUDES += hardware/qcom/display/libgenlock +LOCAL_C_INCLUDES += hardware/qcom/display/libqcomui +LOCAL_MODULE := gralloc.$(TARGET_BOARD_PLATFORM) +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).gralloc\" \ + -DDEBUG_CALC_FPS +LOCAL_SRC_FILES := gpu.cpp gralloc.cpp framebuffer.cpp mapper.cpp -LOCAL_C_INCLUDES += hardware/qcom/display/libgenlock -LOCAL_C_INCLUDES += hardware/qcom/display/libqcomui -LOCAL_ADDITIONAL_DEPENDENCIES += -LOCAL_SRC_FILES := framebuffer.cpp \ - gpu.cpp \ - gralloc.cpp \ - mapper.cpp +ifeq ($(TARGET_USES_POST_PROCESSING),true) + LOCAL_CFLAGS += -DUSES_POST_PROCESSING + LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/pp/inc +endif -LOCAL_MODULE := gralloc.$(TARGET_BOARD_PLATFORM) -LOCAL_MODULE_TAGS := optional -LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).gralloc\" -DHOST -DDEBUG_CALC_FPS - -ifeq ($(call is-board-platform,msm7627_surf msm7627_6x),true) - LOCAL_CFLAGS += -DTARGET_MSM7x27 +ifeq ($(TARGET_USES_MDP3), true) + LOCAL_CFLAGS += -DUSE_MDP3 endif ifeq ($(TARGET_HAVE_HDMI_OUT),true) LOCAL_CFLAGS += -DHDMI_DUAL_DISPLAY - LOCAL_C_INCLUDES += hardware/qcom/display/liboverlay LOCAL_SHARED_LIBRARIES += liboverlay endif - -ifeq ($(TARGET_USES_SF_BYPASS),true) - LOCAL_CFLAGS += -DSF_BYPASS -endif - -ifeq ($(TARGET_GRALLOC_USES_ASHMEM),true) - LOCAL_CFLAGS += -DUSE_ASHMEM -endif - include $(BUILD_SHARED_LIBRARY) #MemAlloc Library include $(CLEAR_VARS) LOCAL_PRELINK_MODULE := false LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES) -LOCAL_C_INCLUDES += hardware/qcom/display/libqcomui -LOCAL_ADDITIONAL_DEPENDENCIES += +LOCAL_C_INCLUDES := hardware/qcom/display/libqcomui LOCAL_SHARED_LIBRARIES := liblog libcutils libutils -LOCAL_SRC_FILES := ionalloc.cpp \ - alloc_controller.cpp +LOCAL_SRC_FILES := ionalloc.cpp alloc_controller.cpp LOCAL_CFLAGS:= -DLOG_TAG=\"memalloc\" - -ifeq ($(TARGET_USES_ION),true) - LOCAL_CFLAGS += -DUSE_ION -endif - +LOCAL_CFLAGS += -DUSE_ION LOCAL_MODULE := libmemalloc LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp index 47cdc68..1356b2f 100644 --- a/libgralloc/alloc_controller.cpp +++ b/libgralloc/alloc_controller.cpp @@ -34,24 +34,26 @@ #include "alloc_controller.h" #include "memalloc.h" #include "ionalloc.h" +#include "pmemalloc.h" #include "ashmemalloc.h" #include "gr.h" +#include "qcomutils/comptype.h" using namespace gralloc; using android::sp; -const int GRALLOC_HEAP_MASK = GRALLOC_USAGE_PRIVATE_ADSP_HEAP | - GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP | - GRALLOC_USAGE_PRIVATE_SMI_HEAP | - GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP | - GRALLOC_USAGE_PRIVATE_IOMMU_HEAP | - GRALLOC_USAGE_PRIVATE_MM_HEAP | - GRALLOC_USAGE_PRIVATE_WRITEBACK_HEAP | - GRALLOC_USAGE_PRIVATE_CAMERA_HEAP; +const int GRALLOC_HEAP_MASK = GRALLOC_USAGE_PRIVATE_ADSP_HEAP | + GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP | + GRALLOC_USAGE_PRIVATE_SMI_HEAP | + GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP | + GRALLOC_USAGE_PRIVATE_IOMMU_HEAP | + GRALLOC_USAGE_PRIVATE_MM_HEAP | + GRALLOC_USAGE_PRIVATE_WRITEBACK_HEAP | + GRALLOC_USAGE_PRIVATE_CAMERA_HEAP; //Common functions -static bool canFallback(int compositionType, int usage, bool triedSystem) +static bool canFallback(int usage, bool triedSystem) { // Fallback to system heap when alloc fails unless // 1. Composition type is MDP @@ -60,11 +62,12 @@ static bool canFallback(int compositionType, int usage, bool triedSystem) // 4. The heap type is protected // 5. The buffer is meant for external display only - if(compositionType == MDP_COMPOSITION) + if(QCCompositionType::getInstance().getCompositionType() & COMPOSITION_TYPE_MDP) return false; if(triedSystem) return false; - if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_PROTECTED)) + if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_PROTECTED | + GRALLOC_USAGE_PRIVATE_CP_BUFFER)) return false; if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_EXTERNAL_ONLY)) return false; @@ -107,13 +110,15 @@ IonController::IonController() } int IonController::allocate(alloc_data& data, int usage, - int compositionType) + int compositionType) { int ionFlags = 0; int ret; bool noncontig = false; data.uncached = useUncached(usage); + data.allocType = 0; + if(usage & GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP) ionFlags |= ION_HEAP(ION_SF_HEAP_ID); @@ -134,11 +139,13 @@ int IonController::allocate(alloc_data& data, int usage, if(usage & GRALLOC_USAGE_PRIVATE_CAMERA_HEAP) ionFlags |= ION_HEAP(ION_CAMERA_HEAP_ID); - if(usage & GRALLOC_USAGE_PROTECTED) + if(usage & GRALLOC_USAGE_PRIVATE_CP_BUFFER) ionFlags |= ION_SECURE; if(usage & GRALLOC_USAGE_PRIVATE_DO_NOT_MAP) - data.allocType = private_handle_t::PRIV_FLAGS_NOT_MAPPED; + data.allocType |= private_handle_t::PRIV_FLAGS_NOT_MAPPED; + else + data.allocType &= ~(private_handle_t::PRIV_FLAGS_NOT_MAPPED); // if no flags are set, default to // SF + IOMMU heaps, so that bypass can work @@ -149,9 +156,9 @@ int IonController::allocate(alloc_data& data, int usage, data.flags = ionFlags; ret = mIonAlloc->alloc_buffer(data); + // Fallback - if(ret < 0 && canFallback(compositionType, - usage, + if(ret < 0 && canFallback(usage, (ionFlags & ION_SYSTEM_HEAP_ID))) { ALOGW("Falling back to system heap"); @@ -161,7 +168,7 @@ int IonController::allocate(alloc_data& data, int usage, } if(ret >= 0 ) { - data.allocType = private_handle_t::PRIV_FLAGS_USES_ION; + data.allocType |= private_handle_t::PRIV_FLAGS_USES_ION; if(noncontig) data.allocType |= private_handle_t::PRIV_FLAGS_NONCONTIGUOUS_MEM; if(ionFlags & ION_SECURE) @@ -183,14 +190,14 @@ sp IonController::getAllocator(int flags) return memalloc; } -#if 0 //-------------- PmemKernelController-----------------------// - +//XXX: Remove - we're not using pmem anymore +#if 0 PmemKernelController::PmemKernelController() { - mPmemAdspAlloc = new PmemKernelAlloc(DEVICE_PMEM_ADSP); - // XXX: Right now, there is no need to maintain an instance - // of the SMI allocator as we need it only in a few cases + mPmemAdspAlloc = new PmemKernelAlloc(DEVICE_PMEM_ADSP); + // XXX: Right now, there is no need to maintain an instance + // of the SMI allocator as we need it only in a few cases } PmemKernelController::~PmemKernelController() @@ -198,7 +205,7 @@ PmemKernelController::~PmemKernelController() } int PmemKernelController::allocate(alloc_data& data, int usage, - int compositionType) + int compositionType) { int ret = 0; bool adspFallback = false; @@ -258,12 +265,13 @@ PmemAshmemController::~PmemAshmemController() } int PmemAshmemController::allocate(alloc_data& data, int usage, - int compositionType) + int compositionType) { int ret = 0; + data.allocType = 0; // Make buffers cacheable by default - data.uncached = false; + data.uncached = false; // Override if we explicitly need uncached buffers if (usage & GRALLOC_USAGE_PRIVATE_UNCACHED) @@ -298,7 +306,7 @@ int PmemAshmemController::allocate(alloc_data& data, int usage, // Fallback if(ret >= 0 ) { data.allocType = private_handle_t::PRIV_FLAGS_USES_PMEM; - } else if(ret < 0 && canFallback(compositionType, usage, false)) { + } else if(ret < 0 && canFallback(usage, false)) { ALOGW("Falling back to ashmem"); ret = mAshmemAlloc->alloc_buffer(data); if(ret >= 0) { @@ -327,9 +335,8 @@ sp PmemAshmemController::getAllocator(int flags) return memalloc; } #endif - size_t getBufferSizeAndDimensions(int width, int height, int format, - int& alignedw, int &alignedh) + int& alignedw, int &alignedh) { size_t size; @@ -376,16 +383,25 @@ size_t getBufferSizeAndDimensions(int width, int height, int format, if (HAL_PIXEL_FORMAT_NV12_ENCODEABLE == format) { // The encoder requires a 2K aligned chroma offset. size = ALIGN(alignedw*alignedh, 2048) + - (ALIGN(alignedw/2, 16) * (alignedh/2))*2; + (ALIGN(alignedw/2, 16) * (alignedh/2))*2; } else { size = alignedw*alignedh + (ALIGN(alignedw/2, 16) * (alignedh/2))*2; } size = ALIGN(size, 4096); break; - + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + case HAL_PIXEL_FORMAT_YCrCb_422_SP: + if(width & 1) { + ALOGE("width is odd for the YUV422_SP format"); + return -EINVAL; + } + alignedw = ALIGN(width, 16); + alignedh = height; + size = ALIGN(alignedw * alignedh * 2, 4096); + break; default: - ALOGE("unrecognized pixel format: %d", format); + ALOGE("unrecognized pixel format: 0x%x", format); return -EINVAL; } @@ -397,31 +413,31 @@ size_t getBufferSizeAndDimensions(int width, int height, int format, // to free the buffer using the free_buffer function int alloc_buffer(private_handle_t **pHnd, int w, int h, int format, int usage) { - alloc_data data; - int alignedw, alignedh; - android::sp sAlloc = - gralloc::IAllocController::getInstance(false); - data.base = 0; - data.fd = -1; - data.offset = 0; - data.size = getBufferSizeAndDimensions(w, h, format, alignedw, alignedh); - data.align = getpagesize(); - data.uncached = useUncached(usage); - int allocFlags = usage; + alloc_data data; + int alignedw, alignedh; + android::sp sAlloc = + gralloc::IAllocController::getInstance(false); + data.base = 0; + data.fd = -1; + data.offset = 0; + data.size = getBufferSizeAndDimensions(w, h, format, alignedw, alignedh); + data.align = getpagesize(); + data.uncached = useUncached(usage); + int allocFlags = usage; - int err = sAlloc->allocate(data, allocFlags, 0); - if (0 != err) { - ALOGE("%s: allocate failed", __FUNCTION__); - return -ENOMEM; - } + int err = sAlloc->allocate(data, allocFlags, 0); + if (0 != err) { + ALOGE("%s: allocate failed", __FUNCTION__); + return -ENOMEM; + } - private_handle_t* hnd = new private_handle_t(data.fd, data.size, - data.allocType, 0, format, alignedw, alignedh); - hnd->base = (int) data.base; - hnd->offset = data.offset; - hnd->gpuaddr = 0; - *pHnd = hnd; - return 0; + private_handle_t* hnd = new private_handle_t(data.fd, data.size, + data.allocType, 0, format, alignedw, alignedh); + hnd->base = (int) data.base; + hnd->offset = data.offset; + hnd->gpuaddr = 0; + *pHnd = hnd; + return 0; } void free_buffer(private_handle_t *hnd) diff --git a/libgralloc/alloc_controller.h b/libgralloc/alloc_controller.h index 6c907d1..134ad40 100644 --- a/libgralloc/alloc_controller.h +++ b/libgralloc/alloc_controller.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, 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 @@ -33,82 +33,82 @@ namespace gralloc { - struct alloc_data; - class IMemAlloc; - class IonAlloc; +struct alloc_data; +class IMemAlloc; +class IonAlloc; - class IAllocController : public android::RefBase { +class IAllocController : public android::RefBase { - public: - /* Allocate using a suitable method - * Returns the type of buffer allocated - */ - virtual int allocate(alloc_data& data, int usage, - int compositionType) = 0; + public: + /* Allocate using a suitable method + * Returns the type of buffer allocated + */ + virtual int allocate(alloc_data& data, int usage, + int compositionType) = 0; - virtual android::sp getAllocator(int flags) = 0; + virtual android::sp getAllocator(int flags) = 0; - virtual ~IAllocController() {}; + virtual ~IAllocController() {}; - static android::sp getInstance(bool useMasterHeap); + static android::sp getInstance(bool useMasterHeap); - private: - static android::sp sController; + private: + static android::sp sController; - }; +}; - class IonController : public IAllocController { +class IonController : public IAllocController { - public: - virtual int allocate(alloc_data& data, int usage, - int compositionType); + public: + virtual int allocate(alloc_data& data, int usage, + int compositionType); - virtual android::sp getAllocator(int flags); + virtual android::sp getAllocator(int flags); - IonController(); + IonController(); - private: - android::sp mIonAlloc; + private: + android::sp mIonAlloc; - }; +}; - class PmemKernelController : public IAllocController { +class PmemKernelController : public IAllocController { - public: - virtual int allocate(alloc_data& data, int usage, - int compositionType); + public: + virtual int allocate(alloc_data& data, int usage, + int compositionType); - virtual android::sp getAllocator(int flags); + virtual android::sp getAllocator(int flags); - PmemKernelController (); + PmemKernelController (); - ~PmemKernelController (); + ~PmemKernelController (); - private: - android::sp mPmemAdspAlloc; + private: + android::sp mPmemAdspAlloc; - }; +}; - // Main pmem controller - this should only - // be used within gralloc - class PmemAshmemController : public IAllocController { +// Main pmem controller - this should only +// be used within gralloc +class PmemAshmemController : public IAllocController { - public: - virtual int allocate(alloc_data& data, int usage, - int compositionType); + public: + virtual int allocate(alloc_data& data, int usage, + int compositionType); - virtual android::sp getAllocator(int flags); + virtual android::sp getAllocator(int flags); - PmemAshmemController(); + PmemAshmemController(); - ~PmemAshmemController(); + ~PmemAshmemController(); - private: - android::sp mPmemUserspaceAlloc; - android::sp mAshmemAlloc; - android::sp mPmemKernelCtrl; + private: + android::sp mPmemUserspaceAlloc; + android::sp mAshmemAlloc; + android::sp mPmemKernelCtrl; - }; +}; } //end namespace gralloc #endif // GRALLOC_ALLOCCONTROLLER_H diff --git a/libgralloc/ashmemalloc.cpp b/libgralloc/ashmemalloc.cpp index 8397e21..b659d90 100644 --- a/libgralloc/ashmemalloc.cpp +++ b/libgralloc/ashmemalloc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, 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 @@ -53,14 +53,14 @@ int AshmemAlloc::alloc_buffer(alloc_data& data) } else { if (ashmem_set_prot_region(fd, prot) < 0) { ALOGE("ashmem_set_prot_region(fd=%d, prot=%x) failed (%s)", - fd, prot, strerror(errno)); + fd, prot, strerror(errno)); close(fd); err = -errno; } else { base = mmap(0, data.size, prot, MAP_SHARED|MAP_POPULATE|MAP_LOCKED, fd, 0); if (base == MAP_FAILED) { ALOGE("alloc mmap(fd=%d, size=%d, prot=%x) failed (%s)", - fd, data.size, prot, strerror(errno)); + fd, data.size, prot, strerror(errno)); close(fd); err = -errno; } else { @@ -74,7 +74,7 @@ int AshmemAlloc::alloc_buffer(alloc_data& data) data.offset = offset; clean_buffer(base, data.size, offset, fd); ALOGD("ashmem: Allocated buffer base:%p size:%d fd:%d", - base, data.size, fd); + base, data.size, fd); } return err; @@ -84,7 +84,7 @@ int AshmemAlloc::alloc_buffer(alloc_data& data) int AshmemAlloc::free_buffer(void* base, size_t size, int offset, int fd) { ALOGD("ashmem: Freeing buffer base:%p size:%d fd:%d", - base, size, fd); + base, size, fd); int err = 0; if(!base) { @@ -102,15 +102,15 @@ int AshmemAlloc::map_buffer(void **pBase, size_t size, int offset, int fd) void *base = 0; base = mmap(0, size, PROT_READ| PROT_WRITE, - MAP_SHARED|MAP_POPULATE, fd, 0); + MAP_SHARED|MAP_POPULATE, fd, 0); *pBase = base; if(base == MAP_FAILED) { ALOGE("ashmem: Failed to map memory in the client: %s", - strerror(errno)); + strerror(errno)); err = -errno; } else { ALOGD("ashmem: Mapped buffer base:%p size:%d fd:%d", - base, size, fd); + base, size, fd); } return err; } @@ -121,7 +121,7 @@ int AshmemAlloc::unmap_buffer(void *base, size_t size, int offset) int err = munmap(base, size); if(err) { ALOGE("ashmem: Failed to unmap memory at %p: %s", - base, strerror(errno)); + base, strerror(errno)); } return err; diff --git a/libgralloc/ashmemalloc.h b/libgralloc/ashmemalloc.h index 051dcd1..50daf04 100644 --- a/libgralloc/ashmemalloc.h +++ b/libgralloc/ashmemalloc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, 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 @@ -34,23 +34,23 @@ #include namespace gralloc { - class AshmemAlloc : public IMemAlloc { +class AshmemAlloc : public IMemAlloc { - public: - virtual int alloc_buffer(alloc_data& data); + public: + virtual int alloc_buffer(alloc_data& data); - virtual int free_buffer(void *base, size_t size, - int offset, int fd); + virtual int free_buffer(void *base, size_t size, + int offset, int fd); - virtual int map_buffer(void **pBase, size_t size, - int offset, int fd); + virtual int map_buffer(void **pBase, size_t size, + int offset, int fd); - virtual int unmap_buffer(void *base, size_t size, - int offset); + virtual int unmap_buffer(void *base, size_t size, + int offset); - virtual int clean_buffer(void*base, size_t size, - int offset, int fd); + virtual int clean_buffer(void*base, size_t size, + int offset, int fd); - }; +}; } #endif /* GRALLOC_ASHMEMALLOC_H */ diff --git a/libgralloc/fb_priv.h b/libgralloc/fb_priv.h new file mode 100644 index 0000000..677d1c1 --- /dev/null +++ b/libgralloc/fb_priv.h @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * Copyright (c) 2012, Code Aurora Forum. All rights reserved. + * + * 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. + */ + +#ifndef FB_PRIV_H +#define FB_PRIV_H +#include + +#define NUM_FRAMEBUFFERS_MIN 2 +//XXX: Enable triple framebuffers +#define NUM_FRAMEBUFFERS_MAX 2 + +#define NO_SURFACEFLINGER_SWAPINTERVAL +#define COLOR_FORMAT(x) (x & 0xFFF) // Max range for colorFormats is 0 - FFF + +#ifdef __cplusplus +template +struct Node +{ + T data; + Node *next; +}; + +template +class Queue +{ + public: + Queue(): front(NULL), back(NULL), len(0) {dummy = new T;} + ~Queue() + { + clear(); + delete dummy; + } + void push(const T& item) //add an item to the back of the queue + { + if(len != 0) { //if the queue is not empty + back->next = new Node; //create a new node + back = back->next; //set the new node as the back node + back->data = item; + back->next = NULL; + } else { + back = new Node; + back->data = item; + back->next = NULL; + front = back; + } + len++; + } + void pop() //remove the first item from the queue + { + if (isEmpty()) + return; //if the queue is empty, no node to dequeue + T item = front->data; + Node *tmp = front; + front = front->next; + delete tmp; + if(front == NULL) //if the queue is empty, update the back pointer + back = NULL; + len--; + return; + } + T& getHeadValue() const //return the value of the first item in the queue + { //without modification to the structure + if (isEmpty()) { + ALOGE("Error can't get head of empty queue"); + return *dummy; + } + return front->data; + } + + bool isEmpty() const //returns true if no elements are in the queue + { + return (front == NULL); + } + + size_t size() const //returns the amount of elements in the queue + { + return len; + } + + private: + Node *front; + Node *back; + size_t len; + void clear() + { + while (!isEmpty()) + pop(); + } + T *dummy; +}; +#endif + +enum hdmi_mirroring_state { + HDMI_NO_MIRRORING, + HDMI_UI_MIRRORING, +}; + +struct private_handle_t; + +struct qbuf_t { + buffer_handle_t buf; + int idx; +}; + +enum buf_state { + SUB, + REF, + AVL +}; + +enum { + // flag to indicate we'll post this buffer + PRIV_USAGE_LOCKED_FOR_POST = 0x80000000, + PRIV_MIN_SWAP_INTERVAL = 0, + PRIV_MAX_SWAP_INTERVAL = 1, +}; + + +struct avail_t { + pthread_mutex_t lock; + pthread_cond_t cond; + bool is_avail; + buf_state state; +}; + +struct private_module_t { + gralloc_module_t base; + + struct private_handle_t* framebuffer; + uint32_t fbFormat; + uint32_t flags; + uint32_t numBuffers; + uint32_t bufferMask; + pthread_mutex_t lock; + buffer_handle_t currentBuffer; + + struct fb_var_screeninfo info; + struct fb_fix_screeninfo finfo; + float xdpi; + float ydpi; + float fps; + uint32_t swapInterval; + Queue disp; // non-empty when buffer is ready for display + int currentIdx; + struct avail_t avail[NUM_FRAMEBUFFERS_MAX]; + pthread_mutex_t qlock; + pthread_cond_t qpost; +#if defined(__cplusplus) && defined(HDMI_DUAL_DISPLAY) + int orientation; + int videoOverlay; // VIDEO_OVERLAY - 2D or 3D + int secureVideoOverlay; // VideoOverlay is secure + uint32_t currentOffset; + int enableHDMIOutput; // holds the type of external display + bool trueMirrorSupport; + bool exitHDMIUILoop; + float actionsafeWidthRatio; + float actionsafeHeightRatio; + bool hdmiStateChanged; + hdmi_mirroring_state hdmiMirroringState; + pthread_mutex_t overlayLock; + pthread_cond_t overlayPost; +#endif +}; + + + +#endif /* FB_PRIV_H */ diff --git a/libgralloc/framebuffer.cpp b/libgralloc/framebuffer.cpp index b6b4a8f..4935785 100644 --- a/libgralloc/framebuffer.cpp +++ b/libgralloc/framebuffer.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project -* Copyright (c) 2010-2012 Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2012 Code Aurora Forum. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,15 +17,11 @@ #include -#include - -#include #include #include -#include +#include #include -#include #include #include @@ -33,9 +29,6 @@ #include #include #include -#include - -#include #include #include @@ -44,18 +37,15 @@ #include #include "gralloc_priv.h" +#include "fb_priv.h" #include "gr.h" -#ifdef NO_SURFACEFLINGER_SWAPINTERVAL #include -#endif +#include -#include +#include "overlay.h" +namespace ovutils = overlay::utils; -#define FB_DEBUG 0 - -#if defined(HDMI_DUAL_DISPLAY) #define EVEN_OUT(x) if (x & 0x0001) {x--;} -using overlay::Overlay; /** min of int a, b */ static inline int min(int a, int b) { return (ab) ? a : b; } -#endif char framebufferStateName[] = {'S', 'R', 'A'}; -/*****************************************************************************/ - -enum { - MDDI_PANEL = '1', - EBI2_PANEL = '2', - LCDC_PANEL = '3', - EXT_MDDI_PANEL = '4', - TV_PANEL = '5' -}; - enum { PAGE_FLIP = 0x00000001, - LOCKED = 0x00000002 + LOCKED = 0x00000002 }; struct fb_context_t { framebuffer_device_t device; }; -static int neworientation; - -/*****************************************************************************/ - -static void -msm_copy_buffer(buffer_handle_t handle, int fd, - int width, int height, int format, - int x, int y, int w, int h); static int fb_setSwapInterval(struct framebuffer_device_t* dev, - int interval) + int interval) { char pval[PROPERTY_VALUE_MAX]; - property_get("debug.gr.swapinterval", pval, "-1"); + property_get("debug.egl.swapinterval", pval, "-1"); int property_interval = atoi(pval); if (property_interval >= 0) interval = property_interval; fb_context_t* ctx = (fb_context_t*)dev; private_module_t* m = reinterpret_cast( - dev->common.module); + dev->common.module); if (interval < dev->minSwapInterval || interval > dev->maxSwapInterval) return -EINVAL; @@ -116,13 +87,13 @@ static int fb_setSwapInterval(struct framebuffer_device_t* dev, } static int fb_setUpdateRect(struct framebuffer_device_t* dev, - int l, int t, int w, int h) + int l, int t, int w, int h) { if (((w|h) <= 0) || ((l|t)<0)) return -EINVAL; fb_context_t* ctx = (fb_context_t*)dev; private_module_t* m = reinterpret_cast( - dev->common.module); + dev->common.module); m->info.reserved[0] = 0x54445055; // "UPDT"; m->info.reserved[1] = (uint16_t)l | ((uint32_t)t << 16); m->info.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16); @@ -150,7 +121,7 @@ static void *disp_loop(void *ptr) // post buf out to display synchronously private_handle_t const* hnd = reinterpret_cast - (nxtBuf.buf); + (nxtBuf.buf); const size_t offset = hnd->base - m->framebuffer->base; m->info.activate = FB_ACTIVATE_VBL; m->info.yoffset = offset / m->finfo.line_length; @@ -173,28 +144,30 @@ static void *disp_loop(void *ptr) int nxtAvail = ((nxtBuf.idx + 1) % m->numBuffers); pthread_mutex_lock(&(m->avail[nxtBuf.idx].lock)); m->avail[nxtBuf.idx].is_avail = true; - m->avail[nxtBuf.idx].state = REF; - pthread_cond_broadcast(&(m->avail[nxtBuf.idx].cond)); + m->avail[nxtBuf.idx].state = SUB; + pthread_cond_signal(&(m->avail[nxtBuf.idx].cond)); pthread_mutex_unlock(&(m->avail[nxtBuf.idx].lock)); } else { +#if 0 //XXX: Triple FB pthread_mutex_lock(&(m->avail[nxtBuf.idx].lock)); if (m->avail[nxtBuf.idx].state != SUB) { ALOGE_IF(m->swapInterval != 0, "[%d] state %c, expected %c", nxtBuf.idx, - framebufferStateName[m->avail[nxtBuf.idx].state], - framebufferStateName[SUB]); + framebufferStateName[m->avail[nxtBuf.idx].state], + framebufferStateName[SUB]); } + m->avail[nxtBuf.idx].state = REF; pthread_mutex_unlock(&(m->avail[nxtBuf.idx].lock)); - - pthread_mutex_lock(&(m->avail[cur_buf].lock)); - m->avail[cur_buf].is_avail = true; if (m->avail[cur_buf].state != REF) { ALOGE_IF(m->swapInterval != 0, "[%d] state %c, expected %c", cur_buf, - framebufferStateName[m->avail[cur_buf].state], - framebufferStateName[REF]); + framebufferStateName[m->avail[cur_buf].state], + framebufferStateName[SUB]); } m->avail[cur_buf].state = AVL; - pthread_cond_broadcast(&(m->avail[cur_buf].cond)); +#endif + pthread_mutex_lock(&(m->avail[cur_buf].lock)); + m->avail[cur_buf].is_avail = true; + pthread_cond_signal(&(m->avail[cur_buf].cond)); pthread_mutex_unlock(&(m->avail[cur_buf].lock)); } cur_buf = nxtBuf.idx; @@ -205,14 +178,19 @@ static void *disp_loop(void *ptr) #if defined(HDMI_DUAL_DISPLAY) static int closeHDMIChannel(private_module_t* m) { + // XXX - when enabling HDMI +#if 0 Overlay* pTemp = m->pobjOverlay; if(pTemp != NULL) pTemp->closeChannel(); +#endif return 0; } +// XXX - Complete when enabling HDMI +#if 0 static void getSecondaryDisplayDestinationInfo(private_module_t* m, overlay_rect& - rect, int& orientation) + rect, int& orientation) { Overlay* pTemp = m->pobjOverlay; int width = pTemp->getFBWidth(); @@ -224,10 +202,10 @@ static void getSecondaryDisplayDestinationInfo(private_module_t* m, overlay_rect switch(rot) { // ROT_0 case 0: - // ROT_180 + // ROT_180 case HAL_TRANSFORM_ROT_180: pTemp->getAspectRatioPosition(fbwidth, fbheight, - &rect); + &rect); if(rot == HAL_TRANSFORM_ROT_180) orientation = HAL_TRANSFORM_ROT_180; else @@ -242,7 +220,7 @@ static void getSecondaryDisplayDestinationInfo(private_module_t* m, overlay_rect //Width and height will be swapped as there //is rotation pTemp->getAspectRatioPosition(fbheight, fbwidth, - &rect); + &rect); if(rot == HAL_TRANSFORM_ROT_90) orientation = HAL_TRANSFORM_ROT_270; @@ -252,82 +230,175 @@ static void getSecondaryDisplayDestinationInfo(private_module_t* m, overlay_rect } return; } +#endif + +/* Determine overlay state based on whether hardware supports true UI + mirroring and whether video is playing or not */ +static ovutils::eOverlayState getOverlayState(struct private_module_t* module) +{ + overlay2::Overlay& ov = *(Overlay::getInstance()); + + // Default to existing state + ovutils::eOverlayState state = ov.getState(); + + // Sanity check + if (!module) { + ALOGE("%s: NULL module", __FUNCTION__); + return state; + } + + // Check if video is playing or not + if (module->videoOverlay) { + // Video is playing, check if hardware supports true UI mirroring + if (module->trueMirrorSupport) { + // True UI mirroring is supported by hardware + if (ov.getState() == ovutils::OV_2D_VIDEO_ON_PANEL) { + // Currently playing 2D video + state = ovutils::OV_2D_TRUE_UI_MIRROR; + } else if (ov.getState() == ovutils::OV_3D_VIDEO_ON_2D_PANEL) { + // Currently playing M3D video + // FIXME: Support M3D true UI mirroring + state = ovutils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV; + } + } else { + // True UI mirroring is not supported by hardware + if (ov.getState() == ovutils::OV_2D_VIDEO_ON_PANEL) { + // Currently playing 2D video + state = ovutils::OV_2D_VIDEO_ON_PANEL_TV; + } else if (ov.getState() == ovutils::OV_3D_VIDEO_ON_2D_PANEL) { + // Currently playing M3D video + state = ovutils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV; + } + } + } else { + // Video is not playing, true UI mirroring support is irrelevant + state = ovutils::OV_UI_MIRROR; + } + + return state; +} + +/* Set overlay state */ +static void setOverlayState(ovutils::eOverlayState state) +{ + overlay2::Overlay& ov = *(Overlay::getInstance()); + ov.setState(state); +} static void *hdmi_ui_loop(void *ptr) { - private_module_t* m = reinterpret_cast( - ptr); + private_module_t* m = reinterpret_cast(ptr); while (1) { pthread_mutex_lock(&m->overlayLock); while(!(m->hdmiStateChanged)) pthread_cond_wait(&(m->overlayPost), &(m->overlayLock)); + m->hdmiStateChanged = false; if (m->exitHDMIUILoop) { pthread_mutex_unlock(&m->overlayLock); return NULL; } - bool waitForVsync = true; - int flags = WAIT_FOR_VSYNC; - if (m->pobjOverlay) { - Overlay* pTemp = m->pobjOverlay; - if (m->hdmiMirroringState == HDMI_NO_MIRRORING) - closeHDMIChannel(m); - else if(m->hdmiMirroringState == HDMI_UI_MIRRORING) { - if (!pTemp->isChannelUP()) { - int alignedW = ALIGN(m->info.xres, 32); - private_handle_t const* hnd = - reinterpret_cast(m->framebuffer); - overlay_buffer_info info; - info.width = alignedW; - info.height = hnd->height; - info.format = hnd->format; - info.size = hnd->size; + // No need to mirror UI if HDMI is not on + if (!m->enableHDMIOutput) { + ALOGE_IF(FB_DEBUG, "%s: hdmi not ON", __FUNCTION__); + pthread_mutex_unlock(&m->overlayLock); + continue; + } - if (m->trueMirrorSupport) - flags &= ~WAIT_FOR_VSYNC; - // start the overlay Channel for mirroring - // m->enableHDMIOutput corresponds to the fbnum - if (pTemp->startChannel(info, m->enableHDMIOutput, - false, true, 0, VG0_PIPE, flags)) { - pTemp->setFd(m->framebuffer->fd); - pTemp->setCrop(0, 0, m->info.xres, m->info.yres); - } else - closeHDMIChannel(m); - } + overlay2::OverlayMgr* ovMgr = + overlay2::OverlayMgrSingleton::getOverlayMgr(); + overlay2::Overlay& ov = ovMgr->ov(); - if (pTemp->isChannelUP()) { - overlay_rect destRect; - int rot = 0; - int currOrientation = 0; - getSecondaryDisplayDestinationInfo(m, destRect, rot); - pTemp->getOrientation(currOrientation); - if(rot != currOrientation) { - pTemp->setTransform(rot); - } - EVEN_OUT(destRect.x); - EVEN_OUT(destRect.y); - EVEN_OUT(destRect.w); - EVEN_OUT(destRect.h); - int currentX = 0, currentY = 0; - uint32_t currentW = 0, currentH = 0; - if (pTemp->getPosition(currentX, currentY, currentW, currentH)) { - if ((currentX != destRect.x) || (currentY != destRect.y) || - (currentW != destRect.w) || (currentH != destRect.h)) { - pTemp->setPosition(destRect.x, destRect.y, destRect.w, - destRect.h); - } - } - if (m->trueMirrorSupport) { - // if video is started the UI channel should be NO_WAIT. - flags = !m->videoOverlay ? WAIT_FOR_VSYNC : 0; - pTemp->updateOverlayFlags(flags); - } - pTemp->queueBuffer(m->currentOffset); - } + // Set overlay state + ovutils::eOverlayState state = getOverlayState(m); + setOverlayState(state); + + // Determine the RGB pipe for UI depending on the state + ovutils::eDest dest = ovutils::OV_PIPE_ALL; + if (state == ovutils::OV_2D_TRUE_UI_MIRROR) { + // True UI mirroring state: external RGB pipe is OV_PIPE2 + dest = ovutils::OV_PIPE2; + } else if (state == ovutils::OV_UI_MIRROR) { + // UI-only mirroring state: external RGB pipe is OV_PIPE0 + dest = ovutils::OV_PIPE0; + } else { + // No UI in this case + pthread_mutex_unlock(&m->overlayLock); + continue; + } + + if (m->hdmiMirroringState == HDMI_UI_MIRRORING) { + int alignedW = ALIGN(m->info.xres, 32); + + private_handle_t const* hnd = + reinterpret_cast(m->framebuffer); + unsigned int width = alignedW; + unsigned int height = hnd->height; + unsigned int format = hnd->format; + unsigned int size = hnd->size/m->numBuffers; + + ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE; + // External display connected during secure video playback + // Open secure UI session + // NOTE: when external display is already connected and then secure + // playback is started, we dont have to do anything + if (m->secureVideoOverlay) { + ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_SECURE_OVERLAY_SESSION); } - else - closeHDMIChannel(m); + + ovutils::Whf whf(width, height, format, size); + ovutils::PipeArgs parg(mdpFlags, + ovutils::OVERLAY_TRANSFORM_0, + whf, + ovutils::WAIT, + ovutils::ZORDER_0, + ovutils::IS_FG_OFF, + ovutils::ROT_FLAG_ENABLED); + ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg }; + bool ret = ov.setSource(pargs, dest); + if (!ret) { + ALOGE("%s setSource failed", __FUNCTION__); + } + + // we need to communicate m->orientation that will get some + // modifications within setParameter func. + // FIXME that is ugly. + const ovutils::Params prms (ovutils::OVERLAY_TRANSFORM_UI, + m->orientation); + ov.setParameter(prms, dest); + if (!ret) { + ALOGE("%s setParameter failed transform", __FUNCTION__); + } + + // x,y,w,h + ovutils::Dim dcrop(0, 0, m->info.xres, m->info.yres); + ov.setMemoryId(m->framebuffer->fd, dest); + ret = ov.setCrop(dcrop, dest); + if (!ret) { + ALOGE("%s setCrop failed", __FUNCTION__); + } + + ovutils::Dim pdim (m->info.xres, + m->info.yres, + 0, + 0, + m->orientation); + ret = ov.setPosition(pdim, dest); + if (!ret) { + ALOGE("%s setPosition failed", __FUNCTION__); + } + + if (!ov.commit(dest)) { + ALOGE("%s commit fails", __FUNCTION__); + } + + ret = ov.queueBuffer(m->currentOffset, dest); + if (!ret) { + ALOGE("%s queueBuffer failed", __FUNCTION__); + } + } else { + setOverlayState(ovutils::OV_CLOSED); } pthread_mutex_unlock(&m->overlayLock); } @@ -336,20 +407,30 @@ static void *hdmi_ui_loop(void *ptr) static int fb_videoOverlayStarted(struct framebuffer_device_t* dev, int started) { + ALOGE_IF(FB_DEBUG, "%s started=%d", __FUNCTION__, started); private_module_t* m = reinterpret_cast( - dev->common.module); + dev->common.module); pthread_mutex_lock(&m->overlayLock); - Overlay* pTemp = m->pobjOverlay; if(started != m->videoOverlay) { m->videoOverlay = started; + m->hdmiStateChanged = true; if (!m->trueMirrorSupport) { - m->hdmiStateChanged = true; - if (started && pTemp) { + if (started) { m->hdmiMirroringState = HDMI_NO_MIRRORING; - closeHDMIChannel(m); + ovutils::eOverlayState state = getOverlayState(m); + setOverlayState(state); } else if (m->enableHDMIOutput) m->hdmiMirroringState = HDMI_UI_MIRRORING; - pthread_cond_signal(&(m->overlayPost)); + } else { + if (m->videoOverlay == VIDEO_3D_OVERLAY_STARTED) { + ALOGE_IF(FB_DEBUG, "3D Video Started, stop mirroring!"); + m->hdmiMirroringState = HDMI_NO_MIRRORING; + ovutils::eOverlayState state = getOverlayState(m); + setOverlayState(state); + } + else if (m->enableHDMIOutput) { + m->hdmiMirroringState = HDMI_UI_MIRRORING; + } } } pthread_mutex_unlock(&m->overlayLock); @@ -358,14 +439,13 @@ static int fb_videoOverlayStarted(struct framebuffer_device_t* dev, int started) static int fb_enableHDMIOutput(struct framebuffer_device_t* dev, int externaltype) { + ALOGE_IF(FB_DEBUG, "%s externaltype=%d", __FUNCTION__, externaltype); private_module_t* m = reinterpret_cast( - dev->common.module); + dev->common.module); pthread_mutex_lock(&m->overlayLock); - Overlay* pTemp = m->pobjOverlay; //Check if true mirroring can be supported - m->trueMirrorSupport = FrameBufferInfo::getInstance()->canSupportTrueMirroring(); + m->trueMirrorSupport = ovutils::FrameBufferInfo::getInstance()->supportTrueMirroring(); m->enableHDMIOutput = externaltype; - ALOGE("In fb_enableHDMIOutput: externaltype = %d", m->enableHDMIOutput); if(externaltype) { if (m->trueMirrorSupport) { m->hdmiMirroringState = HDMI_UI_MIRRORING; @@ -373,9 +453,11 @@ static int fb_enableHDMIOutput(struct framebuffer_device_t* dev, int externaltyp if(!m->videoOverlay) m->hdmiMirroringState = HDMI_UI_MIRRORING; } - } else if (!externaltype && pTemp) { + } else if (!externaltype) { + // Either HDMI is disconnected or suspend occurred m->hdmiMirroringState = HDMI_NO_MIRRORING; - closeHDMIChannel(m); + ovutils::eOverlayState state = getOverlayState(m); + setOverlayState(state); } m->hdmiStateChanged = true; pthread_cond_signal(&(m->overlayPost)); @@ -383,58 +465,132 @@ static int fb_enableHDMIOutput(struct framebuffer_device_t* dev, int externaltyp return 0; } - -static int fb_setActionSafeWidthRatio(struct framebuffer_device_t* dev, float asWidthRatio) -{ - private_module_t* m = reinterpret_cast( - dev->common.module); - pthread_mutex_lock(&m->overlayLock); - m->actionsafeWidthRatio = asWidthRatio; - pthread_mutex_unlock(&m->overlayLock); - return 0; -} - -static int fb_setActionSafeHeightRatio(struct framebuffer_device_t* dev, float asHeightRatio) -{ - private_module_t* m = reinterpret_cast( - dev->common.module); - pthread_mutex_lock(&m->overlayLock); - m->actionsafeHeightRatio = asHeightRatio; - pthread_mutex_unlock(&m->overlayLock); - return 0; -} - static int fb_orientationChanged(struct framebuffer_device_t* dev, int orientation) { private_module_t* m = reinterpret_cast( - dev->common.module); + dev->common.module); pthread_mutex_lock(&m->overlayLock); neworientation = orientation; pthread_mutex_unlock(&m->overlayLock); return 0; } + +static int handle_open_secure_start(private_module_t* m) { + pthread_mutex_lock(&m->overlayLock); + m->hdmiMirroringState = HDMI_NO_MIRRORING; + m->secureVideoOverlay = true; + pthread_mutex_unlock(&m->overlayLock); + return 0; +} + +static int handle_open_secure_end(private_module_t* m) { + pthread_mutex_lock(&m->overlayLock); + if (m->enableHDMIOutput) { + if (m->trueMirrorSupport) { + m->hdmiMirroringState = HDMI_UI_MIRRORING; + } else if(!m->videoOverlay) { + m->hdmiMirroringState = HDMI_UI_MIRRORING; + } + m->hdmiStateChanged = true; + pthread_cond_signal(&(m->overlayPost)); + } + pthread_mutex_unlock(&m->overlayLock); + return 0; +} + +static int handle_close_secure_start(private_module_t* m) { + pthread_mutex_lock(&m->overlayLock); + m->hdmiMirroringState = HDMI_NO_MIRRORING; + m->secureVideoOverlay = false; + pthread_mutex_unlock(&m->overlayLock); + return 0; +} + +static int handle_close_secure_end(private_module_t* m) { + pthread_mutex_lock(&m->overlayLock); + if (m->enableHDMIOutput) { + if (m->trueMirrorSupport) { + m->hdmiMirroringState = HDMI_UI_MIRRORING; + } else if(!m->videoOverlay) { + m->hdmiMirroringState = HDMI_UI_MIRRORING; + } + m->hdmiStateChanged = true; + pthread_cond_signal(&(m->overlayPost)); + } + pthread_mutex_unlock(&m->overlayLock); + return 0; +} #endif + + +/* fb_perform - used to add custom event and handle them in fb HAL + * Used for external display related functions as of now + */ +static int fb_perform(struct framebuffer_device_t* dev, int event, int value) +{ + private_module_t* m = reinterpret_cast( + dev->common.module); + switch(event) { +#if defined(HDMI_DUAL_DISPLAY) + case EVENT_EXTERNAL_DISPLAY: + fb_enableHDMIOutput(dev, value); + break; + case EVENT_VIDEO_OVERLAY: + fb_videoOverlayStarted(dev, value); + break; + case EVENT_ORIENTATION_CHANGE: + fb_orientationChanged(dev, value); + break; + case EVENT_OVERLAY_STATE_CHANGE: + if (value == OVERLAY_STATE_CHANGE_START) { + // When state change starts, get a lock on overlay + pthread_mutex_lock(&m->overlayLock); + } else if (value == OVERLAY_STATE_CHANGE_END) { + // When state change is complete, unlock overlay + pthread_mutex_unlock(&m->overlayLock); + } + break; + case EVENT_OPEN_SECURE_START: + handle_open_secure_start(m); + break; + case EVENT_OPEN_SECURE_END: + handle_open_secure_end(m); + break; + case EVENT_CLOSE_SECURE_START: + handle_close_secure_start(m); + break; + case EVENT_CLOSE_SECURE_END: + handle_close_secure_end(m); + break; +#endif + default: + ALOGE("In %s: UNKNOWN Event = %d!!!", __FUNCTION__, event); + break; + } + return 0; +} + + static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer) { if (private_handle_t::validate(buffer) < 0) return -EINVAL; - int nxtIdx, futureIdx = -1; + int nxtIdx;//, futureIdx = -1; bool reuse; struct qbuf_t qb; fb_context_t* ctx = (fb_context_t*)dev; private_handle_t const* hnd = reinterpret_cast(buffer); private_module_t* m = reinterpret_cast( - dev->common.module); + dev->common.module); if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { reuse = false; nxtIdx = (m->currentIdx + 1) % m->numBuffers; - futureIdx = (nxtIdx + 1) % m->numBuffers; - + //futureIdx = (nxtIdx + 1) % m->numBuffers; if (m->swapInterval == 0) { // if SwapInterval = 0 and no buffers available then reuse // current buf for next rendering so don't post new buffer @@ -450,24 +606,25 @@ static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer) if(!reuse){ // unlock previous ("current") Buffer and lock the new buffer m->base.lock(&m->base, buffer, - private_module_t::PRIV_USAGE_LOCKED_FOR_POST, - 0,0, m->info.xres, m->info.yres, NULL); + PRIV_USAGE_LOCKED_FOR_POST, + 0,0, m->info.xres, m->info.yres, NULL); // post/queue the new buffer pthread_mutex_lock(&(m->avail[nxtIdx].lock)); - if (m->avail[nxtIdx].is_avail != true) { - ALOGE_IF(m->swapInterval != 0, "Found %d buf to be not avail", nxtIdx); - } - m->avail[nxtIdx].is_avail = false; +#if 0 //XXX: Triple FB + if (m->avail[nxtIdx].is_avail != true) { + ALOGE_IF(m->swapInterval != 0, "Found %d buf to be not avail", nxtIdx); + } if (m->avail[nxtIdx].state != AVL) { ALOGD("[%d] state %c, expected %c", nxtIdx, - framebufferStateName[m->avail[nxtIdx].state], - framebufferStateName[AVL]); + framebufferStateName[m->avail[nxtIdx].state], + framebufferStateName[AVL]); } m->avail[nxtIdx].state = SUB; +#endif pthread_mutex_unlock(&(m->avail[nxtIdx].lock)); qb.idx = nxtIdx; @@ -486,40 +643,12 @@ static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer) if (m->currentBuffer) m->base.unlock(&m->base, m->currentBuffer); m->base.lock(&m->base, buffer, - private_module_t::PRIV_USAGE_LOCKED_FOR_POST, + PRIV_USAGE_LOCKED_FOR_POST, 0,0, m->info.xres, m->info.yres, NULL); m->currentBuffer = buffer; } - } else { - void* fb_vaddr; - void* buffer_vaddr; - m->base.lock(&m->base, m->framebuffer, - GRALLOC_USAGE_SW_WRITE_RARELY, - 0, 0, m->info.xres, m->info.yres, - &fb_vaddr); - - m->base.lock(&m->base, buffer, - GRALLOC_USAGE_SW_READ_RARELY, - 0, 0, m->info.xres, m->info.yres, - &buffer_vaddr); - - //memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres); - - msm_copy_buffer( - m->framebuffer, m->framebuffer->fd, - m->info.xres, m->info.yres, m->fbFormat, - m->info.xoffset, m->info.yoffset, - m->info.width, m->info.height); - - m->base.unlock(&m->base, buffer); - m->base.unlock(&m->base, m->framebuffer); } - - ALOGD_IF(FB_DEBUG, "Framebuffer state: [0] = %c [1] = %c [2] = %c", - framebufferStateName[m->avail[0].state], - framebufferStateName[m->avail[1].state], - framebufferStateName[m->avail[2].state]); return 0; } @@ -534,7 +663,7 @@ static int fb_compositionComplete(struct framebuffer_device_t* dev) static int fb_lockBuffer(struct framebuffer_device_t* dev, int index) { private_module_t* m = reinterpret_cast( - dev->common.module); + dev->common.module); // Return immediately if the buffer is available if ((m->avail[index].state == AVL) || (m->swapInterval == 0)) @@ -543,15 +672,13 @@ static int fb_lockBuffer(struct framebuffer_device_t* dev, int index) pthread_mutex_lock(&(m->avail[index].lock)); while (m->avail[index].state != AVL) { pthread_cond_wait(&(m->avail[index].cond), - &(m->avail[index].lock)); + &(m->avail[index].lock)); } pthread_mutex_unlock(&(m->avail[index].lock)); return 0; } -/*****************************************************************************/ - int mapFrameBufferLocked(struct private_module_t* module) { // already initialized... @@ -559,9 +686,9 @@ int mapFrameBufferLocked(struct private_module_t* module) return 0; } char const * const device_template[] = { - "/dev/graphics/fb%u", - "/dev/fb%u", - 0 }; + "/dev/graphics/fb%u", + "/dev/fb%u", + 0 }; int fd = -1; int i=0; @@ -592,11 +719,11 @@ int mapFrameBufferLocked(struct private_module_t* module) info.activate = FB_ACTIVATE_NOW; /* Interpretation of offset for color fields: All offsets are from the right, - * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you - * can use the offset as right argument to <<). A pixel afterwards is a bit - * stream and is written to video memory as that unmodified. This implies - * big-endian byte order if bits_per_pixel is greater than 8. - */ + * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you + * can use the offset as right argument to <<). A pixel afterwards is a bit + * stream and is written to video memory as that unmodified. This implies + * big-endian byte order if bits_per_pixel is greater than 8. + */ if(info.bits_per_pixel == 32) { /* @@ -617,7 +744,8 @@ int mapFrameBufferLocked(struct private_module_t* module) * RGBA instead of RGBX. */ if (property_get("debug.sf.hw", property, NULL) > 0 && atoi(property) == 0) module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888; - else if(property_get("debug.composition.type", property, NULL) > 0 && (strncmp(property, "mdp", 3) == 0)) + else if(property_get("debug.composition.type", property, NULL) > 0 && + (strncmp(property, "mdp", 3) == 0)) module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888; else module->fbFormat = HAL_PIXEL_FORMAT_RGBA_8888; @@ -641,7 +769,7 @@ int mapFrameBufferLocked(struct private_module_t* module) int size = roundUpToPageSize(info.yres * info.xres * (info.bits_per_pixel/8)); /* - * Request NUM_BUFFERS screens (at lest 2 for page flipping) + * Request NUM_BUFFERS screens (at least 2 for page flipping) */ int numberOfBuffers = (int)(finfo.smem_len/size); ALOGV("num supported framebuffers in kernel = %d", numberOfBuffers); @@ -673,7 +801,7 @@ int mapFrameBufferLocked(struct private_module_t* module) info.yres_virtual = size / line_length; flags &= ~PAGE_FLIP; ALOGW("page flipping not supported (yres_virtual=%d, requested=%d)", - info.yres_virtual, info.yres*2); + info.yres_virtual, info.yres*2); } if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1) @@ -691,35 +819,35 @@ int mapFrameBufferLocked(struct private_module_t* module) //The reserved[4] field is used to store FPS by the driver. float fps = info.reserved[4]; - ALOGI( "using (fd=%d)\n" - "id = %s\n" - "xres = %d px\n" - "yres = %d px\n" - "xres_virtual = %d px\n" - "yres_virtual = %d px\n" - "bpp = %d\n" - "r = %2u:%u\n" - "g = %2u:%u\n" - "b = %2u:%u\n", - fd, - finfo.id, - info.xres, - info.yres, - info.xres_virtual, - info.yres_virtual, - info.bits_per_pixel, - info.red.offset, info.red.length, - info.green.offset, info.green.length, - info.blue.offset, info.blue.length - ); + ALOGI("using (fd=%d)\n" + "id = %s\n" + "xres = %d px\n" + "yres = %d px\n" + "xres_virtual = %d px\n" + "yres_virtual = %d px\n" + "bpp = %d\n" + "r = %2u:%u\n" + "g = %2u:%u\n" + "b = %2u:%u\n", + fd, + finfo.id, + info.xres, + info.yres, + info.xres_virtual, + info.yres_virtual, + info.bits_per_pixel, + info.red.offset, info.red.length, + info.green.offset, info.green.length, + info.blue.offset, info.blue.length + ); - ALOGI( "width = %d mm (%f dpi)\n" - "height = %d mm (%f dpi)\n" - "refresh rate = %.2f Hz\n", - info.width, xdpi, - info.height, ydpi, - fps - ); + ALOGI("width = %d mm (%f dpi)\n" + "height = %d mm (%f dpi)\n" + "refresh rate = %.2f Hz\n", + info.width, xdpi, + info.height, ydpi, + fps + ); if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) @@ -739,12 +867,12 @@ int mapFrameBufferLocked(struct private_module_t* module) char pval[PROPERTY_VALUE_MAX]; property_get("debug.gr.swapinterval", pval, "1"); module->swapInterval = atoi(pval); - if (module->swapInterval < private_module_t::PRIV_MIN_SWAP_INTERVAL || - module->swapInterval > private_module_t::PRIV_MAX_SWAP_INTERVAL) { + if (module->swapInterval < PRIV_MIN_SWAP_INTERVAL || + module->swapInterval > PRIV_MAX_SWAP_INTERVAL) { module->swapInterval = 1; ALOGW("Out of range (%d to %d) value for debug.gr.swapinterval, using 1", - private_module_t::PRIV_MIN_SWAP_INTERVAL, - private_module_t::PRIV_MAX_SWAP_INTERVAL); + PRIV_MIN_SWAP_INTERVAL, + PRIV_MAX_SWAP_INTERVAL); } #else @@ -765,9 +893,9 @@ int mapFrameBufferLocked(struct private_module_t* module) } /* create display update thread */ - pthread_t thread1; - if (pthread_create(&thread1, NULL, &disp_loop, (void *) module)) { - return -errno; + pthread_t disp_thread; + if (pthread_create(&disp_thread, NULL, &disp_loop, (void *) module)) { + return -errno; } /* @@ -778,10 +906,12 @@ int mapFrameBufferLocked(struct private_module_t* module) module->numBuffers = info.yres_virtual / info.yres; module->bufferMask = 0; //adreno needs page aligned offsets. Align the fbsize to pagesize. - size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres) * module->numBuffers; + size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres)* + module->numBuffers; module->framebuffer = new private_handle_t(fd, fbSize, - private_handle_t::PRIV_FLAGS_USES_PMEM, BUFFER_TYPE_UI, - module->fbFormat, info.xres, info.yres); + private_handle_t::PRIV_FLAGS_USES_PMEM, + BUFFER_TYPE_UI, + module->fbFormat, info.xres, info.yres); void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (vaddr == MAP_FAILED) { ALOGE("Error mapping the framebuffer (%s)", strerror(errno)); @@ -794,7 +924,6 @@ int mapFrameBufferLocked(struct private_module_t* module) /* Overlay for HDMI*/ pthread_mutex_init(&(module->overlayLock), NULL); pthread_cond_init(&(module->overlayPost), NULL); - module->pobjOverlay = new Overlay(); module->currentOffset = 0; module->exitHDMIUILoop = false; module->hdmiStateChanged = false; @@ -822,7 +951,7 @@ static int fb_close(struct hw_device_t *dev) fb_context_t* ctx = (fb_context_t*)dev; #if defined(HDMI_DUAL_DISPLAY) private_module_t* m = reinterpret_cast( - ctx->device.common.module); + ctx->device.common.module); pthread_mutex_lock(&m->overlayLock); m->exitHDMIUILoop = true; pthread_cond_signal(&(m->overlayPost)); @@ -835,7 +964,7 @@ static int fb_close(struct hw_device_t *dev) } int fb_device_open(hw_module_t const* module, const char* name, - hw_device_t** device) + hw_device_t** device) { int status = -EINVAL; if (!strcmp(name, GRALLOC_HARDWARE_FB0)) { @@ -849,22 +978,14 @@ int fb_device_open(hw_module_t const* module, const char* name, memset(dev, 0, sizeof(*dev)); /* initialize the procs */ - dev->device.common.tag = HARDWARE_DEVICE_TAG; - dev->device.common.version = 0; - dev->device.common.module = const_cast(module); - dev->device.common.close = fb_close; + dev->device.common.tag = HARDWARE_DEVICE_TAG; + dev->device.common.version = 0; + dev->device.common.module = const_cast(module); + dev->device.common.close = fb_close; dev->device.setSwapInterval = fb_setSwapInterval; dev->device.post = fb_post; - dev->device.setUpdateRect = 0; + dev->device.setUpdateRect = 0; dev->device.compositionComplete = fb_compositionComplete; - //dev->device.lockBuffer = fb_lockBuffer; -#if defined(HDMI_DUAL_DISPLAY) - dev->device.orientationChanged = fb_orientationChanged; - dev->device.videoOverlayStarted = fb_videoOverlayStarted; - dev->device.enableHDMIOutput = fb_enableHDMIOutput; - dev->device.setActionSafeWidthRatio = fb_setActionSafeWidthRatio; - dev->device.setActionSafeHeightRatio = fb_setActionSafeHeightRatio; -#endif private_module_t* m = (private_module_t*)module; status = mapFrameBuffer(m); @@ -878,11 +999,10 @@ int fb_device_open(hw_module_t const* module, const char* name, const_cast(dev->device.xdpi) = m->xdpi; const_cast(dev->device.ydpi) = m->ydpi; const_cast(dev->device.fps) = m->fps; - const_cast(dev->device.minSwapInterval) = private_module_t::PRIV_MIN_SWAP_INTERVAL; - const_cast(dev->device.maxSwapInterval) = private_module_t::PRIV_MAX_SWAP_INTERVAL; - //const_cast(dev->device.numFramebuffers) = m->numBuffers; + const_cast(dev->device.minSwapInterval) = PRIV_MIN_SWAP_INTERVAL; + const_cast(dev->device.maxSwapInterval) = PRIV_MAX_SWAP_INTERVAL; if (m->finfo.reserved[0] == 0x5444 && - m->finfo.reserved[1] == 0x5055) { + m->finfo.reserved[1] == 0x5055) { dev->device.setUpdateRect = fb_setUpdateRect; ALOGD("UPDATE_ON_DEMAND supported"); } @@ -895,43 +1015,3 @@ int fb_device_open(hw_module_t const* module, const char* name, } return status; } - -/* Copy a pmem buffer to the framebuffer */ - -static void -msm_copy_buffer(buffer_handle_t handle, int fd, - int width, int height, int format, - int x, int y, int w, int h) -{ - struct { - unsigned int count; - mdp_blit_req req; - } blit; - private_handle_t *priv = (private_handle_t*) handle; - - memset(&blit, 0, sizeof(blit)); - blit.count = 1; - - blit.req.flags = 0; - blit.req.alpha = 0xff; - blit.req.transp_mask = 0xffffffff; - - blit.req.src.width = width; - blit.req.src.height = height; - blit.req.src.offset = 0; - blit.req.src.memory_id = priv->fd; - - blit.req.dst.width = width; - blit.req.dst.height = height; - blit.req.dst.offset = 0; - blit.req.dst.memory_id = fd; - blit.req.dst.format = format; - - blit.req.src_rect.x = blit.req.dst_rect.x = x; - blit.req.src_rect.y = blit.req.dst_rect.y = y; - blit.req.src_rect.w = blit.req.dst_rect.w = w; - blit.req.src_rect.h = blit.req.dst_rect.h = h; - - if (ioctl(fd, MSMFB_BLIT, &blit)) - ALOGE("MSMFB_BLIT failed = %d", -errno); -} diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp old mode 100755 new mode 100644 index 77ad174..0ec8d73 --- a/libgralloc/gpu.cpp +++ b/libgralloc/gpu.cpp @@ -32,34 +32,12 @@ using namespace gralloc; using android::sp; gpu_context_t::gpu_context_t(const private_module_t* module, - sp alloc_ctrl ) : + sp alloc_ctrl ) : mAllocCtrl(alloc_ctrl) { // Zero out the alloc_device_t memset(static_cast(this), 0, sizeof(alloc_device_t)); - char property[PROPERTY_VALUE_MAX]; - if (property_get("debug.sf.hw", property, NULL) > 0) { - if(atoi(property) == 0) { - //debug.sf.hw = 0 - compositionType = CPU_COMPOSITION; - } else { //debug.sf.hw = 1 - // Get the composition type - property_get("debug.composition.type", property, NULL); - if (property == NULL) { - compositionType = GPU_COMPOSITION; - } else if ((strncmp(property, "mdp", 3)) == 0) { - compositionType = MDP_COMPOSITION; - } else if ((strncmp(property, "c2d", 3)) == 0) { - compositionType = C2D_COMPOSITION; - } else { - compositionType = GPU_COMPOSITION; - } - } - } else { //debug.sf.hw is not set. Use cpu composition - compositionType = CPU_COMPOSITION; - } - // Initialize the procs common.tag = HARDWARE_DEVICE_TAG; common.version = 0; @@ -74,7 +52,7 @@ gpu_context_t::gpu_context_t(const private_module_t* module, } int gpu_context_t::gralloc_alloc_framebuffer_locked(size_t size, int usage, - buffer_handle_t* pHandle) + buffer_handle_t* pHandle) { private_module_t* m = reinterpret_cast(common.module); @@ -136,7 +114,7 @@ int gpu_context_t::gralloc_alloc_framebuffer_locked(size_t size, int usage, int gpu_context_t::gralloc_alloc_framebuffer(size_t size, int usage, - buffer_handle_t* pHandle) + buffer_handle_t* pHandle) { private_module_t* m = reinterpret_cast(common.module); pthread_mutex_lock(&m->lock); @@ -162,7 +140,7 @@ int gpu_context_t::gralloc_alloc_buffer(size_t size, int usage, else data.align = getpagesize(); data.pHandle = (unsigned int) pHandle; - err = mAllocCtrl->allocate(data, usage, compositionType); + err = mAllocCtrl->allocate(data, usage, 0); if (usage & GRALLOC_USAGE_PRIVATE_UNSYNCHRONIZED) { flags |= private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED; @@ -179,7 +157,8 @@ int gpu_context_t::gralloc_alloc_buffer(size_t size, int usage, if (err == 0) { flags |= data.allocType; private_handle_t* hnd = new private_handle_t(data.fd, size, flags, - bufferType, format, width, height); + bufferType, format, width, + height); hnd->offset = data.offset; hnd->base = int(data.base) + data.offset; @@ -217,7 +196,8 @@ void gpu_context_t::getGrallocInformationFromFormat(int inputFormat, } int gpu_context_t::alloc_impl(int w, int h, int format, int usage, - buffer_handle_t* pHandle, int* pStride, size_t bufferSize) { + buffer_handle_t* pHandle, int* pStride, + size_t bufferSize) { if (!pHandle || !pStride) return -EINVAL; @@ -234,8 +214,9 @@ int gpu_context_t::alloc_impl(int w, int h, int format, int usage, // All buffers marked as protected or for external // display need to go to overlay if ((usage & GRALLOC_USAGE_EXTERNAL_DISP) || - (usage & GRALLOC_USAGE_PROTECTED)) { - bufferType = BUFFER_TYPE_VIDEO; + (usage & GRALLOC_USAGE_PROTECTED) || + (usage & GRALLOC_USAGE_PRIVATE_CP_BUFFER)) { + bufferType = BUFFER_TYPE_VIDEO; } int err; if (usage & GRALLOC_USAGE_HW_FB) { @@ -268,12 +249,12 @@ int gpu_context_t::free_impl(private_handle_t const* hnd) { int index = (hnd->base - m->framebuffer->base) / bufferSize; m->bufferMask &= ~(1<base, const_cast(hnd)); sp memalloc = mAllocCtrl->getAllocator(hnd->flags); int err = memalloc->free_buffer((void*)hnd->base, (size_t) hnd->size, - hnd->offset, hnd->fd); + hnd->offset, hnd->fd); if(err) return err; - terminateBuffer(&m->base, const_cast(hnd)); } // Release the genlock @@ -287,7 +268,8 @@ int gpu_context_t::free_impl(private_handle_t const* hnd) { } int gpu_context_t::gralloc_alloc(alloc_device_t* dev, int w, int h, int format, - int usage, buffer_handle_t* pHandle, int* pStride) + int usage, buffer_handle_t* pHandle, + int* pStride) { if (!dev) { return -EINVAL; @@ -295,8 +277,10 @@ int gpu_context_t::gralloc_alloc(alloc_device_t* dev, int w, int h, int format, gpu_context_t* gpu = reinterpret_cast(dev); return gpu->alloc_impl(w, h, format, usage, pHandle, pStride, 0); } -int gpu_context_t::gralloc_alloc_size(alloc_device_t* dev, int w, int h, int format, - int usage, buffer_handle_t* pHandle, int* pStride, int bufferSize) +int gpu_context_t::gralloc_alloc_size(alloc_device_t* dev, int w, int h, + int format, int usage, + buffer_handle_t* pHandle, int* pStride, + int bufferSize) { if (!dev) { return -EINVAL; @@ -307,7 +291,7 @@ int gpu_context_t::gralloc_alloc_size(alloc_device_t* dev, int w, int h, int for int gpu_context_t::gralloc_free(alloc_device_t* dev, - buffer_handle_t handle) + buffer_handle_t handle) { if (private_handle_t::validate(handle) < 0) return -EINVAL; diff --git a/libgralloc/gpu.h b/libgralloc/gpu.h index 301c411..487f4d1 100644 --- a/libgralloc/gpu.h +++ b/libgralloc/gpu.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project - * Copyright (c) 2011 Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,54 +28,51 @@ #include #include "gralloc_priv.h" +#include namespace gralloc { - class IAllocController; - class gpu_context_t : public alloc_device_t { - public: - gpu_context_t(const private_module_t* module, - android::spalloc_ctrl); +class IAllocController; +class gpu_context_t : public alloc_device_t { + public: + gpu_context_t(const private_module_t* module, + android::spalloc_ctrl); - int gralloc_alloc_framebuffer_locked(size_t size, int usage, - buffer_handle_t* pHandle); + int gralloc_alloc_framebuffer_locked(size_t size, int usage, + buffer_handle_t* pHandle); - int gralloc_alloc_framebuffer(size_t size, int usage, - buffer_handle_t* pHandle); + int gralloc_alloc_framebuffer(size_t size, int usage, + buffer_handle_t* pHandle); - int gralloc_alloc_buffer(size_t size, int usage, - buffer_handle_t* pHandle, - int bufferType, int format, - int width, int height); + int gralloc_alloc_buffer(size_t size, int usage, + buffer_handle_t* pHandle, + int bufferType, int format, + int width, int height); - int free_impl(private_handle_t const* hnd); + int free_impl(private_handle_t const* hnd); - int alloc_impl(int w, int h, int format, int usage, - buffer_handle_t* pHandle, int* pStride, - size_t bufferSize = 0); + int alloc_impl(int w, int h, int format, int usage, + buffer_handle_t* pHandle, int* pStride, + size_t bufferSize = 0); - static int gralloc_alloc(alloc_device_t* dev, int w, int h, - int format, int usage, - buffer_handle_t* pHandle, - int* pStride); + static int gralloc_alloc(alloc_device_t* dev, int w, int h, + int format, int usage, + buffer_handle_t* pHandle, + int* pStride); - static int gralloc_free(alloc_device_t* dev, buffer_handle_t handle); + static int gralloc_free(alloc_device_t* dev, buffer_handle_t handle); - static int gralloc_alloc_size(alloc_device_t* dev, - int w, int h, int format, - int usage, buffer_handle_t* pHandle, - int* pStride, int bufferSize); + static int gralloc_alloc_size(alloc_device_t* dev, + int w, int h, int format, + int usage, buffer_handle_t* pHandle, + int* pStride, int bufferSize); - static int gralloc_close(struct hw_device_t *dev); + static int gralloc_close(struct hw_device_t *dev); - int get_composition_type() const { return compositionType; } - - - private: - android::sp mAllocCtrl; - int compositionType; - void getGrallocInformationFromFormat(int inputFormat, - int *colorFormat, - int *bufferType); - }; + private: + android::sp mAllocCtrl; + void getGrallocInformationFromFormat(int inputFormat, + int *colorFormat, + int *bufferType); +}; } #endif // GRALLOC_GPU_H diff --git a/libgralloc/gr.h b/libgralloc/gr.h index cc36d9a..b330da9 100644 --- a/libgralloc/gr.h +++ b/libgralloc/gr.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project - * Copyright (c) 2011 Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -51,11 +51,11 @@ inline size_t ALIGN(size_t x, size_t align) { int mapFrameBufferLocked(struct private_module_t* module); int terminateBuffer(gralloc_module_t const* module, private_handle_t* hnd); size_t getBufferSizeAndDimensions(int width, int height, int format, - int& alignedw, int &alignedh); + int& alignedw, int &alignedh); int decideBufferHandlingMechanism(int format, const char *compositionUsed, - int hasBlitEngine, int *needConversion, - int *useBufferDirectly); + int hasBlitEngine, int *needConversion, + int *useBufferDirectly); // Allocate buffer from width, height, format into a private_handle_t // It is the responsibility of the caller to free the buffer @@ -66,10 +66,10 @@ void free_buffer(private_handle_t *hnd); class Locker { pthread_mutex_t mutex; -public: + public: class Autolock { Locker& locker; - public: + public: inline Autolock(Locker& locker) : locker(locker) { locker.lock(); } inline ~Autolock() { locker.unlock(); } }; diff --git a/libgralloc/gralloc.cpp b/libgralloc/gralloc.cpp index a98baf8..cf57fee 100644 --- a/libgralloc/gralloc.cpp +++ b/libgralloc/gralloc.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008, The Android Open Source Project - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,71 +36,71 @@ using namespace gralloc; using android::sp; int fb_device_open(const hw_module_t* module, const char* name, - hw_device_t** device); + hw_device_t** device); static int gralloc_device_open(const hw_module_t* module, const char* name, - hw_device_t** device); + hw_device_t** device); extern int gralloc_lock(gralloc_module_t const* module, - buffer_handle_t handle, int usage, - int l, int t, int w, int h, - void** vaddr); + buffer_handle_t handle, int usage, + int l, int t, int w, int h, + void** vaddr); extern int gralloc_unlock(gralloc_module_t const* module, - buffer_handle_t handle); + buffer_handle_t handle); extern int gralloc_register_buffer(gralloc_module_t const* module, - buffer_handle_t handle); + buffer_handle_t handle); extern int gralloc_unregister_buffer(gralloc_module_t const* module, - buffer_handle_t handle); + buffer_handle_t handle); extern int gralloc_perform(struct gralloc_module_t const* module, - int operation, ... ); + int operation, ... ); // HAL module methods static struct hw_module_methods_t gralloc_module_methods = { - open: gralloc_device_open +open: gralloc_device_open }; // HAL module initialize struct private_module_t HAL_MODULE_INFO_SYM = { - base: { - common: { - tag: HARDWARE_MODULE_TAG, - version_major: 1, - version_minor: 0, - id: GRALLOC_HARDWARE_MODULE_ID, - name: "Graphics Memory Allocator Module", - author: "The Android Open Source Project", - methods: &gralloc_module_methods, - dso: 0, - reserved: {0}, - }, - registerBuffer: gralloc_register_buffer, - unregisterBuffer: gralloc_unregister_buffer, - lock: gralloc_lock, - unlock: gralloc_unlock, - perform: gralloc_perform, - reserved_proc: {0}, - }, - framebuffer: 0, - fbFormat: 0, - flags: 0, - numBuffers: 0, - bufferMask: 0, - lock: PTHREAD_MUTEX_INITIALIZER, - currentBuffer: 0, +base: { + common: { + tag: HARDWARE_MODULE_TAG, + version_major: 1, + version_minor: 0, + id: GRALLOC_HARDWARE_MODULE_ID, + name: "Graphics Memory Allocator Module", + author: "The Android Open Source Project", + methods: &gralloc_module_methods, + dso: 0, + reserved: {0}, + }, + registerBuffer: gralloc_register_buffer, + unregisterBuffer: gralloc_unregister_buffer, + lock: gralloc_lock, + unlock: gralloc_unlock, + perform: gralloc_perform, + reserved_proc: {0}, + }, +framebuffer: 0, +fbFormat: 0, +flags: 0, +numBuffers: 0, +bufferMask: 0, +lock: PTHREAD_MUTEX_INITIALIZER, +currentBuffer: 0, }; // Open Gralloc device int gralloc_device_open(const hw_module_t* module, const char* name, - hw_device_t** device) + hw_device_t** device) { int status = -EINVAL; if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) { const private_module_t* m = reinterpret_cast( - module); + module); gpu_context_t *dev; sp alloc_ctrl = IAllocController::getInstance(true); dev = new gpu_context_t(m, alloc_ctrl); diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h index 0679621..846a611 100644 --- a/libgralloc/gralloc_priv.h +++ b/libgralloc/gralloc_priv.h @@ -28,13 +28,6 @@ #include -#include - -#if defined(__cplusplus) && defined(HDMI_DUAL_DISPLAY) -#include "overlayLib.h" -using namespace overlay; -#endif - #include enum { @@ -87,6 +80,14 @@ enum { * other EXTERNAL_ONLY buffers are available. Used during suspend. */ GRALLOC_USAGE_EXTERNAL_BLOCK = 0x00020000, + + /* Use this flag to request content protected buffers. Please note + * that this flag is different from the GRALLOC_USAGE_PROTECTED flag + * which can be used for buffers that are not secured for DRM + * but still need to be protected from screen captures + * 0x00040000 is reserved and these values are subject to change. + */ + GRALLOC_USAGE_PRIVATE_CP_BUFFER = 0x00080000, }; enum { @@ -96,107 +97,12 @@ enum { }; -enum { - GPU_COMPOSITION, - C2D_COMPOSITION, - MDP_COMPOSITION, - CPU_COMPOSITION, -}; - -/* numbers of max buffers for page flipping */ -#define NUM_FRAMEBUFFERS_MIN 2 -#define NUM_FRAMEBUFFERS_MAX 3 - -/* number of default bufers for page flipping */ -#define NUM_DEF_FRAME_BUFFERS 2 -#define NO_SURFACEFLINGER_SWAPINTERVAL #define INTERLACE_MASK 0x80 #define S3D_FORMAT_MASK 0xFF000 -#define COLOR_FORMAT(x) (x & 0xFFF) // Max range for colorFormats is 0 - FFF #define DEVICE_PMEM "/dev/pmem" #define DEVICE_PMEM_ADSP "/dev/pmem_adsp" #define DEVICE_PMEM_SMIPOOL "/dev/pmem_smipool" /*****************************************************************************/ -#ifdef __cplusplus - -//XXX: Remove framebuffer specific classes and defines to a different header -template -struct Node -{ - T data; - Node *next; -}; - -template -class Queue -{ -public: - Queue(): front(NULL), back(NULL), len(0) {dummy = new T;} - ~Queue() - { - clear(); - delete dummy; - } - void push(const T& item) //add an item to the back of the queue - { - if(len != 0) { //if the queue is not empty - back->next = new Node; //create a new node - back = back->next; //set the new node as the back node - back->data = item; - back->next = NULL; - } else { - back = new Node; - back->data = item; - back->next = NULL; - front = back; - } - len++; - } - void pop() //remove the first item from the queue - { - if (isEmpty()) - return; //if the queue is empty, no node to dequeue - T item = front->data; - Node *tmp = front; - front = front->next; - delete tmp; - if(front == NULL) //if the queue is empty, update the back pointer - back = NULL; - len--; - return; - } - T& getHeadValue() const //return the value of the first item in the queue - { //without modification to the structure - if (isEmpty()) { - ALOGE("Error can't get head of empty queue"); - return *dummy; - } - return front->data; - } - - bool isEmpty() const //returns true if no elements are in the queue - { - return (front == NULL); - } - - size_t size() const //returns the amount of elements in the queue - { - return len; - } - -private: - Node *front; - Node *back; - size_t len; - void clear() - { - while (!isEmpty()) - pop(); - } - T *dummy; -}; -#endif - enum { /* OEM specific HAL formats */ HAL_PIXEL_FORMAT_NV12_ENCODEABLE = 0x102, @@ -206,6 +112,8 @@ enum { HAL_PIXEL_FORMAT_YCrCb_422_SP = 0x10B, HAL_PIXEL_FORMAT_R_8 = 0x10D, HAL_PIXEL_FORMAT_RG_88 = 0x10E, + HAL_PIXEL_FORMAT_YCbCr_444_SP = 0x10F, + HAL_PIXEL_FORMAT_YCrCb_444_SP = 0x110, HAL_PIXEL_FORMAT_INTERLACE = 0x180, }; @@ -224,89 +132,8 @@ enum { }; enum { - BUFFER_TYPE_UI = 0, - BUFFER_TYPE_VIDEO -}; - -#if defined(HDMI_DUAL_DISPLAY) -enum hdmi_mirroring_state { - HDMI_NO_MIRRORING, - HDMI_UI_MIRRORING, - HDMI_ORIGINAL_RESOLUTION_MIRRORING -}; -#endif -/*****************************************************************************/ - -struct private_module_t; -struct private_handle_t; -struct PmemAllocator; - -struct qbuf_t { - buffer_handle_t buf; - int idx; -}; - -enum buf_state { - SUB, - REF, - AVL -}; - -struct avail_t { - pthread_mutex_t lock; - pthread_cond_t cond; -#ifdef __cplusplus - bool is_avail; - buf_state state; -#endif -}; - -struct private_module_t { - gralloc_module_t base; - - struct private_handle_t* framebuffer; - uint32_t fbFormat; - uint32_t flags; - uint32_t numBuffers; - uint32_t bufferMask; - pthread_mutex_t lock; - buffer_handle_t currentBuffer; - - struct fb_var_screeninfo info; - struct fb_fix_screeninfo finfo; - float xdpi; - float ydpi; - float fps; - int swapInterval; -#ifdef __cplusplus - Queue disp; // non-empty when buffer is ready for display -#endif - int currentIdx; - struct avail_t avail[NUM_FRAMEBUFFERS_MAX]; - pthread_mutex_t qlock; - pthread_cond_t qpost; - - enum { - // flag to indicate we'll post this buffer - PRIV_USAGE_LOCKED_FOR_POST = 0x80000000, - PRIV_MIN_SWAP_INTERVAL = 0, - PRIV_MAX_SWAP_INTERVAL = 1, - }; -#if defined(__cplusplus) && defined(HDMI_DUAL_DISPLAY) - Overlay* pobjOverlay; - int orientation; - bool videoOverlay; - uint32_t currentOffset; - int enableHDMIOutput; // holds the type of external display - bool trueMirrorSupport; - bool exitHDMIUILoop; - float actionsafeWidthRatio; - float actionsafeHeightRatio; - bool hdmiStateChanged; - hdmi_mirroring_state hdmiMirroringState; - pthread_mutex_t overlayLock; - pthread_cond_t overlayPost; -#endif + BUFFER_TYPE_UI = 0, + BUFFER_TYPE_VIDEO }; /*****************************************************************************/ @@ -314,87 +141,114 @@ struct private_module_t { #ifdef __cplusplus struct private_handle_t : public native_handle { #else -struct private_handle_t { - native_handle_t nativeHandle; + struct private_handle_t { + native_handle_t nativeHandle; #endif - enum { - PRIV_FLAGS_FRAMEBUFFER = 0x00000001, - PRIV_FLAGS_USES_PMEM = 0x00000002, - PRIV_FLAGS_USES_PMEM_ADSP = 0x00000004, - PRIV_FLAGS_USES_ION = 0x00000008, - PRIV_FLAGS_USES_ASHMEM = 0x00000010, - PRIV_FLAGS_NEEDS_FLUSH = 0x00000020, - PRIV_FLAGS_DO_NOT_FLUSH = 0x00000040, - PRIV_FLAGS_SW_LOCK = 0x00000080, - PRIV_FLAGS_NONCONTIGUOUS_MEM = 0x00000100, - PRIV_FLAGS_HWC_LOCK = 0x00000200, // Set by HWC when storing the handle - PRIV_FLAGS_SECURE_BUFFER = 0x00000400, - PRIV_FLAGS_UNSYNCHRONIZED = 0x00000800, // For explicit synchronization - PRIV_FLAGS_NOT_MAPPED = 0x00001000, // Not mapped in userspace - PRIV_FLAGS_EXTERNAL_ONLY = 0x00002000, // Display on external only - PRIV_FLAGS_EXTERNAL_BLOCK = 0x00004000, // Display only this buffer on external - }; + enum { + PRIV_FLAGS_FRAMEBUFFER = 0x00000001, + PRIV_FLAGS_USES_PMEM = 0x00000002, + PRIV_FLAGS_USES_PMEM_ADSP = 0x00000004, + PRIV_FLAGS_USES_ION = 0x00000008, + PRIV_FLAGS_USES_ASHMEM = 0x00000010, + PRIV_FLAGS_NEEDS_FLUSH = 0x00000020, + PRIV_FLAGS_DO_NOT_FLUSH = 0x00000040, + PRIV_FLAGS_SW_LOCK = 0x00000080, + PRIV_FLAGS_NONCONTIGUOUS_MEM = 0x00000100, + // Set by HWC when storing the handle + PRIV_FLAGS_HWC_LOCK = 0x00000200, + PRIV_FLAGS_SECURE_BUFFER = 0x00000400, + // For explicit synchronization + PRIV_FLAGS_UNSYNCHRONIZED = 0x00000800, + // Not mapped in userspace + PRIV_FLAGS_NOT_MAPPED = 0x00001000, + // Display on external only + PRIV_FLAGS_EXTERNAL_ONLY = 0x00002000, + // Display only this buffer on external + PRIV_FLAGS_EXTERNAL_BLOCK = 0x00004000, + }; - // file-descriptors - int fd; - int genlockHandle; // genlock handle to be dup'd by the binder - // ints - int magic; - int flags; - int size; - int offset; - int bufferType; - - // FIXME: the attributes below should be out-of-line - int base; - int gpuaddr; // The gpu address mapped into the mmu. If using ashmem, set to 0 They don't care - int pid; - int format; - int width; - int height; - int genlockPrivFd; // local fd of the genlock device. + // file-descriptors + int fd; + // genlock handle to be dup'd by the binder + int genlockHandle; + // ints + int magic; + int flags; + int size; + int offset; + int bufferType; + int base; + // The gpu address mapped into the mmu. + // If using ashmem, set to 0, they don't care + int gpuaddr; + int pid; + int format; + int width; + int height; + // local fd of the genlock device. + int genlockPrivFd; #ifdef __cplusplus - static const int sNumInts = 12; - static const int sNumFds = 2; - static const int sMagic = 'gmsm'; + static const int sNumInts = 12; + static const int sNumFds = 2; + static const int sMagic = 'gmsm'; - private_handle_t(int fd, int size, int flags, int bufferType, int format, int width, int height) : - fd(fd), genlockHandle(-1), magic(sMagic), flags(flags), size(size), offset(0), - bufferType(bufferType), base(0), gpuaddr(0), pid(getpid()), format(format), - width(width), height(height), genlockPrivFd(-1) - { - version = sizeof(native_handle); - numInts = sNumInts; - numFds = sNumFds; - } - ~private_handle_t() { - magic = 0; - } + private_handle_t(int fd, int size, int flags, int bufferType, + int format,int width, int height) : + fd(fd), genlockHandle(-1), magic(sMagic), + flags(flags), size(size), offset(0), + bufferType(bufferType), base(0), gpuaddr(0), + pid(getpid()), format(format), + width(width), height(height), genlockPrivFd(-1) + { + version = sizeof(native_handle); + numInts = sNumInts; + numFds = sNumFds; + } + ~private_handle_t() { + magic = 0; + } - bool usesPhysicallyContiguousMemory() { - return (flags & PRIV_FLAGS_USES_PMEM) != 0; - } + bool usesPhysicallyContiguousMemory() { + return (flags & PRIV_FLAGS_USES_PMEM) != 0; + } - static int validate(const native_handle* h) { - const private_handle_t* hnd = (const private_handle_t*)h; - if (!h || h->version != sizeof(native_handle) || + static int validate(const native_handle* h) { + const private_handle_t* hnd = (const private_handle_t*)h; + if (!h || h->version != sizeof(native_handle) || h->numInts != sNumInts || h->numFds != sNumFds || hnd->magic != sMagic) - { - ALOGE("invalid gralloc handle (at %p)", h); - return -EINVAL; + { + ALOGD("Invalid gralloc handle (at %p): " + "ver(%d/%d) ints(%d/%d) fds(%d/%d) magic(%c%c%c%c/%c%c%c%c)", + h, + h ? h->version : -1, sizeof(native_handle), + h ? h->numInts : -1, sNumInts, + h ? h->numFds : -1, sNumFds, + hnd ? (((hnd->magic >> 24) & 0xFF)? + ((hnd->magic >> 24) & 0xFF) : '-') : '?', + hnd ? (((hnd->magic >> 16) & 0xFF)? + ((hnd->magic >> 16) & 0xFF) : '-') : '?', + hnd ? (((hnd->magic >> 8) & 0xFF)? + ((hnd->magic >> 8) & 0xFF) : '-') : '?', + hnd ? (((hnd->magic >> 0) & 0xFF)? + ((hnd->magic >> 0) & 0xFF) : '-') : '?', + (sMagic >> 24) & 0xFF, + (sMagic >> 16) & 0xFF, + (sMagic >> 8) & 0xFF, + (sMagic >> 0) & 0xFF); + return -EINVAL; + } + return 0; } - return 0; - } - static private_handle_t* dynamicCast(const native_handle* in) { - if (validate(in) == 0) { - return (private_handle_t*) in; + static private_handle_t* dynamicCast(const native_handle* in) { + if (validate(in) == 0) { + return (private_handle_t*) in; + } + return NULL; } - return NULL; - } #endif -}; + }; #endif /* GRALLOC_PRIV_H_ */ diff --git a/libgralloc/ionalloc.cpp b/libgralloc/ionalloc.cpp index 9ff0a5e..7c8fbf4 100644 --- a/libgralloc/ionalloc.cpp +++ b/libgralloc/ionalloc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, 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 @@ -48,7 +48,7 @@ int IonAlloc::open_device() if(mIonFd < 0 ) { ALOGE("%s: Failed to open ion device - %s", - __FUNCTION__, strerror(errno)); + __FUNCTION__, strerror(errno)); mIonFd = FD_INIT; return -errno; } @@ -64,6 +64,7 @@ void IonAlloc::close_device() int IonAlloc::alloc_buffer(alloc_data& data) { + Locker::Autolock _l(mLock); int err = 0; int ionSyncFd = FD_INIT; int iFd = FD_INIT; @@ -84,12 +85,11 @@ int IonAlloc::alloc_buffer(alloc_data& data) if(data.uncached) { // Use the sync FD to alloc and map // when we need uncached memory - // FIX: О–DSYNC defined to open uncached - add that in kernel - //ionSyncFd = open(ION_DEVICE, O_RDONLY|O_DSYNC); - ionSyncFd = open(ION_DEVICE, O_RDONLY); + // XXX: Change O_SYNC to O_DSYNC when available in bionic + ionSyncFd = open(ION_DEVICE, O_RDONLY|O_SYNC); if(ionSyncFd < 0) { ALOGE("%s: Failed to open ion device - %s", - __FUNCTION__, strerror(errno)); + __FUNCTION__, strerror(errno)); return -errno; } iFd = ionSyncFd; @@ -111,7 +111,7 @@ int IonAlloc::alloc_buffer(alloc_data& data) if(ioctl(iFd, ION_IOC_MAP, &fd_data)) { err = -errno; ALOGE("%s: ION_IOC_MAP failed with error - %s", - __FUNCTION__, strerror(errno)); + __FUNCTION__, strerror(errno)); ioctl(mIonFd, ION_IOC_FREE, &handle_data); if(ionSyncFd >= 0) close(ionSyncFd); @@ -119,15 +119,15 @@ int IonAlloc::alloc_buffer(alloc_data& data) return err; } - //if(!(data.flags & ION_SECURE) && - if(!(data.allocType & private_handle_t::PRIV_FLAGS_NOT_MAPPED)) { + if(!(data.flags & ION_SECURE) && + !(data.allocType & private_handle_t::PRIV_FLAGS_NOT_MAPPED)) { base = mmap(0, ionAllocData.len, PROT_READ|PROT_WRITE, - MAP_SHARED, fd_data.fd, 0); + MAP_SHARED, fd_data.fd, 0); if(base == MAP_FAILED) { err = -errno; ALOGE("%s: Failed to map the allocated memory: %s", - __FUNCTION__, strerror(errno)); + __FUNCTION__, strerror(errno)); ioctl(mIonFd, ION_IOC_FREE, &handle_data); ionSyncFd = FD_INIT; return err; @@ -146,15 +146,16 @@ int IonAlloc::alloc_buffer(alloc_data& data) data.fd = fd_data.fd; ioctl(mIonFd, ION_IOC_FREE, &handle_data); ALOGD("ion: Allocated buffer base:%p size:%d fd:%d", - data.base, ionAllocData.len, data.fd); + data.base, ionAllocData.len, data.fd); return 0; } int IonAlloc::free_buffer(void* base, size_t size, int offset, int fd) { + Locker::Autolock _l(mLock); ALOGD("ion: Freeing buffer base:%p size:%d fd:%d", - base, size, fd); + base, size, fd); int err = 0; err = open_device(); if (err) @@ -177,15 +178,15 @@ int IonAlloc::map_buffer(void **pBase, size_t size, int offset, int fd) return err; base = mmap(0, size, PROT_READ| PROT_WRITE, - MAP_SHARED, fd, 0); + MAP_SHARED, fd, 0); *pBase = base; if(base == MAP_FAILED) { err = -errno; ALOGD("ion: Failed to map memory in the client: %s", - strerror(errno)); + strerror(errno)); } else { ALOGD("ion: Mapped buffer base:%p size:%d offset:%d fd:%d", - base, size, offset, fd); + base, size, offset, fd); } return err; } @@ -197,7 +198,7 @@ int IonAlloc::unmap_buffer(void *base, size_t size, int offset) if(munmap(base, size)) { err = -errno; ALOGE("ion: Failed to unmap memory at %p : %s", - base, strerror(errno)); + base, strerror(errno)); } return err; @@ -218,7 +219,7 @@ int IonAlloc::clean_buffer(void *base, size_t size, int offset, int fd) if (ioctl(mIonFd, ION_IOC_IMPORT, &fd_data)) { err = -errno; ALOGE("%s: ION_IOC_IMPORT failed with error - %s", - __FUNCTION__, strerror(errno)); + __FUNCTION__, strerror(errno)); return err; } @@ -230,7 +231,7 @@ int IonAlloc::clean_buffer(void *base, size_t size, int offset, int fd) if(ioctl(mIonFd, ION_IOC_CLEAN_INV_CACHES, &flush_data)) { err = -errno; ALOGE("%s: ION_IOC_CLEAN_INV_CACHES failed with error - %s", - __FUNCTION__, strerror(errno)); + __FUNCTION__, strerror(errno)); ioctl(mIonFd, ION_IOC_FREE, &handle_data); return err; } diff --git a/libgralloc/ionalloc.h b/libgralloc/ionalloc.h index be26cd7..083f106 100644 --- a/libgralloc/ionalloc.h +++ b/libgralloc/ionalloc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, 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 @@ -31,39 +31,44 @@ #define GRALLOC_IONALLOC_H #include "memalloc.h" +#include "gr.h" +//#include +//XXX: Move to bionic #include "ion_msm.h" namespace gralloc { - class IonAlloc : public IMemAlloc { +class IonAlloc : public IMemAlloc { - public: - virtual int alloc_buffer(alloc_data& data); + public: + virtual int alloc_buffer(alloc_data& data); - virtual int free_buffer(void *base, size_t size, - int offset, int fd); + virtual int free_buffer(void *base, size_t size, + int offset, int fd); - virtual int map_buffer(void **pBase, size_t size, - int offset, int fd); + virtual int map_buffer(void **pBase, size_t size, + int offset, int fd); - virtual int unmap_buffer(void *base, size_t size, - int offset); + virtual int unmap_buffer(void *base, size_t size, + int offset); - virtual int clean_buffer(void*base, size_t size, - int offset, int fd); + virtual int clean_buffer(void*base, size_t size, + int offset, int fd); - IonAlloc() { mIonFd = FD_INIT; } + IonAlloc() { mIonFd = FD_INIT; } - ~IonAlloc() { close_device(); } + ~IonAlloc() { close_device(); } - private: - int mIonFd; + private: + int mIonFd; - int open_device(); + int open_device(); - void close_device(); + void close_device(); - }; + mutable Locker mLock; + +}; } diff --git a/libgralloc/mapper.cpp b/libgralloc/mapper.cpp old mode 100755 new mode 100644 index c7ee7d4..4249f3f --- a/libgralloc/mapper.cpp +++ b/libgralloc/mapper.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 The Android Open Source Project - * Copyright (c) 2011 Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,8 +58,8 @@ static sp getAllocator(int flags) } static int gralloc_map(gralloc_module_t const* module, - buffer_handle_t handle, - void** vaddr) + buffer_handle_t handle, + void** vaddr) { private_handle_t* hnd = (private_handle_t*)handle; void *mappedAddress; @@ -68,22 +68,22 @@ static int gralloc_map(gralloc_module_t const* module, size_t size = hnd->size; sp memalloc = getAllocator(hnd->flags) ; int err = memalloc->map_buffer(&mappedAddress, size, - hnd->offset, hnd->fd); + hnd->offset, hnd->fd); if(err) { ALOGE("Could not mmap handle %p, fd=%d (%s)", - handle, hnd->fd, strerror(errno)); + handle, hnd->fd, strerror(errno)); hnd->base = 0; return -errno; } if (mappedAddress == MAP_FAILED) { ALOGE("Could not mmap handle %p, fd=%d (%s)", - handle, hnd->fd, strerror(errno)); + handle, hnd->fd, strerror(errno)); hnd->base = 0; return -errno; } hnd->base = intptr_t(mappedAddress) + hnd->offset; - //ALOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p", + //LOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p", // hnd->fd, hnd->offset, hnd->size, mappedAddress); } *vaddr = (void*)hnd->base; @@ -91,7 +91,7 @@ static int gralloc_map(gralloc_module_t const* module, } static int gralloc_unmap(gralloc_module_t const* module, - buffer_handle_t handle) + buffer_handle_t handle) { private_handle_t* hnd = (private_handle_t*)handle; if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) { @@ -116,7 +116,7 @@ static pthread_mutex_t sMapLock = PTHREAD_MUTEX_INITIALIZER; /*****************************************************************************/ int gralloc_register_buffer(gralloc_module_t const* module, - buffer_handle_t handle) + buffer_handle_t handle) { if (private_handle_t::validate(handle) < 0) return -EINVAL; @@ -164,7 +164,7 @@ int gralloc_register_buffer(gralloc_module_t const* module, } int gralloc_unregister_buffer(gralloc_module_t const* module, - buffer_handle_t handle) + buffer_handle_t handle) { if (private_handle_t::validate(handle) < 0) return -EINVAL; @@ -195,7 +195,7 @@ int gralloc_unregister_buffer(gralloc_module_t const* module, } int terminateBuffer(gralloc_module_t const* module, - private_handle_t* hnd) + private_handle_t* hnd) { /* * If the buffer has been mapped during a lock operation, it's time @@ -215,7 +215,8 @@ int terminateBuffer(gralloc_module_t const* module, gralloc_unmap(module, hnd); } } else { - ALOGE("terminateBuffer: unmapping a non pmem/ashmem buffer flags = 0x%x", hnd->flags); + ALOGE("terminateBuffer: unmapping a non pmem/ashmem buffer flags = 0x%x", + hnd->flags); gralloc_unmap(module, hnd); } } @@ -224,9 +225,9 @@ int terminateBuffer(gralloc_module_t const* module, } int gralloc_lock(gralloc_module_t const* module, - buffer_handle_t handle, int usage, - int l, int t, int w, int h, - void** vaddr) + buffer_handle_t handle, int usage, + int l, int t, int w, int h, + void** vaddr) { if (private_handle_t::validate(handle) < 0) return -EINVAL; @@ -254,10 +255,10 @@ int gralloc_lock(gralloc_module_t const* module, int timeout = GENLOCK_MAX_TIMEOUT; if (GENLOCK_NO_ERROR != genlock_lock_buffer((native_handle_t *)handle, - (genlock_lock_type)lockType, - timeout)) { + (genlock_lock_type)lockType, + timeout)) { ALOGE("%s: genlock_lock_buffer (lockType=0x%x) failed", __FUNCTION__, - lockType); + lockType); return -EINVAL; } else { // Mark this buffer as locked for SW read/write operation. @@ -274,7 +275,7 @@ int gralloc_lock(gralloc_module_t const* module, } int gralloc_unlock(gralloc_module_t const* module, - buffer_handle_t handle) + buffer_handle_t handle) { if (private_handle_t::validate(handle) < 0) return -EINVAL; @@ -285,9 +286,9 @@ int gralloc_unlock(gralloc_module_t const* module, int err; sp memalloc = getAllocator(hnd->flags) ; err = memalloc->clean_buffer((void*)hnd->base, - hnd->size, hnd->offset, hnd->fd); + hnd->size, hnd->offset, hnd->fd); ALOGE_IF(err < 0, "cannot flush handle %p (offs=%x len=%x, flags = 0x%x) err=%s\n", - hnd, hnd->offset, hnd->size, hnd->flags, strerror(errno)); + hnd, hnd->offset, hnd->size, hnd->flags, strerror(errno)); hnd->flags &= ~private_handle_t::PRIV_FLAGS_NEEDS_FLUSH; } @@ -305,7 +306,7 @@ int gralloc_unlock(gralloc_module_t const* module, /*****************************************************************************/ int gralloc_perform(struct gralloc_module_t const* module, - int operation, ... ) + int operation, ... ) { int res = -EINVAL; va_list args; @@ -324,12 +325,12 @@ int gralloc_perform(struct gralloc_module_t const* module, native_handle_t** handle = va_arg(args, native_handle_t**); int memoryFlags = va_arg(args, int); private_handle_t* hnd = (private_handle_t*)native_handle_create( - private_handle_t::sNumFds, private_handle_t::sNumInts); + private_handle_t::sNumFds, private_handle_t::sNumInts); hnd->magic = private_handle_t::sMagic; hnd->fd = fd; unsigned int contigFlags = GRALLOC_USAGE_PRIVATE_ADSP_HEAP | - GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP | - GRALLOC_USAGE_PRIVATE_SMI_HEAP; + GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP | + GRALLOC_USAGE_PRIVATE_SMI_HEAP; if (memoryFlags & contigFlags) { // check if the buffer is a pmem buffer @@ -338,7 +339,7 @@ int gralloc_perform(struct gralloc_module_t const* module, hnd->flags = private_handle_t::PRIV_FLAGS_USES_ION; else hnd->flags = private_handle_t::PRIV_FLAGS_USES_PMEM | - private_handle_t::PRIV_FLAGS_DO_NOT_FLUSH; + private_handle_t::PRIV_FLAGS_DO_NOT_FLUSH; } else { if (memoryFlags & GRALLOC_USAGE_PRIVATE_ION) hnd->flags = private_handle_t::PRIV_FLAGS_USES_ION; diff --git a/libgralloc/memalloc.h b/libgralloc/memalloc.h index 13a54e7..349078d 100644 --- a/libgralloc/memalloc.h +++ b/libgralloc/memalloc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, 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 @@ -35,50 +35,50 @@ namespace gralloc { - struct alloc_data { - void *base; - int fd; - int offset; - size_t size; - size_t align; - unsigned int pHandle; - bool uncached; - unsigned int flags; - int allocType; +struct alloc_data { + void *base; + int fd; + int offset; + size_t size; + size_t align; + unsigned int pHandle; + bool uncached; + unsigned int flags; + int allocType; +}; + +class IMemAlloc : public android::RefBase { + + public: + // Allocate buffer - fill in the alloc_data + // structure and pass it in. Mapped address + // and fd are returned in the alloc_data struct + virtual int alloc_buffer(alloc_data& data) = 0; + + // Free buffer + virtual int free_buffer(void *base, size_t size, + int offset, int fd) = 0; + + // Map buffer + virtual int map_buffer(void **pBase, size_t size, + int offset, int fd) = 0; + + // Unmap buffer + virtual int unmap_buffer(void *base, size_t size, + int offset) = 0; + + // Clean and invalidate + virtual int clean_buffer(void *base, size_t size, + int offset, int fd) = 0; + + // Destructor + virtual ~IMemAlloc() {}; + + enum { + FD_INIT = -1, }; - class IMemAlloc : public android::RefBase { - - public: - // Allocate buffer - fill in the alloc_data - // structure and pass it in. Mapped address - // and fd are returned in the alloc_data struct - virtual int alloc_buffer(alloc_data& data) = 0; - - // Free buffer - virtual int free_buffer(void *base, size_t size, - int offset, int fd) = 0; - - // Map buffer - virtual int map_buffer(void **pBase, size_t size, - int offset, int fd) = 0; - - // Unmap buffer - virtual int unmap_buffer(void *base, size_t size, - int offset) = 0; - - // Clean and invalidate - virtual int clean_buffer(void *base, size_t size, - int offset, int fd) = 0; - - // Destructor - virtual ~IMemAlloc() {}; - - enum { - FD_INIT = -1, - }; - - }; +}; } // end gralloc namespace #endif // GRALLOC_MEMALLOC_H diff --git a/libgralloc/pmem_bestfit_alloc.cpp b/libgralloc/pmem_bestfit_alloc.cpp index e3875e9..3b91dec 100644 --- a/libgralloc/pmem_bestfit_alloc.cpp +++ b/libgralloc/pmem_bestfit_alloc.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 The Android Open Source Project - * Copyright (c) 2011 Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,12 +24,12 @@ const int SimpleBestFitAllocator::kMemoryAlign = 32; SimpleBestFitAllocator::SimpleBestFitAllocator() - : mHeapSize(0) +: mHeapSize(0) { } SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size) - : mHeapSize(0) +: mHeapSize(0) { setSize(size); } @@ -113,13 +113,13 @@ ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags) mList.insertBefore(free_chunk, split); } - LOGE_IF(((free_chunk->start*kMemoryAlign)&(pagesize-1)), - "page is not aligned!!!"); + ALOGE_IF(((free_chunk->start*kMemoryAlign)&(pagesize-1)), + "page is not aligned!!!"); const ssize_t tail_free = free_size - (size+extra); if (tail_free > 0) { chunk_t* split = new chunk_t( - free_chunk->start + free_chunk->size, tail_free); + free_chunk->start + free_chunk->size, tail_free); mList.insertAfter(free_chunk, split); } } @@ -128,33 +128,33 @@ ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags) // we are out of PMEM. Print pmem stats // check if there is any leak or fragmentation - LOGD (" Out of PMEM. Dumping PMEM stats for debugging"); - LOGD (" ------------- PRINT PMEM STATS --------------"); + ALOGD (" Out of PMEM. Dumping PMEM stats for debugging"); + ALOGD (" ------------- PRINT PMEM STATS --------------"); cur = mList.head(); static uint32_t node_count; static uint64_t allocated, free_space; while (cur) { - LOGD (" Node %d -> Start Address : %u Size %u Free info %d",\ - node_count++, cur->start, cur->size, cur->free); + ALOGD (" Node %d -> Start Address : %u Size %u Free info %d",\ + node_count++, cur->start, cur->size, cur->free); - // if cur-> free is 1 , the node is free - // calculate the total allocated and total free stats also + // if cur-> free is 1 , the node is free + // calculate the total allocated and total free stats also - if (cur->free) - free_space += cur->size; - else - allocated += cur->size; - // read next node - cur = cur->next; + if (cur->free) + free_space += cur->size; + else + allocated += cur->size; + // read next node + cur = cur->next; } - LOGD (" Total Allocated: %l Total Free: %l", allocated, free_space ); + ALOGD (" Total Allocated: %l Total Free: %l", allocated, free_space ); node_count = 0; allocated = 0; free_space = 0; - LOGD ("----------------------------------------------"); + ALOGD ("----------------------------------------------"); return -ENOMEM; } @@ -164,9 +164,9 @@ SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start) chunk_t* cur = mList.head(); while (cur) { if (cur->start == start) { - LOG_FATAL_IF(cur->free, - "block at offset 0x%08lX of size 0x%08lX already freed", - cur->start*kMemoryAlign, cur->size*kMemoryAlign); + ALOG_FATAL_IF(cur->free, + "block at offset 0x%08lX of size 0x%08lX already freed", + cur->start*kMemoryAlign, cur->size*kMemoryAlign); // merge freed blocks together chunk_t* freed = cur; @@ -183,9 +183,9 @@ SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start) cur = n; } while (cur && cur->free); - LOG_FATAL_IF(!freed->free, - "freed block at offset 0x%08lX of size 0x%08lX is not free!", - freed->start * kMemoryAlign, freed->size * kMemoryAlign); + ALOG_FATAL_IF(!freed->free, + "freed block at offset 0x%08lX of size 0x%08lX is not free!", + freed->start * kMemoryAlign, freed->size * kMemoryAlign); return freed; } diff --git a/libgralloc/pmem_bestfit_alloc.h b/libgralloc/pmem_bestfit_alloc.h index 2ea8452..4346ec3 100644 --- a/libgralloc/pmem_bestfit_alloc.h +++ b/libgralloc/pmem_bestfit_alloc.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 The Android Open Source Project - * Copyright (c) 2011 Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,8 +36,8 @@ class LinkedList NODE* mFirst; NODE* mLast; -public: - LinkedList() : mFirst(0), mLast(0) { } + public: + LinkedList() : mFirst(0), mLast(0) { } bool isEmpty() const { return mFirst == 0; } NODE const* head() const { return mFirst; } NODE* head() { return mFirst; } @@ -53,11 +53,11 @@ public: } void insertBefore(NODE* node, NODE* newNode) { - newNode->prev = node->prev; - newNode->next = node; - if (node->prev == 0) mFirst = newNode; - else node->prev->next = newNode; - node->prev = newNode; + newNode->prev = node->prev; + newNode->next = node; + if (node->prev == 0) mFirst = newNode; + else node->prev->next = newNode; + node->prev = newNode; } void insertHead(NODE* newNode) { @@ -94,36 +94,36 @@ public: class SimpleBestFitAllocator : public gralloc::PmemUserspaceAlloc::Allocator { -public: + public: - SimpleBestFitAllocator(); - SimpleBestFitAllocator(size_t size); - virtual ~SimpleBestFitAllocator(); + SimpleBestFitAllocator(); + SimpleBestFitAllocator(size_t size); + virtual ~SimpleBestFitAllocator(); - virtual ssize_t setSize(size_t size); + virtual ssize_t setSize(size_t size); - virtual ssize_t allocate(size_t size, uint32_t flags = 0); - virtual ssize_t deallocate(size_t offset); - virtual size_t size() const; + virtual ssize_t allocate(size_t size, uint32_t flags = 0); + virtual ssize_t deallocate(size_t offset); + virtual size_t size() const; -private: - struct chunk_t { - chunk_t(size_t start, size_t size) - : start(start), size(size), free(1), prev(0), next(0) { - } - size_t start; - size_t size : 28; - int free : 4; - mutable chunk_t* prev; - mutable chunk_t* next; - }; + private: + struct chunk_t { + chunk_t(size_t start, size_t size) + : start(start), size(size), free(1), prev(0), next(0) { + } + size_t start; + size_t size : 28; + int free : 4; + mutable chunk_t* prev; + mutable chunk_t* next; + }; - ssize_t alloc(size_t size, uint32_t flags); - chunk_t* dealloc(size_t start); + ssize_t alloc(size_t size, uint32_t flags); + chunk_t* dealloc(size_t start); - static const int kMemoryAlign; - mutable Locker mLock; - LinkedList mList; - size_t mHeapSize; + static const int kMemoryAlign; + mutable Locker mLock; + LinkedList mList; + size_t mHeapSize; }; #endif /* GRALLOC_ALLOCATOR_H_ */ diff --git a/libgralloc/pmemalloc.cpp b/libgralloc/pmemalloc.cpp index ccbf127..2286fb0 100644 --- a/libgralloc/pmemalloc.cpp +++ b/libgralloc/pmemalloc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, 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 @@ -126,17 +126,17 @@ int PmemUserspaceAlloc::init_pmem_area_locked() ALOGD("%s: Total pmem size: %d", __FUNCTION__, size); if (err < 0) { ALOGE("%s: PMEM_GET_TOTAL_SIZE failed (%d), limp mode", mPmemDev, - err); + err); size = 8<<20; // 8 MiB } mAllocator->setSize(size); void* base = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, - 0); + 0); if (base == MAP_FAILED) { err = -errno; ALOGE("%s: Failed to map pmem master fd: %s", mPmemDev, - strerror(errno)); + strerror(errno)); base = 0; close(fd); fd = -1; @@ -147,7 +147,7 @@ int PmemUserspaceAlloc::init_pmem_area_locked() } else { err = -errno; ALOGE("%s: Failed to open pmem device: %s", mPmemDev, - strerror(errno)); + strerror(errno)); } return err; } @@ -203,13 +203,13 @@ int PmemUserspaceAlloc::alloc_buffer(alloc_data& data) if (err < 0) { ALOGE("%s: Failed to initialize pmem sub-heap: %d", mPmemDev, - err); + err); close(fd); mAllocator->deallocate(offset); fd = -1; } else { ALOGD("%s: Allocated buffer base:%p size:%d offset:%d fd:%d", - mPmemDev, base, size, offset, fd); + mPmemDev, base, size, offset, fd); memset((char*)base + offset, 0, size); //Clean cache before flushing to ensure pmem is properly flushed err = clean_buffer((void*)((intptr_t) base + offset), size, offset, fd); @@ -230,12 +230,12 @@ int PmemUserspaceAlloc::alloc_buffer(alloc_data& data) int PmemUserspaceAlloc::free_buffer(void* base, size_t size, int offset, int fd) { ALOGD("%s: Freeing buffer base:%p size:%d offset:%d fd:%d", - mPmemDev, base, size, offset, fd); + mPmemDev, base, size, offset, fd); int err = 0; if (fd >= 0) { int err = unmapSubRegion(fd, offset, size); ALOGE_IF(err<0, "PMEM_UNMAP failed (%s), fd=%d, sub.offset=%u, " - "sub.size=%u", strerror(errno), fd, offset, size); + "sub.size=%u", strerror(errno), fd, offset, size); if (err == 0) { // we can't deallocate the memory in case of UNMAP failure // because it would give that process access to someone else's @@ -252,15 +252,15 @@ int PmemUserspaceAlloc::map_buffer(void **pBase, size_t size, int offset, int fd int err = 0; size += offset; void *base = mmap(0, size, PROT_READ| PROT_WRITE, - MAP_SHARED, fd, 0); + MAP_SHARED, fd, 0); *pBase = base; if(base == MAP_FAILED) { err = -errno; ALOGE("%s: Failed to map buffer size:%d offset:%d fd:%d Error: %s", - mPmemDev, size, offset, fd, strerror(errno)); + mPmemDev, size, offset, fd, strerror(errno)); } else { ALOGD("%s: Mapped buffer base:%p size:%d offset:%d fd:%d", - mPmemDev, base, size, offset, fd); + mPmemDev, base, size, offset, fd); } return err; @@ -273,16 +273,15 @@ int PmemUserspaceAlloc::unmap_buffer(void *base, size_t size, int offset) base = (void*)(intptr_t(base) - offset); size += offset; ALOGD("%s: Unmapping buffer base:%p size:%d offset:%d", - mPmemDev , base, size, offset); + mPmemDev , base, size, offset); if (munmap(base, size) < 0) { - err = -errno; ALOGE("%s: Failed to unmap memory at %p :%s", - mPmemDev, base, strerror(errno)); + mPmemDev, base, strerror(errno)); } - return err; + return err; } int PmemUserspaceAlloc::clean_buffer(void *base, size_t size, int offset, int fd) @@ -327,7 +326,7 @@ int PmemKernelAlloc::alloc_buffer(alloc_data& data) if (base == MAP_FAILED) { err = -errno; ALOGE("%s: failed to map pmem fd: %s", mPmemDev, - strerror(errno)); + strerror(errno)); close(fd); return err; } @@ -337,7 +336,7 @@ int PmemKernelAlloc::alloc_buffer(alloc_data& data) data.offset = 0; data.fd = fd; ALOGD("%s: Allocated buffer base:%p size:%d fd:%d", - mPmemDev, base, size, fd); + mPmemDev, base, size, fd); return 0; } @@ -345,7 +344,7 @@ int PmemKernelAlloc::alloc_buffer(alloc_data& data) int PmemKernelAlloc::free_buffer(void* base, size_t size, int offset, int fd) { ALOGD("%s: Freeing buffer base:%p size:%d fd:%d", - mPmemDev, base, size, fd); + mPmemDev, base, size, fd); int err = unmap_buffer(base, size, offset); close(fd); @@ -356,15 +355,15 @@ int PmemKernelAlloc::map_buffer(void **pBase, size_t size, int offset, int fd) { int err = 0; void *base = mmap(0, size, PROT_READ| PROT_WRITE, - MAP_SHARED, fd, 0); + MAP_SHARED, fd, 0); *pBase = base; if(base == MAP_FAILED) { err = -errno; ALOGE("%s: Failed to map memory in the client: %s", - mPmemDev, strerror(errno)); + mPmemDev, strerror(errno)); } else { ALOGD("%s: Mapped buffer base:%p size:%d, fd:%d", - mPmemDev, base, size, fd); + mPmemDev, base, size, fd); } return err; @@ -376,7 +375,7 @@ int PmemKernelAlloc::unmap_buffer(void *base, size_t size, int offset) if (munmap(base, size)) { err = -errno; ALOGW("%s: Error unmapping memory at %p: %s", - mPmemDev, base, strerror(err)); + mPmemDev, base, strerror(err)); } return err; diff --git a/libgralloc/pmemalloc.h b/libgralloc/pmemalloc.h index 4aed0b1..82794ec 100644 --- a/libgralloc/pmemalloc.h +++ b/libgralloc/pmemalloc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, 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 @@ -35,72 +35,72 @@ #include "memalloc.h" namespace gralloc { - class PmemUserspaceAlloc : public IMemAlloc { +class PmemUserspaceAlloc : public IMemAlloc { + public: + class Allocator: public android::RefBase { public: - class Allocator: public android::RefBase { - public: - virtual ~Allocator() {}; - virtual ssize_t setSize(size_t size) = 0; - virtual size_t size() const = 0; - virtual ssize_t allocate(size_t size, uint32_t flags = 0) = 0; - virtual ssize_t deallocate(size_t offset) = 0; - }; - - virtual int alloc_buffer(alloc_data& data); - - virtual int free_buffer(void *base, size_t size, - int offset, int fd); - - virtual int map_buffer(void **pBase, size_t size, - int offset, int fd); - - virtual int unmap_buffer(void *base, size_t size, - int offset); - - virtual int clean_buffer(void*base, size_t size, - int offset, int fd); - - PmemUserspaceAlloc(); - - ~PmemUserspaceAlloc(); - - private: - int mMasterFd; - void* mMasterBase; - const char* mPmemDev; - android::sp mAllocator; - pthread_mutex_t mLock; - int init_pmem_area(); - int init_pmem_area_locked(); - + virtual ~Allocator() {}; + virtual ssize_t setSize(size_t size) = 0; + virtual size_t size() const = 0; + virtual ssize_t allocate(size_t size, uint32_t flags = 0) = 0; + virtual ssize_t deallocate(size_t offset) = 0; }; - class PmemKernelAlloc : public IMemAlloc { + virtual int alloc_buffer(alloc_data& data); - public: - virtual int alloc_buffer(alloc_data& data); + virtual int free_buffer(void *base, size_t size, + int offset, int fd); - virtual int free_buffer(void *base, size_t size, - int offset, int fd); + virtual int map_buffer(void **pBase, size_t size, + int offset, int fd); - virtual int map_buffer(void **pBase, size_t size, - int offset, int fd); + virtual int unmap_buffer(void *base, size_t size, + int offset); - virtual int unmap_buffer(void *base, size_t size, - int offset); + virtual int clean_buffer(void*base, size_t size, + int offset, int fd); - virtual int clean_buffer(void*base, size_t size, - int offset, int fd); + PmemUserspaceAlloc(); - PmemKernelAlloc(const char* device); + ~PmemUserspaceAlloc(); - ~PmemKernelAlloc(); - private: - const char* mPmemDev; + private: + int mMasterFd; + void* mMasterBase; + const char* mPmemDev; + android::sp mAllocator; + pthread_mutex_t mLock; + int init_pmem_area(); + int init_pmem_area_locked(); + +}; + +class PmemKernelAlloc : public IMemAlloc { + + public: + virtual int alloc_buffer(alloc_data& data); + + virtual int free_buffer(void *base, size_t size, + int offset, int fd); + + virtual int map_buffer(void **pBase, size_t size, + int offset, int fd); + + virtual int unmap_buffer(void *base, size_t size, + int offset); + + virtual int clean_buffer(void*base, size_t size, + int offset, int fd); + + PmemKernelAlloc(const char* device); + + ~PmemKernelAlloc(); + private: + const char* mPmemDev; - }; +}; } #endif /* GRALLOC_PMEMALLOC_H */ diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk index a600f97..7cb5c6f 100644 --- a/libhwcomposer/Android.mk +++ b/libhwcomposer/Android.mk @@ -1,39 +1,18 @@ LOCAL_PATH := $(call my-dir) - -# HAL module implemenation, not prelinked and stored in -# hw/..so include $(CLEAR_VARS) LOCAL_PRELINK_MODULE := false LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw -LOCAL_SHARED_LIBRARIES := liblog libcutils libEGL libhardware libutils liboverlay -LOCAL_SHARED_LIBRARIES += libgenlock libQcomUI libmemalloc - -LOCAL_SRC_FILES := \ - hwcomposer.cpp \ - external_display_only.h - +LOCAL_SHARED_LIBRARIES := liblog libcutils libhardware libutils +LOCAL_SHARED_LIBRARIES += libEGL liboverlay libgenlock +LOCAL_SRC_FILES := hwc.cpp \ + hwc_overlay.cpp \ + hwc_utils.cpp LOCAL_MODULE := hwcomposer.$(TARGET_BOARD_PLATFORM) -LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).hwcomposer\" -DDEBUG_CALC_FPS - -LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc -LOCAL_C_INCLUDES += hardware/qcom/display/liboverlay -LOCAL_C_INCLUDES += hardware/qcom/display/libcopybit +LOCAL_C_INCLUDES := hardware/qcom/display/libgralloc LOCAL_C_INCLUDES += hardware/qcom/display/libgenlock +LOCAL_C_INCLUDES += hardware/qcom/display/liboverlay LOCAL_C_INCLUDES += hardware/qcom/display/libqcomui -LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).hwcomposer\" -LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr -ifeq ($(TARGET_HAVE_HDMI_OUT),true) -LOCAL_CFLAGS += -DHDMI_DUAL_DISPLAY -endif -ifeq ($(TARGET_USES_OVERLAY),true) -LOCAL_CFLAGS += -DUSE_OVERLAY -endif -ifeq ($(TARGET_HAVE_BYPASS),true) -LOCAL_CFLAGS += -DCOMPOSITION_BYPASS -endif -ifeq ($(TARGET_USE_HDMI_AS_PRIMARY),true) -LOCAL_CFLAGS += -DHDMI_AS_PRIMARY -endif -LOCAL_MODULE_TAGS := optional eng +LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) diff --git a/libhwcomposer/external_display_only.h b/libhwcomposer/external_display_only.h deleted file mode 100644 index fa24642..0000000 --- a/libhwcomposer/external_display_only.h +++ /dev/null @@ -1,498 +0,0 @@ -/* - * Copyright (c) 2012, 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. - */ - -#define EXTDEBUG 0 -class ExtDispOnly { - - enum ExternalOnlyMode { - EXT_ONLY_MODE_OFF = 0, - EXT_ONLY_MODE_ON = 1, - }; - - enum { - MAX_EXT_ONLY_LAYERS = 2, - }; - -public: - /* Initialize, allocate data members */ - static void init(); - - /* Deallocate data members */ - static void destroy(); - - /* Closes all the overlay channels */ - static void close(); - - /* Prepare overlay and configures mdp pipes */ - static int prepare(hwc_context_t *ctx, hwc_layer_t *layer, int index, - bool waitForVsync); - - /* Returns status of external-only mode */ - static bool isModeOn(); - - /* Updates stats and pipe config related to external_only and external_block layers - * If we are staring or stopping this mode, update default mirroring. - */ - static int update(hwc_context_t* ctx, hwc_layer_list_t* list); - - /* Stores the locked handle for the buffer that was successfully queued */ - static void storeLockedHandles(hwc_layer_list_t* list); - - /* Queue buffers to mdp for display */ - static int draw(hwc_context_t *ctx, hwc_layer_list_t *list); - -private: - /* Locks a buffer and marks it as locked */ - static void lockBuffer(native_handle_t *hnd); - - /* Unlocks a buffer and clears the locked flag */ - static void unlockBuffer(native_handle_t *hnd); - - /* Unlocks buffers queued in previous round (and displayed by now) - * Clears the handle cache. - */ - static void unlockPreviousBuffers(); - - /* Closes the a range of overlay channels */ - static void closeRange(int start); - - /* Start default external mirroring */ - static void startDefaultMirror(hwc_context_t* ctx); - - /* Stop default external mirroring */ - static void stopDefaultMirror(hwc_context_t* ctx); - - /* Checks if external-only mode is starting */ - static bool isExtModeStarting(hwc_context_t* ctx, const int& - numExtLayers); - - /* Checks if external-only mode is stopping */ - static bool isExtModeStopping(hwc_context_t* ctx, const int& - numExtLayers); - - //Data members -#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY) - static overlay::OverlayUI* sOvExtUI[MAX_EXT_ONLY_LAYERS]; - static native_handle_t* sPreviousExtHandle[MAX_EXT_ONLY_LAYERS]; - static ExternalOnlyMode sExtOnlyMode; - static int sNumExtOnlyLayers; - static bool sSkipLayerPresent; - static bool sBlockLayerPresent; - static int sBlockLayerIndex; -#endif -}; //class ExtDispOnly - -void ExtDispOnly::lockBuffer(native_handle_t *hnd) { -#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY) - private_handle_t* phnd = (private_handle_t*)hnd; - - //Genlock is reference counted and recursive. - //Do not accidently lock a locked buffer. - if(phnd && (phnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK)) { - LOGE_IF(EXTDEBUG, "%s: handle %p already locked", __func__, phnd); - return; - } - if (GENLOCK_FAILURE == genlock_lock_buffer(hnd, GENLOCK_READ_LOCK, - GENLOCK_MAX_TIMEOUT)) { - LOGE("%s: genlock_lock_buffer(READ) failed", __func__); - return; - } - phnd->flags |= private_handle_t::PRIV_FLAGS_HWC_LOCK; - LOGE_IF(EXTDEBUG, "%s: locked handle = %p", __func__, hnd); -#endif -} - -void ExtDispOnly::unlockBuffer(native_handle_t *hnd) { -#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY) - //Check if buffer is still around - if(private_handle_t::validate(hnd) != 0) { - LOGE("%s Handle already deallocated", __func__); - return; - } - - private_handle_t* phnd = (private_handle_t*)hnd; - - //Check if buffer was locked in the first place - if((phnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK) == 0) { - LOGE("%s Handle not locked, cannot unlock", __func__); - return; - } - - //Actually try to unlock - if (GENLOCK_FAILURE == genlock_unlock_buffer(hnd)) { - LOGE("%s: genlock_unlock_buffer failed", __func__); - return; - } - - //Clear the locked flag - phnd->flags &= ~private_handle_t::PRIV_FLAGS_HWC_LOCK; - LOGE_IF(EXTDEBUG, "%s: unlocked handle = %p", __func__, hnd); -#endif -} - -void ExtDispOnly::unlockPreviousBuffers() { -#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY) - for(int i = 0; (i < MAX_EXT_ONLY_LAYERS) && sPreviousExtHandle[i]; i++) { - LOGE_IF(EXTDEBUG, "%s", __func__); - ExtDispOnly::unlockBuffer(sPreviousExtHandle[i]); - sPreviousExtHandle[i] = NULL; - } -#endif -} - -void ExtDispOnly::init() { -#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY) - for(int i = 0; i < MAX_EXT_ONLY_LAYERS; i++) { - sOvExtUI[i] = new overlay::OverlayUI(); - sPreviousExtHandle[i] = NULL; - } - sExtOnlyMode = EXT_ONLY_MODE_OFF; - sNumExtOnlyLayers = 0; - sSkipLayerPresent = false; - sBlockLayerPresent = false; - sBlockLayerIndex = -1; - LOGE_IF(EXTDEBUG, "%s", __func__); -#endif -} - -void ExtDispOnly::destroy() { -#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY) - for(int i = 0; i < MAX_EXT_ONLY_LAYERS; i++) { - delete sOvExtUI[i]; - } -#endif -} - -void ExtDispOnly::closeRange(int start) { -#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY) - for (int index = start; index < MAX_EXT_ONLY_LAYERS; index++) { - if(sPreviousExtHandle[index]) { - LOGE_IF(EXTDEBUG, "%s", __func__); - ExtDispOnly::unlockBuffer(sPreviousExtHandle[index]); - sPreviousExtHandle[index] = NULL; - } - sOvExtUI[index]->closeChannel(); - } -#endif -} - -void inline ExtDispOnly::close() { -#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY) - closeRange(0); -#endif -} - -int ExtDispOnly::prepare(hwc_context_t *ctx, hwc_layer_t *layer, int index, - bool waitForVsync) { -#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY) - if(ctx->mHDMIEnabled == EXT_DISPLAY_OFF || - ctx->pendingHDMI == true) - return -1; - - if (ctx && sOvExtUI[index]) { - private_hwc_module_t* hwcModule = reinterpret_cast< - private_hwc_module_t*>(ctx->device.common.module); - if (!hwcModule) { - LOGE("%s null module", __func__); - return -1; - } - private_handle_t *hnd = (private_handle_t *)layer->handle; - if(!hnd) { - LOGE("%s handle null", __func__); - return -1; - } - overlay::OverlayUI *ovUI = sOvExtUI[index]; - int ret = 0; - //int orientation = layer->transform; - //Assuming layers will always be source landscape - const int orientation = 0; - overlay_buffer_info info; - hwc_rect_t sourceCrop = layer->sourceCrop; - info.width = sourceCrop.right - sourceCrop.left; - info.height = sourceCrop.bottom - sourceCrop.top; - info.format = hnd->format; - info.size = hnd->size; - - - const int fbnum = ctx->mHDMIEnabled; //HDMI or WFD - const bool isFg = false; - //Just to differentiate zorders for different layers - const int zorder = index; - const bool isVGPipe = true; - ovUI->setSource(info, orientation); - ovUI->setDisplayParams(fbnum, waitForVsync, isFg, zorder, isVGPipe); - const int fbWidth = ovUI->getFBWidth(); - const int fbHeight = ovUI->getFBHeight(); - ovUI->setPosition(0, 0, fbWidth, fbHeight); - if(ovUI->commit() != overlay::NO_ERROR) { - LOGE("%s: Overlay Commit failed", __func__); - return -1; - } - } - LOGE_IF(EXTDEBUG, "%s", __func__); -#endif - return overlay::NO_ERROR; -} - -inline void ExtDispOnly::startDefaultMirror(hwc_context_t* ctx) { -#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY) - hwc_composer_device_t* dev = (hwc_composer_device_t*) ctx; - private_hwc_module_t* hwcModule = - reinterpret_cast(dev->common.module); - framebuffer_device_t *fbDev = hwcModule->fbDevice; - if (fbDev) { - //mHDMIEnabled could be HDMI/WFD/NO EXTERNAL - fbDev->enableHDMIOutput(fbDev, ctx->mHDMIEnabled); - } -#endif -} - -inline void ExtDispOnly::stopDefaultMirror(hwc_context_t* ctx) { -#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY) - hwc_composer_device_t* dev = (hwc_composer_device_t*) ctx; - private_hwc_module_t* hwcModule = - reinterpret_cast(dev->common.module); - framebuffer_device_t *fbDev = hwcModule->fbDevice; - if (fbDev) { - fbDev->enableHDMIOutput(fbDev, EXT_DISPLAY_OFF); - } -#endif -} - -inline bool ExtDispOnly::isExtModeStarting(hwc_context_t* ctx, const int& - numExtLayers) { -#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY) - return ((sExtOnlyMode == EXT_ONLY_MODE_OFF) && numExtLayers); -#endif - return false; -} - -inline bool ExtDispOnly::isExtModeStopping(hwc_context_t* ctx, const int& - numExtLayers) { -#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY) - return ((sExtOnlyMode == EXT_ONLY_MODE_ON) && (numExtLayers == 0)); -#endif - return false; -} - -inline bool ExtDispOnly::isModeOn() { -#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY) - return (sExtOnlyMode == EXT_ONLY_MODE_ON); -#endif - return false; -} - -int ExtDispOnly::update(hwc_context_t* ctx, hwc_layer_list_t* list) { -#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY) - int aNumExtLayers = 0; - bool aSkipLayerPresent = false; - bool aBlockLayerPresent = false; - int aBlockLayerIndex = -1; - - //Book-keeping done each cycle - for (size_t i = 0; i < list->numHwLayers; i++) { - private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; - // Dont draw in this round - if(list->hwLayers[i].flags & HWC_SKIP_LAYER) { - aSkipLayerPresent = true; - } - if(hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY)) { - aNumExtLayers++; - // No way we can let this be drawn by GPU to fb0 - if(list->hwLayers[i].flags & HWC_SKIP_LAYER) { - list->hwLayers[i].flags &= ~ HWC_SKIP_LAYER; - } - list->hwLayers[i].flags |= HWC_USE_EXT_ONLY; - list->hwLayers[i].compositionType = HWC_USE_OVERLAY; - list->hwLayers[i].hints &= ~HWC_HINT_CLEAR_FB; - //EXTERNAL_BLOCK is always an add-on - if(hnd && (hnd->flags & - private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK)) { - aBlockLayerPresent = true; - aBlockLayerIndex = i; - list->hwLayers[i].flags |= HWC_USE_EXT_BLOCK; - } - } - } - - //Update Default mirroring state - if (isExtModeStarting(ctx, aNumExtLayers)) { - stopDefaultMirror(ctx); - } else if (isExtModeStopping(ctx, aNumExtLayers)) { - startDefaultMirror(ctx); - } - - //Cache our stats - sExtOnlyMode = aNumExtLayers ? EXT_ONLY_MODE_ON : EXT_ONLY_MODE_OFF; - sNumExtOnlyLayers = aNumExtLayers; - sSkipLayerPresent = aSkipLayerPresent; - sBlockLayerPresent = aBlockLayerPresent; - sBlockLayerIndex = aBlockLayerIndex; - - LOGE_IF(EXTDEBUG, "%s: numExtLayers = %d skipLayerPresent = %d", __func__, - aNumExtLayers, aSkipLayerPresent); - //If skip layer present return. Buffers to be unlocked in draw phase. - if(aSkipLayerPresent) { - return overlay::NO_ERROR; - } - - //If External is not connected, dont setup pipes, just return - if(ctx->mHDMIEnabled == EXT_DISPLAY_OFF || - ctx->pendingHDMI == true) { - ExtDispOnly::close(); - return -1; - } - - - //Update pipes - bool waitForVsync = true; - bool index = 0; - - if (aBlockLayerPresent) { - ExtDispOnly::closeRange(1); - ExtDispOnly::prepare(ctx, &(list->hwLayers[aBlockLayerIndex]), - index, waitForVsync); - } else if (aNumExtLayers) { - ExtDispOnly::closeRange(aNumExtLayers); - for (size_t i = 0; i < list->numHwLayers; i++) { - private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; - if(hnd && hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY) { - waitForVsync = (index == (aNumExtLayers - 1)); - ExtDispOnly::prepare(ctx, &(list->hwLayers[i]), - index, waitForVsync); - index++; - } - } - } else { - ExtDispOnly::close(); - } -#endif - return overlay::NO_ERROR; -} - -void ExtDispOnly::storeLockedHandles(hwc_layer_list_t* list) { -#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY) - int index = 0; - if(sBlockLayerPresent) { - private_handle_t *hnd = (private_handle_t *) - list->hwLayers[sBlockLayerIndex].handle; - if(list->hwLayers[sBlockLayerIndex].flags & HWC_USE_EXT_ONLY) { - if(!(hnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK)) { - ExtDispOnly::lockBuffer(hnd); - } - sPreviousExtHandle[index] = hnd; - LOGE_IF(EXTDEBUG, "%s BLOCK: handle = %p", __func__, hnd); - return; - } - } - for(int i = 0; i < list->numHwLayers; i++) { - private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; - if(list->hwLayers[i].flags & HWC_USE_EXT_ONLY) { - if(!(hnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK)) { - ExtDispOnly::lockBuffer(hnd); - } - sPreviousExtHandle[index] = hnd; - index++; - LOGE_IF(EXTDEBUG, "%s: handle = %p", __func__, hnd); - } - } -#endif -} - -int ExtDispOnly::draw(hwc_context_t *ctx, hwc_layer_list_t *list) { -#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY) - LOGE_IF(EXTDEBUG, "%s", __func__); - if(ctx->mHDMIEnabled == EXT_DISPLAY_OFF || - ctx->pendingHDMI == true) { - ExtDispOnly::close(); - return -1; - } - - int ret = overlay::NO_ERROR; - int index = 0; - - //If skip layer present or list invalid unlock and return. - if(sSkipLayerPresent || list == NULL) { - ExtDispOnly::unlockPreviousBuffers(); - return overlay::NO_ERROR; - } - - if(sBlockLayerPresent) { - private_handle_t *hnd = (private_handle_t*) - list->hwLayers[sBlockLayerIndex].handle; - ExtDispOnly::lockBuffer(hnd); - ret = sOvExtUI[index]->queueBuffer(hnd); - if (ret) { - LOGE("%s queueBuffer failed", __func__); - // Unlock the locked buffer - ExtDispOnly::unlockBuffer(hnd); - ExtDispOnly::close(); - return -1; - } - ExtDispOnly::unlockPreviousBuffers(); - ExtDispOnly::storeLockedHandles(list); - return overlay::NO_ERROR; - } - - for(int i = 0; i < list->numHwLayers; i++) { - private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; - if(hnd && list->hwLayers[i].flags & HWC_USE_EXT_ONLY) { - overlay::OverlayUI *ovUI = sOvExtUI[index]; - ExtDispOnly::lockBuffer(hnd); - ret = ovUI->queueBuffer(hnd); - if (ret) { - LOGE("%s queueBuffer failed", __func__); - // Unlock the all the currently locked buffers - for (int j = 0; j <= i; j++) { - private_handle_t *tmphnd = - (private_handle_t *)list->hwLayers[j].handle; - if(hnd && list->hwLayers[j].flags & HWC_USE_EXT_ONLY) - ExtDispOnly::unlockBuffer(tmphnd); - } - ExtDispOnly::close(); - return -1; - } - index++; - } - } - ExtDispOnly::unlockPreviousBuffers(); - ExtDispOnly::storeLockedHandles(list); -#endif - return overlay::NO_ERROR; -} - -#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY) -overlay::OverlayUI* ExtDispOnly::sOvExtUI[MAX_EXT_ONLY_LAYERS]; -native_handle_t* ExtDispOnly::sPreviousExtHandle[MAX_EXT_ONLY_LAYERS]; -ExtDispOnly::ExternalOnlyMode ExtDispOnly::sExtOnlyMode; -int ExtDispOnly::sNumExtOnlyLayers; -bool ExtDispOnly::sSkipLayerPresent; -bool ExtDispOnly::sBlockLayerPresent; -int ExtDispOnly::sBlockLayerIndex; -#endif diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp new file mode 100644 index 0000000..afd2aa9 --- /dev/null +++ b/libhwcomposer/hwc.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012, Code Aurora Forum. All rights reserved. + * + * 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. + */ + +#include +#include + +#include +#include +#include + +#include "hwc_utils.h" + +using namespace qhwc; + +static int hwc_device_open(const struct hw_module_t* module, + const char* name, + struct hw_device_t** device); + +static struct hw_module_methods_t hwc_module_methods = { + open: hwc_device_open +}; + +hwc_module_t HAL_MODULE_INFO_SYM = { + common: { + tag: HARDWARE_MODULE_TAG, + version_major: 2, + version_minor: 0, + id: HWC_HARDWARE_MODULE_ID, + name: "Qualcomm Hardware Composer Module", + author: "CodeAurora Forum", + methods: &hwc_module_methods, + dso: 0, + reserved: {0}, + } +}; + +/* + * Save callback functions registered to HWC + */ +static void hwc_registerProcs(struct hwc_composer_device* dev, + hwc_procs_t const* procs) +{ + hwc_context_t* ctx = (hwc_context_t*)(dev); + if(!ctx) { + ALOGE("%s: Invalid context", __FUNCTION__); + return; + } + ctx->device.reserved_proc[0] = (void*)procs; +} + +static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) +{ + hwc_context_t* ctx = (hwc_context_t*)(dev); + if (LIKELY(list)) { + getLayerStats(ctx, list); + cleanOverlays(ctx); + for (int i=list->numHwLayers-1; i >= 0 ; i--) { + private_handle_t *hnd = + (private_handle_t *)list->hwLayers[i].handle; + if (isSkipLayer(&list->hwLayers[i])) { + break; + } else if(isYuvBuffer(hnd)) { + handleYUV(ctx,&list->hwLayers[i]); + } else { + list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; + } + } + } + return 0; +} + +static int hwc_set(hwc_composer_device_t *dev, + hwc_display_t dpy, + hwc_surface_t sur, + hwc_layer_list_t* list) +{ + int ret = 0; + hwc_context_t* ctx = (hwc_context_t*)(dev); + if (LIKELY(list)) { + for (size_t i=0; inumHwLayers; i++) { + if (list->hwLayers[i].flags & HWC_SKIP_LAYER) { + continue; + } else if (list->hwLayers[i].compositionType == HWC_USE_OVERLAY) { + drawLayerUsingOverlay(ctx, &(list->hwLayers[i])); + } + } + //XXX: Handle vsync with FBIO_WAITFORVSYNC ioctl + //All other operations (including pan display) should be NOWAIT + EGLBoolean sucess = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur); + } else { + //XXX: put in a wrapper for non overlay targets + setOverlayState(ctx, ovutils::OV_CLOSED); + } + ctx->qbuf->unlockAllPrevious(); + return ret; +} + +static int hwc_device_close(struct hw_device_t *dev) +{ + if(!dev) { + ALOGE("hwc_device_close null device pointer"); + return -1; + } + closeContext((hwc_context_t*)dev); + free(dev); + + return 0; +} + +static int hwc_device_open(const struct hw_module_t* module, const char* name, + struct hw_device_t** device) +{ + int status = -EINVAL; + + if (!strcmp(name, HWC_HARDWARE_COMPOSER)) { + struct hwc_context_t *dev; + dev = (hwc_context_t*)malloc(sizeof(*dev)); + memset(dev, 0, sizeof(*dev)); + initContext(dev); + dev->device.common.tag = HARDWARE_DEVICE_TAG; + dev->device.common.version = 0; + dev->device.common.module = const_cast(module); + dev->device.common.close = hwc_device_close; + dev->device.prepare = hwc_prepare; + dev->device.set = hwc_set; + dev->device.registerProcs = hwc_registerProcs; + *device = &dev->device.common; + status = 0; + } + return status; +} diff --git a/libhwcomposer/hwc_overlay.cpp b/libhwcomposer/hwc_overlay.cpp new file mode 100644 index 0000000..00f53e9 --- /dev/null +++ b/libhwcomposer/hwc_overlay.cpp @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012, Code Aurora Forum. All rights reserved. + * + * 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. + */ + +#include "hwc_utils.h" + +namespace qhwc { +// Determine overlay state based on decoded video info +static ovutils::eOverlayState determineOverlayState(hwc_context_t* ctx, + uint32_t bypassLayer, + uint32_t format) +{ + ovutils::eOverlayState state = ovutils::OV_CLOSED; + + // Sanity check + if (!ctx) { + ALOGE("%s: NULL ctx", __FUNCTION__); + return state; + } + + overlay::Overlay& ov = *(ctx->mOverlay); + state = ov.getState(); + + // If there are any bypassLayers, state is based on number of layers + if ((bypassLayer > 0) && (ctx->hdmiEnabled == EXT_TYPE_NONE)) { + if (bypassLayer == 1) { + state = ovutils::OV_BYPASS_1_LAYER; + } else if (bypassLayer == 2) { + state = ovutils::OV_BYPASS_2_LAYER; + } else if (bypassLayer == 3) { + state = ovutils::OV_BYPASS_3_LAYER; + } + return state; + } + + // RGB is ambiguous for determining overlay state + if (ovutils::isRgb(ovutils::getMdpFormat(format))) { + return state; + } + + // Content type is either 2D or 3D + uint32_t fmt3D = 0;//XXX: 3D - ovutils::getS3DFormat(format); + + // Determine state based on the external display, content type, and hw type + if (ctx->hdmiEnabled == EXT_TYPE_HDMI) { + // External display is HDMI + if (fmt3D) { + // Content type is 3D + if (ovutils::is3DTV()) { + // TV panel type is 3D + state = ovutils::OV_3D_VIDEO_ON_3D_TV; + } else { + // TV panel type is 2D + state = ovutils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV; + } + } else { + // Content type is 2D + if (ovutils::FrameBufferInfo::getInstance()->supportTrueMirroring()) { + // True UI mirroring is supported + state = ovutils::OV_2D_TRUE_UI_MIRROR; + } else { + // True UI mirroring is not supported + state = ovutils::OV_2D_VIDEO_ON_PANEL_TV; + } + } + } else if (ctx->hdmiEnabled == EXT_TYPE_WIFI) { + // External display is Wifi (currently unsupported) + ALOGE("%s: WIFI external display is unsupported", __FUNCTION__); + return state; + } else { + // No external display (primary panel only) + if (fmt3D) { + // Content type is 3D + if (ovutils::usePanel3D()) { + // Primary panel type is 3D + state = ovutils::OV_3D_VIDEO_ON_3D_PANEL; + } else { + // Primary panel type is 2D + state = ovutils::OV_3D_VIDEO_ON_2D_PANEL; + } + } else { + // Content type is 2D + state = ovutils::OV_2D_VIDEO_ON_PANEL; + } + } + + return state; +} + +void setOverlayState(hwc_context_t *ctx, ovutils::eOverlayState state) +{ + if (!ctx) { + ALOGE("%s: NULL ctx", __FUNCTION__); + return; + } + + overlay::Overlay *ov = ctx->mOverlay; + if (!ov) { + ALOGE("%s: NULL OV object", __FUNCTION__); + return; + } + ov->setState(state); +} + +bool prepareOverlay(hwc_context_t *ctx, hwc_layer_t *layer) +{ + bool ret = false; + if (LIKELY(ctx->mOverlay)) { + private_handle_t *hnd = (private_handle_t *)layer->handle; + overlay::Overlay& ov = *(ctx->mOverlay); + ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size); + + // Set overlay state + ovutils::eOverlayState state = determineOverlayState(ctx, 0, info.format); + setOverlayState(ctx, state); + + ovutils::eDest dest = ovutils::OV_PIPE_ALL; + + // In the true UI mirroring case, video needs to go to OV_PIPE0 (for + // primary) and OV_PIPE1 (for external) + if (state == ovutils::OV_2D_TRUE_UI_MIRROR) { + dest = static_cast( + ovutils::OV_PIPE0 | ovutils::OV_PIPE1); + } + + // Order order order + // setSource - just setting source + // setParameter - changes src w/h/f accordingly + // setCrop - ROI - that is src_rect + // setPosition - need to do scaling + // commit - commit changes to mdp driver + // queueBuffer - not here, happens when draw is called + + ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE; + if (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) { + ovutils::setMdpFlags(mdpFlags, + ovutils::OV_MDP_SECURE_OVERLAY_SESSION); + } + + // FIXME: Use source orientation for TV when source is portrait + int transform = layer->transform & FINAL_TRANSFORM_MASK; + ovutils::eTransform orient = + static_cast(transform); + + ovutils::eWait waitFlag = ovutils::NO_WAIT; + if (ctx->skipComposition == true) { + waitFlag = ovutils::WAIT; + } + + ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF; + if (ctx->numHwLayers == 1) { + isFgFlag = ovutils::IS_FG_SET; + } + + ovutils::PipeArgs parg(mdpFlags, + orient, + info, + waitFlag, + ovutils::ZORDER_0, + isFgFlag, + ovutils::ROT_FLAG_DISABLED); + ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg }; + ret = ov.setSource(pargs, dest); + if (!ret) { + ALOGE("%s: setSource failed", __FUNCTION__); + return ret; + } + + const ovutils::Params prms (ovutils::OVERLAY_TRANSFORM, orient); + ret = ov.setParameter(prms, dest); + if (!ret) { + ALOGE("%s: setParameter failed transform %x", __FUNCTION__, orient); + return ret; + } + + hwc_rect_t sourceCrop = layer->sourceCrop; + // x,y,w,h + ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top, // x, y + sourceCrop.right - sourceCrop.left, // w + sourceCrop.bottom - sourceCrop.top);// h + ret = ov.setCrop(dcrop, dest); + if (!ret) { + ALOGE("%s: setCrop failed", __FUNCTION__); + return ret; + } + + int orientation = 0; + ovutils::Dim dim; + hwc_rect_t displayFrame = layer->displayFrame; + dim.x = displayFrame.left; + dim.y = displayFrame.top; + dim.w = (displayFrame.right - displayFrame.left); + dim.h = (displayFrame.bottom - displayFrame.top); + dim.o = orientation; + + ret = ov.setPosition(dim, dest); + if (!ret) { + ALOGE("%s: setPosition failed", __FUNCTION__); + return ret; + } + if (!ov.commit(dest)) { + ALOGE("%s: commit fails", __FUNCTION__); + return false; + } + } + return true; +} + +bool drawLayerUsingOverlay(hwc_context_t *ctx, hwc_layer_t *layer) +{ + private_handle_t *hnd = (private_handle_t *)layer->handle; + + // Lock this buffer for read. + ctx->qbuf->lockAndAdd(hnd); + bool ret = true; + overlay::Overlay& ov = *(ctx->mOverlay); + ovutils::eOverlayState state = ov.getState(); + + // Differentiate between states that need to wait for vsync + switch (state) { + case ovutils::OV_2D_VIDEO_ON_PANEL_TV: + case ovutils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + case ovutils::OV_2D_TRUE_UI_MIRROR: + // If displaying on both primary and external, must play each + // pipe individually since wait for vsync needs to be done at + // the end. Do the following: + // - Play external + // - Play primary + // - Wait for external vsync to be done + // NOTE: In these states + // - primary VG = OV_PIPE0 + // - external VG = OV_PIPE1 + // - external RGB = OV_PIPE2 + // - Only in true UI mirroring case, played by fb + + // Same FD for both primary and external VG pipes + ov.setMemoryId(hnd->fd, static_cast( + ovutils::OV_PIPE0 | ovutils::OV_PIPE1)); + + // Play external + if (!ov.queueBuffer(hnd->offset, ovutils::OV_PIPE1)) { + ALOGE("%s: queueBuffer failed for external", __FUNCTION__); + ret = false; + } + + // Play primary + if (!ov.queueBuffer(hnd->offset, ovutils::OV_PIPE0)) { + ALOGE("%s: queueBuffer failed for primary", __FUNCTION__); + ret = false; + } + + // Wait for external vsync to be done + if (!ov.waitForVsync(ovutils::OV_PIPE1)) { + ALOGE("%s: waitForVsync failed for external", __FUNCTION__); + ret = false; + } + break; + default: + // In most cases, displaying only to one (primary or external) + // so use OV_PIPE_ALL since overlay will ignore NullPipes + ov.setMemoryId(hnd->fd, ovutils::OV_PIPE_ALL); + if (!ov.queueBuffer(hnd->offset, ovutils::OV_PIPE_ALL)) { + ALOGE("%s: queueBuffer failed", __FUNCTION__); + ret = false; + } + break; + } + + if (!ret) { + ALOGE("%s: failed", __FUNCTION__); + } + return ret; +} + +void cleanOverlays(hwc_context_t *ctx ) +{ + //XXX: handle for HDMI + if(0 == ctx->yuvBufferCount) + setOverlayState(ctx, ovutils::OV_CLOSED); +} +}; //namespace qhwc diff --git a/libhwcomposer/hwc_qbuf.h b/libhwcomposer/hwc_qbuf.h new file mode 100644 index 0000000..a0ade8c --- /dev/null +++ b/libhwcomposer/hwc_qbuf.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012, Code Aurora Forum. All rights reserved. + * + * 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. + */ + +// ----------------------------------------------------------------------------- +// QueuedBufferStore +//This class holds currently and previously queued buffers. +//Provides utilities to store, lock, remove, unlock. + +namespace qhwc{ +static const int MAX_QUEUED_BUFS = 4; +class QueuedBufferStore { + public: + QueuedBufferStore() { + clearCurrent(); + clearPrevious(); + } + ~QueuedBufferStore() {} + void lockAndAdd(private_handle_t*); + void unlockAllPrevious(); + + private: + QueuedBufferStore& operator=(const QueuedBufferStore&); + QueuedBufferStore(const QueuedBufferStore&); + bool lockBuffer(private_handle_t *hnd); + void unlockBuffer(private_handle_t *hnd); + void clearCurrent(); + void clearPrevious(); + void mvCurrToPrev(); + + //members + private_handle_t *current[MAX_QUEUED_BUFS]; //holds buf being queued + private_handle_t *previous[MAX_QUEUED_BUFS]; //holds bufs queued in prev round + int curCount; + int prevCount; +}; + +//Store and lock current drawing round buffers +inline void QueuedBufferStore::lockAndAdd(private_handle_t *hnd) { + if(lockBuffer(hnd)) + current[curCount++] = hnd; +} + +//Unlock all previous drawing round buffers +inline void QueuedBufferStore::unlockAllPrevious() { + //Unlock + for(int i = 0; i < prevCount; i++) { + unlockBuffer(previous[i]); + previous[i] = NULL; + } + //Move current hnd to previous + mvCurrToPrev(); + //Clear current + clearCurrent(); +} + +//Clear currentbuf store +inline void QueuedBufferStore::clearCurrent() { + for(int i = 0; i < MAX_QUEUED_BUFS; i++) + current[i] = NULL; + curCount = 0; +} + +//Clear previousbuf store +inline void QueuedBufferStore::clearPrevious() { + for(int i = 0; i < MAX_QUEUED_BUFS; i++) + previous[i] = NULL; + prevCount = 0; +} + +//Copy from current to previous +inline void QueuedBufferStore::mvCurrToPrev() { + for(int i = 0; i < curCount; i++) + previous[i] = current[i]; + prevCount = curCount; +} + +inline bool QueuedBufferStore::lockBuffer(private_handle_t *hnd) { + if (GENLOCK_FAILURE == genlock_lock_buffer(hnd, GENLOCK_READ_LOCK, + GENLOCK_MAX_TIMEOUT)) { + ALOGE("%s: genlock_lock_buffer(READ) failed", __func__); + return false; + } + return true; +} + +inline void QueuedBufferStore::unlockBuffer(private_handle_t *hnd) { + //Check if buffer is still around + if(private_handle_t::validate(hnd) != 0) { + ALOGE("%s Invalid Handle", __func__); + return; + } + //Actually try to unlock + if (GENLOCK_FAILURE == genlock_unlock_buffer(hnd)) { + ALOGE("%s: genlock_unlock_buffer failed", __func__); + return; + } +} +// ----------------------------------------------------------------------------- +};//namespace + diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp new file mode 100644 index 0000000..13873f8 --- /dev/null +++ b/libhwcomposer/hwc_utils.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012, Code Aurora Forum. All rights reserved. + * + * 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. + */ + +#include "hwc_utils.h" + +namespace qhwc { +void initContext(hwc_context_t *ctx) +{ + //XXX: target specific initializations here + openFramebufferDevice(ctx); + ctx->mOverlay = overlay::Overlay::getInstance(); + ctx->qbuf = new QueuedBufferStore(); + +} + +void closeContext(hwc_context_t *ctx) +{ + if(ctx->mOverlay) { + delete ctx->mOverlay; + ctx->mOverlay = NULL; + } + if(ctx->fbDev) { + framebuffer_close(ctx->fbDev); + ctx->fbDev = NULL; + } + + if(ctx->qbuf) { + delete ctx->qbuf; + ctx->qbuf = NULL; + } +} + +// Opens Framebuffer device +void openFramebufferDevice(hwc_context_t *ctx) { + hw_module_t const *module; + if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) { + framebuffer_open(module, &(ctx->fbDev)); + } +} + +void dumpLayer(hwc_layer_t const* l) +{ + ALOGD("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, {%d,%d,%d,%d}" + ", {%d,%d,%d,%d}", + l->compositionType, l->flags, l->handle, l->transform, l->blending, + l->sourceCrop.left, + l->sourceCrop.top, + l->sourceCrop.right, + l->sourceCrop.bottom, + l->displayFrame.left, + l->displayFrame.top, + l->displayFrame.right, + l->displayFrame.bottom); +} + +void getLayerStats(hwc_context_t *ctx, const hwc_layer_list_t *list) +{ + int yuvBufCount = 0; + int layersNotUpdatingCount = 0; + for (size_t i=0 ; inumHwLayers; i++) { + private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; + if (isYuvBuffer(hnd)) { + yuvBufCount++; + } + } + // Number of video/camera layers drawable with overlay + ctx->yuvBufferCount = yuvBufCount; + ctx->numHwLayers = list->numHwLayers; + return; +} + +void handleYUV(hwc_context_t *ctx, hwc_layer_t *layer) +{ + private_handle_t *hnd = + (private_handle_t *)layer->handle; + //XXX: Handle targets not using overlay + if(prepareOverlay(ctx, layer)) { + layer->compositionType = HWC_USE_OVERLAY; + layer->hints |= HWC_HINT_CLEAR_FB; + } +} +};//namespace diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h new file mode 100644 index 0000000..b1c7871 --- /dev/null +++ b/libhwcomposer/hwc_utils.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012, Code Aurora Forum. All rights reserved. + * + * 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. + */ + +#ifndef HWC_UTILS_H +#define HWC_UTILS_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hwc_qbuf.h" + +#define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1)) +#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) +#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) + +struct hwc_context_t; +namespace qhwc { + +// ----------------------------------------------------------------------------- +// Utility functions - implemented in hwc_utils.cpp +void dumpLayer(hwc_layer_t const* l); +void getLayerStats(hwc_context_t *ctx, const hwc_layer_list_t *list); +void handleYUV(hwc_context_t *ctx, hwc_layer_t *layer); +void initContext(hwc_context_t *ctx); +void closeContext(hwc_context_t *ctx); +void openFramebufferDevice(hwc_context_t *ctx); + +// Inline utility functions +static inline bool isSkipLayer(const hwc_layer_t* l) { + return (UNLIKELY(l && (l->flags & HWC_SKIP_LAYER))); +} + +// Returns true if the buffer is yuv +static inline bool isYuvBuffer(const private_handle_t* hnd) { + return (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO)); +} + +//Return true if buffer is marked locked +static inline bool isBufferLocked(const private_handle_t* hnd) { + return (hnd && (private_handle_t::PRIV_FLAGS_HWC_LOCK & hnd->flags)); +} + +// ----------------------------------------------------------------------------- +// Overlay specific functions - inline or implemented in hwc_overlay.cpp +bool prepareOverlay(hwc_context_t *ctx, hwc_layer_t *layer); +//XXX: Refine draw functions +bool drawLayerUsingOverlay(hwc_context_t *ctx, hwc_layer_t *layer); +//XXX: Refine +void cleanOverlays(hwc_context_t *ctx ); +void setOverlayState(hwc_context_t* ctx, ovutils::eOverlayState state); + +// ----------------------------------------------------------------------------- +// Copybit specific functions - inline or implemented in hwc_copybit.cpp + + + +// ----------------------------------------------------------------------------- +// HDMI specific functions - inline or implemented in hwc_hdmi.cpp + + + +} //qhwc namespace + + + +// ----------------------------------------------------------------------------- +// HWC context +// This structure contains overall state +struct hwc_context_t { + hwc_composer_device_t device; + // Layer variables + int yuvBufferCount; + int hdmiEnabled; + int numHwLayers; + bool skipComposition; + + //Framebuffer device + framebuffer_device_t *fbDev; + + //Overlay object - NULL for non overlay devices + overlay::Overlay *mOverlay; + + //QueuedBufferStore to hold buffers for overlay + qhwc::QueuedBufferStore *qbuf; +}; + + + + +#endif //HWC_UTILS_H diff --git a/libhwcomposer/hwcomposer.cpp b/libhwcomposer/hwcomposer.cpp deleted file mode 100755 index c43fa04..0000000 --- a/libhwcomposer/hwcomposer.cpp +++ /dev/null @@ -1,1734 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/*****************************************************************************/ -#define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1)) -#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) -#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) - -#ifdef COMPOSITION_BYPASS -#define MAX_BYPASS_LAYERS 3 -#define BYPASS_DEBUG 0 -#define BYPASS_INDEX_OFFSET 4 - -enum BypassState { - BYPASS_ON, - BYPASS_OFF, - BYPASS_OFF_PENDING, -}; - -enum BypassBufferLockState { - BYPASS_BUFFER_UNLOCKED, - BYPASS_BUFFER_LOCKED, -}; -#endif - -enum HWCLayerType{ - HWC_SINGLE_VIDEO = 0x1, - HWC_ORIG_RESOLUTION = 0x2, - HWC_S3D_LAYER = 0x4, - HWC_STOP_UI_MIRRORING_MASK = 0xF -}; - -enum eHWCOverlayStatus { - HWC_OVERLAY_OPEN, - HWC_OVERLAY_PREPARE_TO_CLOSE, - HWC_OVERLAY_CLOSED -}; - -struct hwc_context_t { - hwc_composer_device_t device; - /* our private state goes below here */ - overlay::Overlay* mOverlayLibObject; - native_handle_t *previousOverlayHandle; -#ifdef COMPOSITION_BYPASS - overlay::OverlayUI* mOvUI[MAX_BYPASS_LAYERS]; - native_handle_t* previousBypassHandle[MAX_BYPASS_LAYERS]; - BypassBufferLockState bypassBufferLockState[MAX_BYPASS_LAYERS]; - int layerindex[MAX_BYPASS_LAYERS]; - int nPipesUsed; - BypassState bypassState; -#endif -#if defined HDMI_DUAL_DISPLAY - external_display mHDMIEnabled; // Type of external display - bool pendingHDMI; -#endif - int previousLayerCount; - eHWCOverlayStatus hwcOverlayStatus; -}; - -static int hwc_device_open(const struct hw_module_t* module, const char* name, - struct hw_device_t** device); - -static struct hw_module_methods_t hwc_module_methods = { - open: hwc_device_open -}; - - -struct private_hwc_module_t { - hwc_module_t base; - copybit_device_t *copybitEngine; - framebuffer_device_t *fbDevice; - int compositionType; - bool isBypassEnabled; //from build.prop ro.sf.compbypass.enable -}; - -struct private_hwc_module_t HAL_MODULE_INFO_SYM = { - base: { - common: { - tag: HARDWARE_MODULE_TAG, - version_major: 1, - version_minor: 0, - id: HWC_HARDWARE_MODULE_ID, - name: "Hardware Composer Module", - author: "The Android Open Source Project", - methods: &hwc_module_methods, - } - }, - copybitEngine: NULL, - fbDevice: NULL, - compositionType: 0, - isBypassEnabled: false, -}; - -//Only at this point would the compiler know all storage class sizes. -//The header has hooks which need to know those beforehand. -#include "external_display_only.h" - -/*****************************************************************************/ - -static void dump_layer(hwc_layer_t const* l) { - LOGD("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, {%d,%d,%d,%d}, {%d,%d,%d,%d}", - l->compositionType, l->flags, l->handle, l->transform, l->blending, - l->sourceCrop.left, - l->sourceCrop.top, - l->sourceCrop.right, - l->sourceCrop.bottom, - l->displayFrame.left, - l->displayFrame.top, - l->displayFrame.right, - l->displayFrame.bottom); -} - -static inline int min(const int& a, const int& b) { - return (a < b) ? a : b; -} - -static inline int max(const int& a, const int& b) { - return (a > b) ? a : b; -} -#ifdef COMPOSITION_BYPASS -void setLayerbypassIndex(hwc_layer_t* layer, const int bypass_index) -{ - layer->flags &= ~HWC_BYPASS_INDEX_MASK; - layer->flags |= bypass_index << BYPASS_INDEX_OFFSET; -} - -int getLayerbypassIndex(hwc_layer_t* layer) -{ - int byp_index = -1; - - if(layer->flags & HWC_COMP_BYPASS) { - byp_index = ((layer->flags & HWC_BYPASS_INDEX_MASK) >> BYPASS_INDEX_OFFSET); - byp_index = (byp_index < MAX_BYPASS_LAYERS ? byp_index : -1 ); - } - return byp_index; -} - -void unlockPreviousBypassBuffers(hwc_context_t* ctx) { - // Unlock the previous bypass buffers. We can blindly unlock the buffers here, - // because buffers will be in this list only if the lock was successfully acquired. - for(int i = 0; i < MAX_BYPASS_LAYERS && ctx->previousBypassHandle[i]; i++) { - private_handle_t *hnd = (private_handle_t*) ctx->previousBypassHandle[i]; - - // Validate the handle to make sure it hasn't been deallocated. - if (private_handle_t::validate(ctx->previousBypassHandle[i])) { - continue; - } - // Check if the handle was locked previously - if (private_handle_t::PRIV_FLAGS_HWC_LOCK & hnd->flags) { - if (GENLOCK_FAILURE == genlock_unlock_buffer(ctx->previousBypassHandle[i])) { - LOGE("%s: genlock_unlock_buffer failed", __FUNCTION__); - } else { - ctx->previousBypassHandle[i] = NULL; - // Reset the lock flag - hnd->flags &= ~private_handle_t::PRIV_FLAGS_HWC_LOCK; - } - } - } -} - -void print_info(hwc_layer_t* layer) -{ - hwc_rect_t sourceCrop = layer->sourceCrop; - hwc_rect_t displayFrame = layer->displayFrame; - - int s_l = sourceCrop.left; - int s_t = sourceCrop.top; - int s_r = sourceCrop.right; - int s_b = sourceCrop.bottom; - - int d_l = displayFrame.left; - int d_t = displayFrame.top; - int d_r = displayFrame.right; - int d_b = displayFrame.bottom; - - LOGE_IF(BYPASS_DEBUG, "src:[%d,%d,%d,%d] (%d x %d) dst:[%d,%d,%d,%d] (%d x %d)", - s_l, s_t, s_r, s_b, (s_r - s_l), (s_b - s_t), - d_l, d_t, d_r, d_b, (d_r - d_l), (d_b - d_t)); -} - -//Crops source buffer against destination and FB boundaries -void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst, int hw_w, int hw_h) { - - int& crop_x = crop.left; - int& crop_y = crop.top; - int& crop_r = crop.right; - int& crop_b = crop.bottom; - int crop_w = crop.right - crop.left; - int crop_h = crop.bottom - crop.top; - - int& dst_x = dst.left; - int& dst_y = dst.top; - int& dst_r = dst.right; - int& dst_b = dst.bottom; - int dst_w = dst.right - dst.left; - int dst_h = dst.bottom - dst.top; - - if(dst_x < 0) { - float scale_x = crop_w * 1.0f / dst_w; - float diff_factor = (scale_x * abs(dst_x)); - crop_x = crop_x + (int)diff_factor; - crop_w = crop_r - crop_x; - - dst_x = 0; - dst_w = dst_r - dst_x;; - } - if(dst_r > hw_w) { - float scale_x = crop_w * 1.0f / dst_w; - float diff_factor = scale_x * (dst_r - hw_w); - crop_r = crop_r - diff_factor; - crop_w = crop_r - crop_x; - - dst_r = hw_w; - dst_w = dst_r - dst_x; - } - if(dst_y < 0) { - float scale_y = crop_h * 1.0f / dst_h; - float diff_factor = scale_y * abs(dst_y); - crop_y = crop_y + diff_factor; - crop_h = crop_b - crop_y; - - dst_y = 0; - dst_h = dst_b - dst_y; - } - if(dst_b > hw_h) { - float scale_y = crop_h * 1.0f / dst_h; - float diff_factor = scale_y * (dst_b - hw_h); - crop_b = crop_b - diff_factor; - crop_h = crop_b - crop_y; - - dst_b = hw_h; - dst_h = dst_b - dst_y; - } - - LOGE_IF(BYPASS_DEBUG,"crop: [%d,%d,%d,%d] dst:[%d,%d,%d,%d]", - crop_x, crop_y, crop_w, crop_h,dst_x, dst_y, dst_w, dst_h); -} - -/* - * Configures pipe(s) for composition bypass - */ -static int prepareBypass(hwc_context_t *ctx, hwc_layer_t *layer, - int nPipeIndex, int vsync_wait, int isFG) { - - if (ctx && ctx->mOvUI[nPipeIndex]) { - overlay::OverlayUI *ovUI = ctx->mOvUI[nPipeIndex]; - - private_hwc_module_t* hwcModule = reinterpret_cast< - private_hwc_module_t*>(ctx->device.common.module); - if (!hwcModule) { - LOGE("%s: NULL Module", __FUNCTION__); - return -1; - } - - private_handle_t *hnd = (private_handle_t *)layer->handle; - if(!hnd) { - LOGE("%s: layer handle is NULL", __FUNCTION__); - return -1; - } - - int hw_w = hwcModule->fbDevice->width; - int hw_h = hwcModule->fbDevice->height; - - hwc_rect_t sourceCrop = layer->sourceCrop; - hwc_rect_t displayFrame = layer->displayFrame; - - const int src_w = sourceCrop.right - sourceCrop.left; - const int src_h = sourceCrop.bottom - sourceCrop.top; - - hwc_rect_t crop = sourceCrop; - int crop_w = crop.right - crop.left; - int crop_h = crop.bottom - crop.top; - - hwc_rect_t dst = displayFrame; - int dst_w = dst.right - dst.left; - int dst_h = dst.bottom - dst.top; - - if(hnd != NULL && (hnd->flags & private_handle_t::PRIV_FLAGS_NONCONTIGUOUS_MEM )) { - LOGE("%s: Unable to setup bypass due to non-pmem memory",__FUNCTION__); - return -1; - } - - if(dst.left < 0 || dst.top < 0 || dst.right > hw_w || dst.bottom > hw_h) { - LOGE_IF(BYPASS_DEBUG,"%s: Destination has negative coordinates", __FUNCTION__); - - calculate_crop_rects(crop, dst, hw_w, hw_h); - - //Update calulated width and height - crop_w = crop.right - crop.left; - crop_h = crop.bottom - crop.top; - - dst_w = dst.right - dst.left; - dst_h = dst.bottom - dst.top; - } - - if( (dst_w > hw_w)|| (dst_h > hw_h)) { - LOGE_IF(BYPASS_DEBUG,"%s: Destination rectangle exceeds FB resolution", __FUNCTION__); - print_info(layer); - dst_w = hw_w; - dst_h = hw_h; - } - - overlay_buffer_info info; - info.width = src_w; - info.height = src_h; - info.format = hnd->format; - info.size = hnd->size; - - int fbnum = 0; - int orientation = layer->transform; - const bool useVGPipe = (nPipeIndex != (MAX_BYPASS_LAYERS-1)); - //only last layer should wait for vsync - const bool waitForVsync = vsync_wait; - const bool isFg = isFG; - //Just to differentiate zorders for different layers - const int zorder = nPipeIndex; - - ovUI->setSource(info, orientation); - ovUI->setCrop(crop.left, crop.top, crop_w, crop_h); - ovUI->setDisplayParams(fbnum, waitForVsync, isFg, zorder, useVGPipe); - ovUI->setPosition(dst.left, dst.top, dst_w, dst_h); - - LOGE_IF(BYPASS_DEBUG,"%s: Bypass set: crop[%d,%d,%d,%d] dst[%d,%d,%d,%d] waitforVsync: %d \ - isFg: %d zorder: %d VG = %d nPipe: %d",__FUNCTION__, - crop.left, crop.top, crop_w, crop_h, - dst.left, dst.top, dst_w, dst_h, - waitForVsync, isFg, zorder, useVGPipe, nPipeIndex ); - - if(ovUI->commit() != overlay::NO_ERROR) { - LOGE("%s: Overlay Commit failed", __FUNCTION__); - return -1; - } - } - return 0; -} - -/* - * Checks if doing comp. bypass is possible. - * It is possible if - * 1. No MDP pipe is used - * 2. Rotation is not needed - * 3. We have atmost MAX_BYPASS_LAYERS - */ -inline static bool isBypassDoable(hwc_composer_device_t *dev, const int yuvCount, - const hwc_layer_list_t* list) { - hwc_context_t* ctx = (hwc_context_t*)(dev); - private_hwc_module_t* hwcModule = reinterpret_cast( - dev->common.module); - //Check if enabled in build.prop - if(hwcModule->isBypassEnabled == false) { - return false; - } - - if(list->numHwLayers < 1) { - return false; - } - -#if defined HDMI_DUAL_DISPLAY - //Disable bypass when HDMI is enabled - if(ctx->mHDMIEnabled || ctx->pendingHDMI) { - return false; - } -#endif - - if(ExtDispOnly::isModeOn()) { - return false; - } - - //Bypass is not efficient if rotation or asynchronous mode is needed. - for(int i = 0; i < list->numHwLayers; ++i) { - if(list->hwLayers[i].transform) { - return false; - } - if(list->hwLayers[i].flags & HWC_LAYER_ASYNCHRONOUS) { - return false; - } - } - - return (yuvCount == 0) && (ctx->hwcOverlayStatus == HWC_OVERLAY_CLOSED) - && (list->numHwLayers <= MAX_BYPASS_LAYERS); -} - -void setBypassLayerFlags(hwc_context_t* ctx, hwc_layer_list_t* list) -{ - for(int index = 0 ; index < MAX_BYPASS_LAYERS; index++ ) - { - int layer_index = ctx->layerindex[index]; - if(layer_index >= 0) { - hwc_layer_t* layer = &(list->hwLayers[layer_index]); - - layer->flags |= HWC_COMP_BYPASS; - layer->compositionType = HWC_USE_OVERLAY; - layer->hints |= HWC_HINT_CLEAR_FB; - } - } - - if( list->numHwLayers > ctx->nPipesUsed ) { - list->flags &= ~HWC_SKIP_COMPOSITION; //Compose to FB - } else { - list->flags |= HWC_SKIP_COMPOSITION; // Dont - } -} - -bool setupBypass(hwc_context_t* ctx, hwc_layer_list_t* list) { - int nPipeIndex, vsync_wait, isFG; - int numHwLayers = list->numHwLayers; - int nPipeAvailable = MAX_BYPASS_LAYERS; - - for (int index = 0 ; (index < numHwLayers) && nPipeAvailable; index++) { - - hwc_layer_t* layer = &(list->hwLayers[index]); - - nPipeIndex = MAX_BYPASS_LAYERS - nPipeAvailable; - //Set VSYNC wait is needed only for the last pipe queued - vsync_wait = (nPipeIndex == (numHwLayers-1)); - //Set isFG to true for layer with z-order zero - isFG = !index; - - //Clear Bypass flags for the layer - layer->flags &= ~HWC_COMP_BYPASS; - layer->flags |= HWC_BYPASS_INDEX_MASK; - - if( prepareBypass(ctx, &(list->hwLayers[index]), nPipeIndex, vsync_wait, isFG) != 0 ) { - LOGE_IF(BYPASS_DEBUG, "%s: layer %d failed to configure bypass for pipe index: %d", - __FUNCTION__, index, nPipeIndex); - return false; - } else { - ctx->layerindex[nPipeIndex] = index; - setLayerbypassIndex(layer, nPipeIndex); - nPipeAvailable--; - } - } - ctx->nPipesUsed = MAX_BYPASS_LAYERS - nPipeAvailable; - return true; -} - -void unsetBypassLayerFlags(hwc_layer_list_t* list) { - if (!list) - return; - - for (int index = 0 ; index < list->numHwLayers; index++) { - if(list->hwLayers[index].flags & HWC_COMP_BYPASS) { - list->hwLayers[index].flags &= ~HWC_COMP_BYPASS; - } - } -} - -void unsetBypassBufferLockState(hwc_context_t* ctx) { - for (int i= 0; i< MAX_BYPASS_LAYERS; i++) { - ctx->bypassBufferLockState[i] = BYPASS_BUFFER_UNLOCKED; - } -} - -void storeLockedBypassHandle(hwc_layer_list_t* list, hwc_context_t* ctx) { - if (!list) - return; - - for(int index = 0; index < MAX_BYPASS_LAYERS; index++ ) { - hwc_layer_t layer = list->hwLayers[ctx->layerindex[index]]; - - if (layer.flags & HWC_COMP_BYPASS) { - private_handle_t *hnd = (private_handle_t*)layer.handle; - - if (ctx->bypassBufferLockState[index] == BYPASS_BUFFER_LOCKED) { - ctx->previousBypassHandle[index] = (native_handle_t*)layer.handle; - hnd->flags |= private_handle_t::PRIV_FLAGS_HWC_LOCK; - } else { - ctx->previousBypassHandle[index] = NULL; - } - } - } -} - -void closeExtraPipes(hwc_context_t* ctx) { - - int pipes_used = ctx->nPipesUsed; - - //Unused pipes must be of higher z-order - for (int i = pipes_used ; i < MAX_BYPASS_LAYERS; i++) { - if (ctx->previousBypassHandle[i]) { - private_handle_t *hnd = (private_handle_t*) ctx->previousBypassHandle[i]; - - if (!private_handle_t::validate(ctx->previousBypassHandle[i])) { - if (GENLOCK_FAILURE == genlock_unlock_buffer(ctx->previousBypassHandle[i])) { - LOGE("%s: genlock_unlock_buffer failed", __FUNCTION__); - } else { - ctx->previousBypassHandle[i] = NULL; - ctx->bypassBufferLockState[i] = BYPASS_BUFFER_UNLOCKED; - hnd->flags &= ~private_handle_t::PRIV_FLAGS_HWC_LOCK; - } - } - } - ctx->mOvUI[i]->closeChannel(); - ctx->layerindex[i] = -1; - } -} -#endif //COMPOSITION_BYPASS - -static int setVideoOverlayStatusInGralloc(hwc_context_t* ctx, const bool enable) { -#if defined HDMI_DUAL_DISPLAY - private_hwc_module_t* hwcModule = reinterpret_cast( - ctx->device.common.module); - if(!hwcModule) { - LOGE("%s: invalid params", __FUNCTION__); - return -1; - } - - framebuffer_device_t *fbDev = hwcModule->fbDevice; - if (!fbDev) { - LOGE("%s: fbDev is NULL", __FUNCTION__); - return -1; - } - - // Inform the gralloc to stop or start UI mirroring - fbDev->videoOverlayStarted(fbDev, enable); -#endif - return 0; -} - -static void setHWCOverlayStatus(hwc_context_t *ctx, bool isVideoPresent) { - - switch (ctx->hwcOverlayStatus) { - case HWC_OVERLAY_OPEN: - ctx->hwcOverlayStatus = - isVideoPresent ? HWC_OVERLAY_OPEN : HWC_OVERLAY_PREPARE_TO_CLOSE; - break; - case HWC_OVERLAY_PREPARE_TO_CLOSE: - ctx->hwcOverlayStatus = - isVideoPresent ? HWC_OVERLAY_OPEN : HWC_OVERLAY_CLOSED; - break; - case HWC_OVERLAY_CLOSED: - ctx->hwcOverlayStatus = - isVideoPresent ? HWC_OVERLAY_OPEN : HWC_OVERLAY_CLOSED; - break; - default: - LOGE("%s: Invalid hwcOverlayStatus (status =%d)", __FUNCTION__, - ctx->hwcOverlayStatus); - break; - } -} - -static int hwc_closeOverlayChannels(hwc_context_t* ctx) { -#ifdef USE_OVERLAY - overlay::Overlay *ovLibObject = ctx->mOverlayLibObject; - if(!ovLibObject) { - LOGE("%s: invalid params", __FUNCTION__); - return -1; - } - - if (HWC_OVERLAY_PREPARE_TO_CLOSE == ctx->hwcOverlayStatus) { - // Video mirroring is going on, and we do not have any layers to - // mirror directly. Close the current video channel and inform the - // gralloc to start UI mirroring - ovLibObject->closeChannel(); - // Inform the gralloc that video overlay has stopped. - setVideoOverlayStatusInGralloc(ctx, false); - } -#endif - return 0; -} - -/* - * Configures mdp pipes - */ -static int prepareOverlay(hwc_context_t *ctx, hwc_layer_t *layer, const int flags) { - int ret = 0; - -#ifdef COMPOSITION_BYPASS - if(ctx && (ctx->bypassState != BYPASS_OFF)) { - ctx->nPipesUsed = 0; - closeExtraPipes(ctx); - ctx->bypassState = BYPASS_OFF; - } -#endif - - if (LIKELY(ctx && ctx->mOverlayLibObject)) { - private_hwc_module_t* hwcModule = - reinterpret_cast(ctx->device.common.module); - if (UNLIKELY(!hwcModule)) { - LOGE("prepareOverlay null module "); - return -1; - } - - private_handle_t *hnd = (private_handle_t *)layer->handle; - overlay::Overlay *ovLibObject = ctx->mOverlayLibObject; - overlay_buffer_info info; - info.width = hnd->width; - info.height = hnd->height; - info.format = hnd->format; - info.size = hnd->size; - - int hdmiConnected = 0; - -#if defined HDMI_DUAL_DISPLAY - if(!ctx->pendingHDMI) //makes sure the UI channel is opened first - hdmiConnected = (int)ctx->mHDMIEnabled; -#endif - ret = ovLibObject->setSource(info, layer->transform, - hdmiConnected, flags); - if (!ret) { - LOGE("prepareOverlay setSource failed"); - return -1; - } - - ret = ovLibObject->setTransform(layer->transform); - if (!ret) { - LOGE("prepareOverlay setTransform failed transform %x", - layer->transform); - return -1; - } - - hwc_rect_t sourceCrop = layer->sourceCrop; - ret = ovLibObject->setCrop(sourceCrop.left, sourceCrop.top, - (sourceCrop.right - sourceCrop.left), - (sourceCrop.bottom - sourceCrop.top)); - if (!ret) { - LOGE("prepareOverlay setCrop failed"); - return -1; - } -#if defined HDMI_DUAL_DISPLAY - // Send the device orientation to overlayLib - if(hwcModule) { - framebuffer_device_t *fbDev = reinterpret_cast - (hwcModule->fbDevice); - if(fbDev) { - private_module_t* m = reinterpret_cast( - fbDev->common.module); - if(m) - ovLibObject->setDeviceOrientation(m->orientation); - } - } -#endif - if (layer->flags & HWC_USE_ORIGINAL_RESOLUTION) { - framebuffer_device_t* fbDev = hwcModule->fbDevice; - ret = ovLibObject->setPosition(0, 0, - fbDev->width, fbDev->height); - } else { - hwc_rect_t displayFrame = layer->displayFrame; - ret = ovLibObject->setPosition(displayFrame.left, displayFrame.top, - (displayFrame.right - displayFrame.left), - (displayFrame.bottom - displayFrame.top)); - } - if (!ret) { - LOGE("prepareOverlay setPosition failed"); - return -1; - } - } - return 0; -} - -void unlockPreviousOverlayBuffer(hwc_context_t* ctx) -{ - if (ctx->previousOverlayHandle) { - // Validate the handle before attempting to use it. - if (!private_handle_t::validate(ctx->previousOverlayHandle)) { - private_handle_t *hnd = (private_handle_t*)ctx->previousOverlayHandle; - // Unlock any previously locked buffers - if (private_handle_t::PRIV_FLAGS_HWC_LOCK & hnd->flags) { - if (GENLOCK_NO_ERROR == genlock_unlock_buffer(ctx->previousOverlayHandle)) { - ctx->previousOverlayHandle = NULL; - hnd->flags &= ~private_handle_t::PRIV_FLAGS_HWC_LOCK; - } else { - LOGE("%s: genlock_unlock_buffer failed", __FUNCTION__); - } - } - } - } -} - -bool canSkipComposition(hwc_context_t* ctx, int yuvBufferCount, int currentLayerCount, - int numLayersNotUpdating) -{ - if (!ctx) { - LOGE("%s: invalid context",__FUNCTION__); - return false; - } - - hwc_composer_device_t* dev = (hwc_composer_device_t *)(ctx); - private_hwc_module_t* hwcModule = reinterpret_cast( - dev->common.module); - if (hwcModule->compositionType == COMPOSITION_TYPE_CPU) - return false; - - //Video / Camera case - if (yuvBufferCount == 1) { - //If the previousLayerCount is anything other than the current count, it - //means something changed and we need to compose atleast once to FB. - if (currentLayerCount != ctx->previousLayerCount) { - ctx->previousLayerCount = currentLayerCount; - return false; - } - // We either have only one overlay layer or we have - // all non-updating UI layers. - // We can skip the composition of the UI layers. - if ((currentLayerCount == 1) || - ((currentLayerCount - 1) == numLayersNotUpdating)) { - return true; - } - } else { - ctx->previousLayerCount = -1; - } - return false; -} - -inline void getLayerResolution(const hwc_layer_t* layer, int& width, int& height) -{ - hwc_rect_t displayFrame = layer->displayFrame; - - width = displayFrame.right - displayFrame.left; - height = displayFrame.bottom - displayFrame.top; -} - -static bool canUseCopybit(const framebuffer_device_t* fbDev, const hwc_layer_list_t* list) { - - if(!fbDev) { - LOGE("ERROR: %s : fb device is invalid",__func__); - return false; - } - - if (!list) - return false; - - int fb_w = fbDev->width; - int fb_h = fbDev->height; - - /* - * Use copybit only when we need to blit - * max 2 full screen sized regions - */ - - unsigned int renderArea = 0; - - for(int i = 0; i < list->numHwLayers; i++ ) { - int w, h; - getLayerResolution(&list->hwLayers[i], w, h); - renderArea += w*h; - } - - return (renderArea <= (2 * fb_w * fb_h)); -} - -static void handleHDMIStateChange(hwc_composer_device_t *dev, int externaltype) { -#if defined HDMI_DUAL_DISPLAY - hwc_context_t* ctx = (hwc_context_t*)(dev); - private_hwc_module_t* hwcModule = reinterpret_cast( - dev->common.module); - //Route the event to fbdev only if we are in default mirror mode - if(ExtDispOnly::isModeOn() == false) { - framebuffer_device_t *fbDev = hwcModule->fbDevice; - if (fbDev) { - fbDev->enableHDMIOutput(fbDev, externaltype); - } - - if(ctx && ctx->mOverlayLibObject) { - overlay::Overlay *ovLibObject = ctx->mOverlayLibObject; - if (!externaltype) { - // Close the external overlay channels if HDMI is disconnected - ovLibObject->closeExternalChannel(); - } - } - } -#endif -} - -/* - * function to set the status of external display in hwc - * Just mark flags and do stuff after eglSwapBuffers - * externaltype - can be HDMI, WIFI or OFF - */ -static void hwc_enableHDMIOutput(hwc_composer_device_t *dev, int externaltype) { -#if defined HDMI_DUAL_DISPLAY - hwc_context_t* ctx = (hwc_context_t*)(dev); - private_hwc_module_t* hwcModule = reinterpret_cast( - dev->common.module); - framebuffer_device_t *fbDev = hwcModule->fbDevice; - overlay::Overlay *ovLibObject = ctx->mOverlayLibObject; - if(externaltype && ctx->mHDMIEnabled && - (externaltype != ctx->mHDMIEnabled)) { - // Close the current external display - as the SF will - // prioritize and send the correct external display HDMI/WFD - handleHDMIStateChange(dev, 0); - } - // Store the external display - ctx->mHDMIEnabled = (external_display)externaltype; - if(ctx->mHDMIEnabled) { //On connect, allow bypass to draw once to FB - ctx->pendingHDMI = true; - } else { //On disconnect, close immediately (there will be no bypass) - handleHDMIStateChange(dev, ctx->mHDMIEnabled); - } -#endif -} - -static bool isValidDestination(const framebuffer_device_t* fbDev, const hwc_rect_t& rect) -{ - if (!fbDev) { - LOGE("%s: fbDev is null", __FUNCTION__); - return false; - } - - int dest_width = (rect.right - rect.left); - int dest_height = (rect.bottom - rect.top); - - if (rect.left < 0 || rect.right < 0 || rect.top < 0 || rect.bottom < 0 - || dest_width <= 0 || dest_height <= 0) { - LOGE("%s: destination: left=%d right=%d top=%d bottom=%d width=%d" - "height=%d", __FUNCTION__, rect.left, rect.right, rect.top, - rect.bottom, dest_width, dest_height); - return false; - } - - if ((rect.left+dest_width) > fbDev->width || (rect.top+dest_height) > fbDev->height) { - LOGE("%s: destination out of bound params", __FUNCTION__); - return false; - } - - return true; -} - -static int getYUVBufferCount (const hwc_layer_list_t* list) { - int yuvBufferCount = 0; - if (list) { - for (size_t i=0 ; inumHwLayers; i++) { - private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; - if (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO) && - !(list->hwLayers[i].flags & HWC_DO_NOT_USE_OVERLAY)) { - yuvBufferCount++; - if (yuvBufferCount > 1) { - break; - } - } - } - } - return yuvBufferCount; -} - -static int getS3DVideoFormat (const hwc_layer_list_t* list) { - int s3dFormat = 0; - if (list) { - for (size_t i=0; inumHwLayers; i++) { - private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; - if (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO)) - s3dFormat = FORMAT_3D_INPUT(hnd->format); - if (s3dFormat) - break; - } - } - return s3dFormat; -} - -static int getS3DFormat (const hwc_layer_list_t* list) { - int s3dFormat = 0; - if (list) { - for (size_t i=0; inumHwLayers; i++) { - private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; - if (hnd) - s3dFormat = FORMAT_3D_INPUT(hnd->format); - if (s3dFormat) - break; - } - } - return s3dFormat; -} - - -static int getLayerS3DFormat (hwc_layer_t &layer) { - int s3dFormat = 0; - private_handle_t *hnd = (private_handle_t *)layer.handle; - if (hnd) - s3dFormat = FORMAT_3D_INPUT(hnd->format); - return s3dFormat; -} -static bool isS3DCompositionRequired() { -#ifdef HDMI_AS_PRIMARY - return overlay::is3DTV(); -#endif - return false; -} - -static void markUILayerForS3DComposition (hwc_layer_t &layer, int s3dVideoFormat) { -#ifdef HDMI_AS_PRIMARY - layer.compositionType = HWC_FRAMEBUFFER; - switch(s3dVideoFormat) { - case HAL_3D_IN_SIDE_BY_SIDE_L_R: - case HAL_3D_IN_SIDE_BY_SIDE_R_L: - layer.hints |= HWC_HINT_DRAW_S3D_SIDE_BY_SIDE; - break; - case HAL_3D_IN_TOP_BOTTOM: - layer.hints |= HWC_HINT_DRAW_S3D_TOP_BOTTOM; - break; - default: - LOGE("%s: Unknown S3D input format 0x%x", __FUNCTION__, s3dVideoFormat); - break; - } -#endif - return; -} - -static int getLayersNotUpdatingCount(const hwc_layer_list_t* list) { - int numLayersNotUpdating = 0; - if (list) { - for (size_t i=0 ; inumHwLayers; i++) { - private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; - if (hnd && (hnd->bufferType != BUFFER_TYPE_VIDEO) && - list->hwLayers[i].flags & HWC_LAYER_NOT_UPDATING) - numLayersNotUpdating++; - } - } - return numLayersNotUpdating; -} - -static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) { - - hwc_context_t* ctx = (hwc_context_t*)(dev); - - if(!ctx) { - LOGE("hwc_prepare invalid context"); - return -1; - } - - private_hwc_module_t* hwcModule = reinterpret_cast( - dev->common.module); - if (!hwcModule) { - LOGE("hwc_prepare invalid module"); -#ifdef COMPOSITION_BYPASS - unlockPreviousBypassBuffers(ctx); - unsetBypassBufferLockState(ctx); -#endif - unlockPreviousOverlayBuffer(ctx); - ExtDispOnly::close(); - return -1; - } - - int yuvBufferCount = 0; - int layerType = 0; - bool isS3DCompositionNeeded = false; - int s3dVideoFormat = 0; - int numLayersNotUpdating = 0; - bool useCopybit = false; - bool isSkipLayerPresent = false; - bool skipComposition = false; - - if (list) { - useCopybit = canUseCopybit(hwcModule->fbDevice, list); - yuvBufferCount = getYUVBufferCount(list); - numLayersNotUpdating = getLayersNotUpdatingCount(list); - skipComposition = canSkipComposition(ctx, yuvBufferCount, - list->numHwLayers, numLayersNotUpdating); - - if (yuvBufferCount == 1) { - s3dVideoFormat = getS3DVideoFormat(list); - if (s3dVideoFormat) - isS3DCompositionNeeded = isS3DCompositionRequired(); - } else if((s3dVideoFormat = getS3DFormat(list))){ - if (s3dVideoFormat) - isS3DCompositionNeeded = isS3DCompositionRequired(); - } else { - unlockPreviousOverlayBuffer(ctx); - } - - if (list->flags & HWC_GEOMETRY_CHANGED) { - if (yuvBufferCount == 1) { - // Inform the gralloc of the current video overlay status - setVideoOverlayStatusInGralloc(ctx, true); - } - } - - for (size_t i=0 ; inumHwLayers ; i++) { - private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle; - - // If there is a single Fullscreen layer, we can bypass it - TBD - // If there is only one video/camera buffer, we can bypass itn - if (list->hwLayers[i].flags & HWC_SKIP_LAYER) { - // During the animaton UI layers are marked as SKIP - // need to still mark the layer for S3D composition - isSkipLayerPresent = true; - skipComposition = false; - //Reset count, so that we end up composing once after animation - //is over, in case of overlay. - ctx->previousLayerCount = -1; - - if (isS3DCompositionNeeded) - markUILayerForS3DComposition(list->hwLayers[i], s3dVideoFormat); - -// LGE_CHANGE_E, [G1_Player][bokyung.kim@lge.com], 20120201, Apply SR 00744210 to fix screen flicker { - ssize_t layer_countdown = ((ssize_t)i) - 1; - // Mark every layer below the SKIP layer to be composed by the GPU - while (layer_countdown >= 0) - { - private_handle_t *countdown_handle = - (private_handle_t *)list->hwLayers[layer_countdown].handle; - if (countdown_handle && (countdown_handle->bufferType == BUFFER_TYPE_VIDEO) - && (yuvBufferCount == 1)) { - unlockPreviousOverlayBuffer(ctx); - } - list->hwLayers[layer_countdown].compositionType = HWC_FRAMEBUFFER; - list->hwLayers[layer_countdown].hints &= ~HWC_HINT_CLEAR_FB; - layer_countdown--; - } -// LGE_CHANGE_E, [G1_Player][bokyung.kim@lge.com], 20120201, Apply SR 00744210 to fix screen flicker } - continue; - } - if (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO) && (yuvBufferCount == 1)) { - int flags = WAIT_FOR_VSYNC; - flags |= (hnd->flags & - private_handle_t::PRIV_FLAGS_SECURE_BUFFER)? - SECURE_OVERLAY_SESSION : 0; - flags |= (1 == list->numHwLayers) ? DISABLE_FRAMEBUFFER_FETCH : 0; - if (!isValidDestination(hwcModule->fbDevice, list->hwLayers[i].displayFrame)) { - list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; - //Even though there are no skip layers, animation is still - //ON and in its final stages. - //Reset count, so that we end up composing once after animation - //is done, if overlay is used. - ctx->previousLayerCount = -1; - skipComposition = false; -#ifdef USE_OVERLAY - } else if(prepareOverlay(ctx, &(list->hwLayers[i]), flags) == 0) { - list->hwLayers[i].compositionType = HWC_USE_OVERLAY; - list->hwLayers[i].hints |= HWC_HINT_CLEAR_FB; - // We've opened the channel. Set the state to open. - ctx->hwcOverlayStatus = HWC_OVERLAY_OPEN; -#endif - } else if (hwcModule->compositionType & (COMPOSITION_TYPE_C2D| - COMPOSITION_TYPE_MDP)) { - //Fail safe path: If drawing with overlay fails, - - //Use C2D if available. - list->hwLayers[i].compositionType = HWC_USE_COPYBIT; - } else { - //If C2D is not enabled fall back to GPU. - list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; - } - if (HWC_USE_OVERLAY != list->hwLayers[i].compositionType) { - unlockPreviousOverlayBuffer(ctx); - skipComposition = false; - } - } else if (getLayerS3DFormat(list->hwLayers[i])) { - int flags = WAIT_FOR_VSYNC; - flags |= (1 == list->numHwLayers) ? DISABLE_FRAMEBUFFER_FETCH : 0; - flags |= (hnd->flags & - private_handle_t::PRIV_FLAGS_SECURE_BUFFER)? - SECURE_OVERLAY_SESSION : 0; -#ifdef USE_OVERLAY - if(prepareOverlay(ctx, &(list->hwLayers[i]), flags) == 0) { - list->hwLayers[i].compositionType = HWC_USE_OVERLAY; - list->hwLayers[i].hints |= HWC_HINT_CLEAR_FB; - // We've opened the channel. Set the state to open. - ctx->hwcOverlayStatus = HWC_OVERLAY_OPEN; - } -#endif - } else if (isS3DCompositionNeeded) { - markUILayerForS3DComposition(list->hwLayers[i], s3dVideoFormat); - } else if (list->hwLayers[i].flags & HWC_USE_ORIGINAL_RESOLUTION) { - list->hwLayers[i].compositionType = HWC_USE_OVERLAY; - list->hwLayers[i].hints |= HWC_HINT_CLEAR_FB; - layerType |= HWC_ORIG_RESOLUTION; - } else if (hnd && hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY) { - //handle later after other layers are handled - } else if (hnd && (hwcModule->compositionType & - (COMPOSITION_TYPE_C2D|COMPOSITION_TYPE_MDP))) { - list->hwLayers[i].compositionType = HWC_USE_COPYBIT; - } else if ((hwcModule->compositionType == COMPOSITION_TYPE_DYN) - && useCopybit) { - list->hwLayers[i].compositionType = HWC_USE_COPYBIT; - } - else { - list->hwLayers[i].compositionType = HWC_FRAMEBUFFER; - } - } - - //Update the stats and pipe config for external-only layers - ExtDispOnly::update(ctx, list); - - if (skipComposition) { - list->flags |= HWC_SKIP_COMPOSITION; - } else { - list->flags &= ~HWC_SKIP_COMPOSITION; - } - -#ifdef COMPOSITION_BYPASS - bool isBypassUsed = true; - bool isDoable = isBypassDoable(dev, yuvBufferCount, list); - //Check if bypass is feasible - if(isDoable && !isSkipLayerPresent) { - if(setupBypass(ctx, list)) { - setBypassLayerFlags(ctx, list); - ctx->bypassState = BYPASS_ON; - } else { - LOGE_IF(BYPASS_DEBUG,"%s: Bypass setup Failed",__FUNCTION__); - isBypassUsed = false; - } - } else { - LOGE_IF(BYPASS_DEBUG,"%s: Bypass not possible[%d,%d]",__FUNCTION__, - isDoable, !isSkipLayerPresent ); - isBypassUsed = false; - } - - //Reset bypass states - if(!isBypassUsed) { - ctx->nPipesUsed = 0; - unsetBypassLayerFlags(list); - if(ctx->bypassState == BYPASS_ON) { - ctx->bypassState = BYPASS_OFF_PENDING; - } - } -#endif - } else { -#ifdef COMPOSITION_BYPASS - unlockPreviousBypassBuffers(ctx); - unsetBypassBufferLockState(ctx); -#endif - unlockPreviousOverlayBuffer(ctx); - } - return 0; -} -// --------------------------------------------------------------------------- -struct range { - int current; - int end; -}; -struct region_iterator : public copybit_region_t { - - region_iterator(hwc_region_t region) { - mRegion = region; - r.end = region.numRects; - r.current = 0; - this->next = iterate; - } - -private: - static int iterate(copybit_region_t const * self, copybit_rect_t* rect) { - if (!self || !rect) { - LOGE("iterate invalid parameters"); - return 0; - } - - region_iterator const* me = static_cast(self); - if (me->r.current != me->r.end) { - rect->l = me->mRegion.rects[me->r.current].left; - rect->t = me->mRegion.rects[me->r.current].top; - rect->r = me->mRegion.rects[me->r.current].right; - rect->b = me->mRegion.rects[me->r.current].bottom; - me->r.current++; - return 1; - } - return 0; - } - - hwc_region_t mRegion; - mutable range r; -}; - -static int drawLayerUsingCopybit(hwc_composer_device_t *dev, hwc_layer_t *layer, EGLDisplay dpy, - EGLSurface surface) -{ - hwc_context_t* ctx = (hwc_context_t*)(dev); - if(!ctx) { - LOGE("drawLayerUsingCopybit null context "); - return -1; - } - - private_hwc_module_t* hwcModule = reinterpret_cast(dev->common.module); - if(!hwcModule) { - LOGE("drawLayerUsingCopybit null module "); - return -1; - } - - private_handle_t *hnd = (private_handle_t *)layer->handle; - if(!hnd) { - LOGE("drawLayerUsingCopybit invalid handle"); - return -1; - } - - // Lock this buffer for read. - genlock_lock_type lockType = GENLOCK_READ_LOCK; - int err = genlock_lock_buffer(hnd, lockType, GENLOCK_MAX_TIMEOUT); - if (GENLOCK_FAILURE == err) { - LOGE("%s: genlock_lock_buffer(READ) failed", __FUNCTION__); - return -1; - } - //render buffer - android_native_buffer_t *renderBuffer = (android_native_buffer_t *)eglGetRenderBufferANDROID(dpy, surface); - if (!renderBuffer) { - LOGE("eglGetRenderBufferANDROID returned NULL buffer"); - genlock_unlock_buffer(hnd); - return -1; - } - private_handle_t *fbHandle = (private_handle_t *)renderBuffer->handle; - if(!fbHandle) { - LOGE("Framebuffer handle is NULL"); - genlock_unlock_buffer(hnd); - return -1; - } - int alignment = 32; - if( HAL_PIXEL_FORMAT_RGB_565 == fbHandle->format ) - alignment = 16; - // Set the copybit source: - copybit_image_t src; - src.w = ALIGN(hnd->width, alignment); - src.h = hnd->height; - src.format = hnd->format; - src.base = (void *)hnd->base; - src.handle = (native_handle_t *)layer->handle; - src.horiz_padding = src.w - hnd->width; - // Initialize vertical padding to zero for now, - // this needs to change to accomodate vertical stride - // if needed in the future - src.vert_padding = 0; - - // Copybit source rect - hwc_rect_t sourceCrop = layer->sourceCrop; - copybit_rect_t srcRect = {sourceCrop.left, sourceCrop.top, - sourceCrop.right, - sourceCrop.bottom}; - - // Copybit destination rect - hwc_rect_t displayFrame = layer->displayFrame; - copybit_rect_t dstRect = {displayFrame.left, displayFrame.top, - displayFrame.right, - displayFrame.bottom}; - - // Copybit dst - copybit_image_t dst; - dst.w = ALIGN(fbHandle->width,alignment); - dst.h = fbHandle->height; - dst.format = fbHandle->format; - dst.base = (void *)fbHandle->base; - dst.handle = (native_handle_t *)renderBuffer->handle; - - copybit_device_t *copybit = hwcModule->copybitEngine; - - int32_t screen_w = displayFrame.right - displayFrame.left; - int32_t screen_h = displayFrame.bottom - displayFrame.top; - int32_t src_crop_width = sourceCrop.right - sourceCrop.left; - int32_t src_crop_height = sourceCrop.bottom -sourceCrop.top; - - float copybitsMaxScale = (float)copybit->get(copybit,COPYBIT_MAGNIFICATION_LIMIT); - float copybitsMinScale = (float)copybit->get(copybit,COPYBIT_MINIFICATION_LIMIT); - - if((layer->transform == HWC_TRANSFORM_ROT_90) || - (layer->transform == HWC_TRANSFORM_ROT_270)) { - //swap screen width and height - int tmp = screen_w; - screen_w = screen_h; - screen_h = tmp; - } - private_handle_t *tmpHnd = NULL; - - if(screen_w <=0 || screen_h<=0 ||src_crop_width<=0 || src_crop_height<=0 ) { - LOGE("%s: wrong params for display screen_w=%d src_crop_width=%d screen_w=%d \ - src_crop_width=%d", __FUNCTION__, screen_w, - src_crop_width,screen_w,src_crop_width); - genlock_unlock_buffer(hnd); - return -1; - } - - float dsdx = (float)screen_w/src_crop_width; - float dtdy = (float)screen_h/src_crop_height; - - float scaleLimitMax = copybitsMaxScale * copybitsMaxScale; - float scaleLimitMin = copybitsMinScale * copybitsMinScale; - if(dsdx > scaleLimitMax || dtdy > scaleLimitMax || dsdx < 1/scaleLimitMin || dtdy < 1/scaleLimitMin) { - LOGE("%s: greater than max supported size dsdx=%f dtdy=%f scaleLimitMax=%f scaleLimitMin=%f", __FUNCTION__,dsdx,dtdy,scaleLimitMax,1/scaleLimitMin); - genlock_unlock_buffer(hnd); - return -1; - } - if(dsdx > copybitsMaxScale || dtdy > copybitsMaxScale || dsdx < 1/copybitsMinScale || dtdy < 1/copybitsMinScale){ - // The requested scale is out of the range the hardware - // can support. - LOGD("%s:%d::Need to scale twice dsdx=%f, dtdy=%f,copybitsMaxScale=%f,copybitsMinScale=%f,screen_w=%d,screen_h=%d \ - src_crop_width=%d src_crop_height=%d",__FUNCTION__,__LINE__, - dsdx,dtdy,copybitsMaxScale,1/copybitsMinScale,screen_w,screen_h,src_crop_width,src_crop_height); - - //Driver makes width and height as even - //that may cause wrong calculation of the ratio - //in display and crop.Hence we make - //crop width and height as even. - src_crop_width = (src_crop_width/2)*2; - src_crop_height = (src_crop_height/2)*2; - - int tmp_w = src_crop_width; - int tmp_h = src_crop_height; - - if (dsdx > copybitsMaxScale || dtdy > copybitsMaxScale ){ - tmp_w = src_crop_width*copybitsMaxScale; - tmp_h = src_crop_height*copybitsMaxScale; - }else if (dsdx < 1/copybitsMinScale ||dtdy < 1/copybitsMinScale ){ - tmp_w = src_crop_width/copybitsMinScale; - tmp_h = src_crop_height/copybitsMinScale; - tmp_w = (tmp_w/2)*2; - tmp_h = (tmp_h/2)*2; - } - LOGD("%s:%d::tmp_w = %d,tmp_h = %d",__FUNCTION__,__LINE__,tmp_w,tmp_h); - - int usage = GRALLOC_USAGE_PRIVATE_ADSP_HEAP | - GRALLOC_USAGE_PRIVATE_MM_HEAP; - - if (0 == alloc_buffer(&tmpHnd, tmp_w, tmp_h, fbHandle->format, usage)){ - copybit_image_t tmp_dst; - copybit_rect_t tmp_rect; - tmp_dst.w = tmp_w; - tmp_dst.h = tmp_h; - tmp_dst.format = tmpHnd->format; - tmp_dst.handle = tmpHnd; - tmp_dst.horiz_padding = src.horiz_padding; - tmp_dst.vert_padding = src.vert_padding; - tmp_rect.l = 0; - tmp_rect.t = 0; - tmp_rect.r = tmp_dst.w; - tmp_rect.b = tmp_dst.h; - //create one clip region - hwc_rect tmp_hwc_rect = {0,0,tmp_rect.r,tmp_rect.b}; - hwc_region_t tmp_hwc_reg = {1,(hwc_rect_t const*)&tmp_hwc_rect}; - region_iterator tmp_it(tmp_hwc_reg); - copybit->set_parameter(copybit,COPYBIT_TRANSFORM,0); - copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, - (layer->blending == HWC_BLENDING_NONE) ? -1 : layer->alpha); - err = copybit->stretch(copybit,&tmp_dst, &src, &tmp_rect, &srcRect, &tmp_it); - if(err < 0){ - LOGE("%s:%d::tmp copybit stretch failed",__FUNCTION__,__LINE__); - if(tmpHnd) - free_buffer(tmpHnd); - genlock_unlock_buffer(hnd); - return err; - } - // copy new src and src rect crop - src = tmp_dst; - srcRect = tmp_rect; - } - } - // Copybit region - hwc_region_t region = layer->visibleRegionScreen; - region_iterator copybitRegion(region); - - copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_WIDTH, renderBuffer->width); - copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_HEIGHT, renderBuffer->height); - copybit->set_parameter(copybit, COPYBIT_TRANSFORM, layer->transform); - copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, - (layer->blending == HWC_BLENDING_NONE) ? -1 : layer->alpha); - copybit->set_parameter(copybit, COPYBIT_PREMULTIPLIED_ALPHA, - (layer->blending == HWC_BLENDING_PREMULT)? COPYBIT_ENABLE : COPYBIT_DISABLE); - copybit->set_parameter(copybit, COPYBIT_DITHER, - (dst.format == HAL_PIXEL_FORMAT_RGB_565)? COPYBIT_ENABLE : COPYBIT_DISABLE); - err = copybit->stretch(copybit, &dst, &src, &dstRect, &srcRect, ©bitRegion); - - if(tmpHnd) - free_buffer(tmpHnd); - - if(err < 0) - LOGE("%s: copybit stretch failed",__FUNCTION__); - - // Unlock this buffer since copybit is done with it. - err = genlock_unlock_buffer(hnd); - if (GENLOCK_FAILURE == err) { - LOGE("%s: genlock_unlock_buffer failed", __FUNCTION__); - } - - return err; -} - -static int drawLayerUsingOverlay(hwc_context_t *ctx, hwc_layer_t *layer) -{ - if (ctx && ctx->mOverlayLibObject) { - private_hwc_module_t* hwcModule = reinterpret_cast(ctx->device.common.module); - if (!hwcModule) { - LOGE("drawLayerUsingLayer null module "); - return -1; - } - private_handle_t *hnd = (private_handle_t *)layer->handle; - overlay::Overlay *ovLibObject = ctx->mOverlayLibObject; - int ret = 0; - - // Lock this buffer for read. - if (GENLOCK_NO_ERROR != genlock_lock_buffer(hnd, GENLOCK_READ_LOCK, - GENLOCK_MAX_TIMEOUT)) { - LOGE("%s: genlock_lock_buffer(READ) failed", __FUNCTION__); - return -1; - } - - ret = ovLibObject->queueBuffer(hnd); - - // Unlock the previously locked buffer, since the overlay has completed reading the buffer - unlockPreviousOverlayBuffer(ctx); - - if (!ret) { - LOGE("drawLayerUsingOverlay queueBuffer failed"); - // Unlock the buffer handle - genlock_unlock_buffer(hnd); - ctx->previousOverlayHandle = NULL; - } else { - // Store the current buffer handle as the one that is to be unlocked after - // the next overlay play call. - ctx->previousOverlayHandle = hnd; - hnd->flags |= private_handle_t::PRIV_FLAGS_HWC_LOCK; - } - - return ret; - } - return -1; -} - -#ifdef COMPOSITION_BYPASS -static int drawLayerUsingBypass(hwc_context_t *ctx, hwc_layer_t *layer, int layer_index) { - - int index = getLayerbypassIndex(layer); - - if(index < 0) { - LOGE("%s: Invalid bypass index (%d)", __FUNCTION__, index); - return -1; - } - - if (ctx && ctx->mOvUI[index]) { - overlay::OverlayUI *ovUI = ctx->mOvUI[index]; - int ret = 0; - - private_handle_t *hnd = (private_handle_t *)layer->handle; - if(!hnd) { - LOGE("%s handle null", __FUNCTION__); - return -1; - } - - ctx->bypassBufferLockState[index] = BYPASS_BUFFER_UNLOCKED; - - if (GENLOCK_FAILURE == genlock_lock_buffer(hnd, GENLOCK_READ_LOCK, - GENLOCK_MAX_TIMEOUT)) { - LOGE("%s: genlock_lock_buffer(READ) failed", __FUNCTION__); - return -1; - } - - ctx->bypassBufferLockState[index] = BYPASS_BUFFER_LOCKED; - - LOGE_IF(BYPASS_DEBUG,"%s: Bypassing layer: %p using pipe: %d",__FUNCTION__, layer, index ); - - ret = ovUI->queueBuffer(hnd); - - if (ret) { - // Unlock the locked buffer - if (GENLOCK_FAILURE == genlock_unlock_buffer(hnd)) { - LOGE("%s: genlock_unlock_buffer failed", __FUNCTION__); - } - ctx->bypassBufferLockState[index] = BYPASS_BUFFER_UNLOCKED; - return -1; - } - } - return 0; -} -#endif - -static int hwc_set(hwc_composer_device_t *dev, - hwc_display_t dpy, - hwc_surface_t sur, - hwc_layer_list_t* list) -{ - hwc_context_t* ctx = (hwc_context_t*)(dev); - if(!ctx) { - LOGE("hwc_set invalid context"); - ExtDispOnly::close(); - return -1; - } - - private_hwc_module_t* hwcModule = reinterpret_cast( - dev->common.module); - if (!hwcModule) { - LOGE("hwc_set invalid module"); -#ifdef COMPOSITION_BYPASS - unlockPreviousBypassBuffers(ctx); - unsetBypassBufferLockState(ctx); -#endif - ExtDispOnly::close(); - unlockPreviousOverlayBuffer(ctx); - return -1; - } - - int ret = 0; - if (list) { - bool bDumpLayers = needToDumpLayers(); // Check need for debugging dumps - for (size_t i=0; inumHwLayers; i++) { - if (bDumpLayers) - dumpLayer(hwcModule->compositionType, list->flags, i, list->hwLayers); - if (list->hwLayers[i].flags & HWC_SKIP_LAYER) { - continue; - } else if(list->hwLayers[i].flags & HWC_USE_EXT_ONLY) { - continue; - //Draw after layers for primary are drawn -#ifdef COMPOSITION_BYPASS - } else if (list->hwLayers[i].flags & HWC_COMP_BYPASS) { - drawLayerUsingBypass(ctx, &(list->hwLayers[i]), i); -#endif - } else if (list->hwLayers[i].compositionType == HWC_USE_OVERLAY) { - drawLayerUsingOverlay(ctx, &(list->hwLayers[i])); - } else if (list->flags & HWC_SKIP_COMPOSITION) { -// LGE_CHANGE_S, [G1_Player][mukyung.jung@lge.com], 20120206, Apply SR 00718706 to fix noise of QCIF contents { - //break; - continue; -// LGE_CHANGE_E, [G1_Player][mukyung.jung@lge.com], 20120206, Apply SR 00718706 to fix noise of QCIF contents } - } else if (list->hwLayers[i].compositionType == HWC_USE_COPYBIT) { - drawLayerUsingCopybit(dev, &(list->hwLayers[i]), (EGLDisplay)dpy, (EGLSurface)sur); - } - } - } else { - //Device in suspended state. Close all the MDP pipes -#ifdef COMPOSITION_BYPASS - ctx->nPipesUsed = 0; -#endif - ctx->hwcOverlayStatus = HWC_OVERLAY_PREPARE_TO_CLOSE; - } - - bool canSkipComposition = list && list->flags & HWC_SKIP_COMPOSITION; - //Draw External-only layers - if(ExtDispOnly::draw(ctx, list) != overlay::NO_ERROR) { - ExtDispOnly::close(); - } - -#ifdef COMPOSITION_BYPASS - unlockPreviousBypassBuffers(ctx); - storeLockedBypassHandle(list, ctx); - // We have stored the handles, unset the current lock states in the context. - unsetBypassBufferLockState(ctx); - closeExtraPipes(ctx); -#if BYPASS_DEBUG - if(canSkipComposition) - LOGE("%s: skipping eglSwapBuffer call", __FUNCTION__); -#endif -#endif - // Do not call eglSwapBuffers if we the skip composition flag is set on the list. - if (dpy && sur && !canSkipComposition) { - EGLBoolean sucess = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur); - if (!sucess) { - ret = HWC_EGL_ERROR; - } else { - CALC_FPS(); - } - } -#if defined HDMI_DUAL_DISPLAY - if(ctx->pendingHDMI) { - handleHDMIStateChange(dev, ctx->mHDMIEnabled); - ctx->pendingHDMI = false; - } -#endif - - hwc_closeOverlayChannels(ctx); - int yuvBufferCount = getYUVBufferCount(list); - setHWCOverlayStatus(ctx, yuvBufferCount); - - return ret; -} - -static int hwc_device_close(struct hw_device_t *dev) -{ - if(!dev) { - LOGE("hwc_device_close null device pointer"); - return -1; - } - - struct hwc_context_t* ctx = (struct hwc_context_t*)dev; - - private_hwc_module_t* hwcModule = reinterpret_cast( - ctx->device.common.module); - // Close the overlay and copybit modules - if(hwcModule->copybitEngine) { - copybit_close(hwcModule->copybitEngine); - hwcModule->copybitEngine = NULL; - } - if(hwcModule->fbDevice) { - framebuffer_close(hwcModule->fbDevice); - hwcModule->fbDevice = NULL; - } - - unlockPreviousOverlayBuffer(ctx); - - if (ctx) { - delete ctx->mOverlayLibObject; - ctx->mOverlayLibObject = NULL; -#ifdef COMPOSITION_BYPASS - for(int i = 0; i < MAX_BYPASS_LAYERS; i++) { - delete ctx->mOvUI[i]; - } - unlockPreviousBypassBuffers(ctx); - unsetBypassBufferLockState(ctx); -#endif - ExtDispOnly::close(); - ExtDispOnly::destroy(); - - free(ctx); - } - return 0; -} - -/*****************************************************************************/ -static int hwc_module_initialize(struct private_hwc_module_t* hwcModule) -{ - - // Open the overlay and copybit modules - hw_module_t const *module; - if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) { - copybit_open(module, &(hwcModule->copybitEngine)); - } - if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) { - framebuffer_open(module, &(hwcModule->fbDevice)); - } - - // get the current composition type - char property[PROPERTY_VALUE_MAX]; - if (property_get("debug.sf.hw", property, NULL) > 0) { - if(atoi(property) == 0) { - //debug.sf.hw = 0 - hwcModule->compositionType = COMPOSITION_TYPE_CPU; - } else { //debug.sf.hw = 1 - // Get the composition type - property_get("debug.composition.type", property, NULL); - if (property == NULL) { - hwcModule->compositionType = COMPOSITION_TYPE_GPU; - } else if ((strncmp(property, "mdp", 3)) == 0) { - hwcModule->compositionType = COMPOSITION_TYPE_MDP; - } else if ((strncmp(property, "c2d", 3)) == 0) { - hwcModule->compositionType = COMPOSITION_TYPE_C2D; - } else if ((strncmp(property, "dyn", 3)) == 0) { - hwcModule->compositionType = COMPOSITION_TYPE_DYN; - } else { - hwcModule->compositionType = COMPOSITION_TYPE_GPU; - } - - if(!hwcModule->copybitEngine) - hwcModule->compositionType = COMPOSITION_TYPE_GPU; - } - } else { //debug.sf.hw is not set. Use cpu composition - hwcModule->compositionType = COMPOSITION_TYPE_CPU; - } - - //Check if composition bypass is enabled - if(property_get("ro.sf.compbypass.enable", property, NULL) > 0) { - if(atoi(property) == 1) { - hwcModule->isBypassEnabled = true; - } - } - - CALC_INIT(); - - return 0; -} - - -static int hwc_device_open(const struct hw_module_t* module, const char* name, - struct hw_device_t** device) -{ - int status = -EINVAL; - - if (!strcmp(name, HWC_HARDWARE_COMPOSER)) { - private_hwc_module_t* hwcModule = reinterpret_cast - (const_cast(module)); - hwc_module_initialize(hwcModule); - struct hwc_context_t *dev; - dev = (hwc_context_t*)malloc(sizeof(*dev)); - - /* initialize our state here */ - memset(dev, 0, sizeof(*dev)); -#ifdef USE_OVERLAY - dev->mOverlayLibObject = new overlay::Overlay(); - if(overlay::initOverlay() == -1) - LOGE("overlay::initOverlay() ERROR!!"); -#else - dev->mOverlayLibObject = NULL; -#endif -#ifdef COMPOSITION_BYPASS - for(int i = 0; i < MAX_BYPASS_LAYERS; i++) { - dev->mOvUI[i] = new overlay::OverlayUI(); - dev->previousBypassHandle[i] = NULL; - } - unsetBypassBufferLockState(dev); - dev->bypassState = BYPASS_OFF; -#endif - ExtDispOnly::init(); -#if defined HDMI_DUAL_DISPLAY - dev->mHDMIEnabled = EXT_DISPLAY_OFF; - dev->pendingHDMI = false; -#endif - dev->previousOverlayHandle = NULL; - dev->hwcOverlayStatus = HWC_OVERLAY_CLOSED; - dev->previousLayerCount = -1; - /* initialize the procs */ - dev->device.common.tag = HARDWARE_DEVICE_TAG; - dev->device.common.version = 0; - dev->device.common.module = const_cast(module); - dev->device.common.close = hwc_device_close; - - dev->device.prepare = hwc_prepare; - dev->device.set = hwc_set; - dev->device.enableHDMIOutput = hwc_enableHDMIOutput; - *device = &dev->device.common; - - status = 0; - } - return status; -} diff --git a/liboverlay/Android.mk b/liboverlay/Android.mk old mode 100755 new mode 100644 index 79e4256..63d7780 --- a/liboverlay/Android.mk +++ b/liboverlay/Android.mk @@ -1,43 +1,20 @@ -# Copyright (C) 2008 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 -# - LOCAL_PATH := $(call my-dir) - include $(CLEAR_VARS) -LOCAL_PRELINK_MODULE := false LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES) -LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libmemalloc -LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include -LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr -LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc +LOCAL_SHARED_LIBRARIES := liblog +LOCAL_SHARED_LIBRARIES += libcutils +LOCAL_SHARED_LIBRARIES += libutils +LOCAL_SHARED_LIBRARIES += libmemalloc +LOCAL_C_INCLUDES := hardware/qcom/display/libgralloc LOCAL_SRC_FILES := \ - overlayLib.cpp \ - overlayLibUI.cpp \ -LOCAL_CFLAGS:= -DLOG_TAG=\"OverlayLib\" + overlay.cpp \ + overlayCtrl.cpp \ + overlayUtils.cpp \ + overlayMdp.cpp \ + overlayRotator.cpp \ + overlayTransitions.cpp -ifeq ($(TARGET_USE_HDMI_AS_PRIMARY),true) -LOCAL_CFLAGS += -DHDMI_AS_PRIMARY -endif -ifeq ($(TARGET_USES_POST_PROCESSING),true) -LOCAL_CFLAGS += -DUSES_POST_PROCESSING -LOCAL_SHARED_LIBRARIES += libmm-abl -LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/pp/inc -LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/lib/ -endif +LOCAL_CFLAGS:= -DLOG_TAG=\"overlay2\" LOCAL_MODULE := liboverlay - -#LGE_CHANGE, for userdebug mode LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) diff --git a/liboverlay/mdpWrapper.h b/liboverlay/mdpWrapper.h new file mode 100644 index 0000000..4cfd3e0 --- /dev/null +++ b/liboverlay/mdpWrapper.h @@ -0,0 +1,270 @@ +/* +* Copyright (c) 2011-2012, 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 MDP_WRAPPER_H +#define MDP_WRAPPER_H + +/* +* In order to make overlay::mdp_wrapper shorter, please do something like: +* namespace mdpwrap = overlay::mdp_wrapper; +* */ + +#include +#include +#include +#include +#include +#include "overlayUtils.h" + +namespace overlay{ + +namespace mdp_wrapper{ +/* FBIOGET_FSCREENINFO */ +bool getFScreenInfo(int fd, fb_fix_screeninfo& finfo); + +/* FBIOGET_VSCREENINFO */ +bool getVScreenInfo(int fd, fb_var_screeninfo& vinfo); + +/* FBIOPUT_VSCREENINFO */ +bool setVScreenInfo(int fd, fb_var_screeninfo& vinfo); + +/* MSM_ROTATOR_IOCTL_START */ +bool startRotator(int fd, msm_rotator_img_info& rot); + +/* MSM_ROTATOR_IOCTL_ROTATE */ +bool rotate(int fd, msm_rotator_data_info& rot); + +/* MSMFB_OVERLAY_SET */ +bool setOverlay(int fd, mdp_overlay& ov); + +/* MSM_ROTATOR_IOCTL_FINISH */ +bool endRotator(int fd, int sessionId); + +/* MSMFB_OVERLAY_UNSET */ +bool unsetOverlay(int fd, int ovId); + +/* MSMFB_OVERLAY_GET */ +bool getOverlay(int fd, mdp_overlay& ov); + +/* MSMFB_OVERLAY_PLAY */ +bool play(int fd, msmfb_overlay_data& od); + +/* MSMFB_OVERLAY_PLAY_WAIT */ +bool playWait(int fd, msmfb_overlay_data& od); + +/* MSMFB_OVERLAY_3D */ +bool set3D(int fd, msmfb_overlay_3d& ov); + +/* the following are helper functions for dumping + * msm_mdp and friends*/ +void dump(const char* const s, const msmfb_overlay_data& ov); +void dump(const char* const s, const msmfb_data& ov); +void dump(const char* const s, const mdp_overlay& ov); +void dump(const char* const s, const msmfb_overlay_3d& ov); +void dump(const char* const s, const uint32_t u[], uint32_t cnt); +void dump(const char* const s, const msmfb_img& ov); +void dump(const char* const s, const mdp_rect& ov); + +/* and rotator */ +void dump(const char* const s, const msm_rotator_img_info& rot); +void dump(const char* const s, const msm_rotator_data_info& rot); + +/* info */ +void dump(const char* const s, const fb_fix_screeninfo& finfo); +void dump(const char* const s, const fb_var_screeninfo& vinfo); + +//---------------Inlines ------------------------------------- + +inline bool getFScreenInfo(int fd, fb_fix_screeninfo& finfo) { + if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) { + ALOGE("Failed to call ioctl FBIOGET_FSCREENINFO err=%d", errno); + return false; + } + return true; +} + +inline bool getVScreenInfo(int fd, fb_var_screeninfo& vinfo) { + if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1) { + ALOGE("Failed to call ioctl FBIOGET_VSCREENINFO err=%d", errno); + return false; + } + return true; +} + +inline bool setVScreenInfo(int fd, fb_var_screeninfo& vinfo) { + if (ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo) == -1) { + ALOGE("Failed to call ioctl FBIOPUT_VSCREENINFO err=%d", errno); + return false; + } + return true; +} + +inline bool startRotator(int fd, msm_rotator_img_info& rot) { + if (ioctl(fd, MSM_ROTATOR_IOCTL_START, &rot) == -1){ + ALOGE("Failed to call ioctl MSM_ROTATOR_IOCTL_START err=%d", errno); + return false; + } + return true; +} + +inline bool rotate(int fd, msm_rotator_data_info& rot) { + if (ioctl(fd, MSM_ROTATOR_IOCTL_ROTATE, &rot) == -1) { + ALOGE("Failed to call ioctl MSM_ROTATOR_IOCTL_ROTATE err=%d", errno); + return false; + } + return true; +} + +inline bool setOverlay(int fd, mdp_overlay& ov) { + if (ioctl(fd, MSMFB_OVERLAY_SET, &ov) == -1) { + ALOGE("Failed to call ioctl MSMFB_OVERLAY_SET err=%d", errno); + return false; + } + return true; +} + +inline bool endRotator(int fd, int sessionId) { + if (ioctl(fd, MSM_ROTATOR_IOCTL_FINISH, &sessionId) == -1) { + ALOGE("Failed to call ioctl MSM_ROTATOR_IOCTL_FINISH err=%d", errno); + return false; + } + return true; +} + +inline bool unsetOverlay(int fd, int ovId) { + if (ioctl(fd, MSMFB_OVERLAY_UNSET, &ovId) == -1) { + ALOGE("Failed to call ioctl MSMFB_OVERLAY_UNSET err=%d", errno); + return false; + } + return true; +} + +inline bool getOverlay(int fd, mdp_overlay& ov) { + if (ioctl(fd, MSMFB_OVERLAY_GET, &ov) == -1) { + ALOGE("Failed to call ioctl MSMFB_OVERLAY_GET err=%d", errno); + return false; + } + return true; +} + +inline bool play(int fd, msmfb_overlay_data& od) { + if (ioctl(fd, MSMFB_OVERLAY_PLAY, &od) == -1) { + ALOGE("Failed to call ioctl MSMFB_OVERLAY_PLAY err=%d", errno); + return false; + } + return true; +} + +inline bool playWait(int fd, msmfb_overlay_data& od) { + if (ioctl(fd, MSMFB_OVERLAY_PLAY_WAIT, &od) == -1) { + ALOGE("Failed to call ioctl MSMFB_OVERLAY_PLAY_WAIT err=%d", errno); + return false; + } + return true; +} + +inline bool set3D(int fd, msmfb_overlay_3d& ov) { + if (ioctl(fd, MSMFB_OVERLAY_3D, &ov) == -1) { + ALOGE("Failed to call ioctl MSMFB_OVERLAY_3D err=%d", errno); + return false; + } + return true; +} + +/* dump funcs */ +inline void dump(const char* const s, const msmfb_overlay_data& ov) { + ALOGE("%s msmfb_overlay_data id=%d", + s, ov.id); + dump("data", ov.data); +} +inline void dump(const char* const s, const msmfb_data& ov) { + ALOGE("%s msmfb_data offset=%d memid=%d id=%d flags=0x%x priv=%d", + s, ov.offset, ov.memory_id, ov.id, ov.flags, ov.priv); +} +inline void dump(const char* const s, const mdp_overlay& ov) { + ALOGE("%s mdp_overlay z=%d fg=%d alpha=%d mask=%d flags=0x%x id=%d", + s, ov.z_order, ov.is_fg, ov.alpha, + ov.transp_mask, ov.flags, ov.id); + dump("src", ov.src); + dump("src_rect", ov.src_rect); + dump("dst_rect", ov.dst_rect); + dump("user_data", ov.user_data, + sizeof(ov.user_data)/sizeof(ov.user_data[0])); +} +inline void dump(const char* const s, const msmfb_img& ov) { + ALOGE("%s msmfb_img w=%d h=%d format=%d %s", + s, ov.width, ov.height, ov.format, + overlay::utils::getFormatString(ov.format)); +} +inline void dump(const char* const s, const mdp_rect& ov) { + ALOGE("%s mdp_rect x=%d y=%d w=%d h=%d", + s, ov.x, ov.y, ov.w, ov.h); +} + +inline void dump(const char* const s, const msmfb_overlay_3d& ov) { + ALOGE("%s msmfb_overlay_3d 3d=%d w=%d h=%d", + s, ov.is_3d, ov.width, ov.height); + +} +inline void dump(const char* const s, const uint32_t u[], uint32_t cnt) { + ALOGE("%s user_data cnt=%d", s, cnt); + for(uint32_t i=0; i < cnt; ++i) { + ALOGE("i=%d val=%d", i, u[i]); + } +} +inline void dump(const char* const s, const msm_rotator_img_info& rot) { + ALOGE("%s msm_rotator_img_info sessid=%d dstx=%d dsty=%d rot=%d, ena=%d", + s, rot.session_id, rot.dst_x, rot.dst_y, + rot.rotations, rot.enable); + dump("src", rot.src); + dump("dst", rot.dst); + dump("src_rect", rot.src_rect); +} +inline void dump(const char* const s, const msm_rotator_data_info& rot) { + ALOGE("%s msm_rotator_data_info sessid=%d verkey=%d", + s, rot.session_id, rot.version_key); + dump("src", rot.src); + dump("dst", rot.dst); + dump("src_chroma", rot.src_chroma); + dump("dst_chroma", rot.dst_chroma); +} +inline void dump(const char* const s, const fb_fix_screeninfo& finfo) { + ALOGE("%s fb_fix_screeninfo type=%d", s, finfo.type); +} +inline void dump(const char* const s, const fb_var_screeninfo& vinfo) { + ALOGE("%s fb_var_screeninfo xres=%d yres=%d", + s, vinfo.xres, vinfo.yres); +} + + +} // mdp_wrapper + +} // overlay + +#endif // MDP_WRAPPER_H diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp new file mode 100644 index 0000000..ed968c1 --- /dev/null +++ b/liboverlay/overlay.cpp @@ -0,0 +1,455 @@ +/* +* Copyright (c) 2011-2012, 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 "overlayUtils.h" +#include "overlayImpl.h" +#include "overlay.h" + +// MDP related FIXME move to state +#include "overlayMdp.h" +#include "overlayCtrlData.h" +#include "overlayRotator.h" + +namespace overlay { + +Overlay::Overlay(): mOv(0) { +} + +Overlay::~Overlay() { + if(mState.state() == utils::OV_CLOSED) return; + close(); + delete mOv; + mOv = 0; +} + +bool Overlay::open() { + // We need an empty open to just open the bare minimum for business + return true; +} + +void Overlay::reset(){ + if(mOv && !mOv->close()) { + ALOGE("%s Overlay failed", __FUNCTION__); + } + + delete mOv; + mOv = 0; +} + +bool Overlay::close() +{ + OVASSERT(mOv, + "%s Overlay and Rotator should be init at this point", + __FUNCTION__); + // FIXME that one needs to move to the state machine class + utils::eOverlayState st = mState.state(); + switch (st) { + case utils::OV_CLOSED: + // try to close any partially opened items + break; + case utils::OV_2D_VIDEO_ON_PANEL: + case utils::OV_2D_VIDEO_ON_PANEL_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + case utils::OV_UI_MIRROR: + case utils::OV_2D_TRUE_UI_MIRROR: + case utils::OV_BYPASS_1_LAYER: + case utils::OV_BYPASS_2_LAYER: + case utils::OV_BYPASS_3_LAYER: + mOv = mState.handleEvent(utils::OV_CLOSED, mOv); + this->reset(); + break; + default: + OVASSERT(false, "close Unknown state %d", st); + return false; + } + return true; +} + +bool Overlay::commit(utils::eDest dest) +{ + OVASSERT(mOv, + "%s Overlay and Rotator should be init at this point", + __FUNCTION__); + // FIXME that one needs to move to the state machine class + utils::eOverlayState st = mState.state(); + switch (st) { + case utils::OV_2D_VIDEO_ON_PANEL: + case utils::OV_2D_VIDEO_ON_PANEL_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + case utils::OV_UI_MIRROR: + case utils::OV_2D_TRUE_UI_MIRROR: + case utils::OV_BYPASS_1_LAYER: + case utils::OV_BYPASS_2_LAYER: + case utils::OV_BYPASS_3_LAYER: + if(!mOv->commit(dest)) { + ALOGE("Overlay %s failed", __FUNCTION__); + return false; + } + break; + default: + OVASSERT(false, "%s Unknown state %d", __FUNCTION__, st); + return false; + } + return true; +} + +bool Overlay::queueBuffer(uint32_t offset, + utils::eDest dest) +{ + OVASSERT(mOv, + "%s Overlay and Rotator should be init at this point", + __FUNCTION__); + // FIXME that one needs to move to the state machine class + utils::eOverlayState st = mState.state(); + switch (st) { + case utils::OV_2D_VIDEO_ON_PANEL: + case utils::OV_2D_VIDEO_ON_PANEL_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + case utils::OV_UI_MIRROR: + case utils::OV_2D_TRUE_UI_MIRROR: + case utils::OV_BYPASS_1_LAYER: + case utils::OV_BYPASS_2_LAYER: + case utils::OV_BYPASS_3_LAYER: + if(!mOv->queueBuffer(offset, dest)) { + ALOGE("Overlay %s failed", __FUNCTION__); + return false; + } + break; + default: + OVASSERT(false, "%s Unknown state %d", __FUNCTION__, st); + return false; + } + return true; +} + +bool Overlay::dequeueBuffer(void*& buf, + utils::eDest dest) +{ + OVASSERT(mOv, + "%s Overlay and Rotator should be init at this point", + __FUNCTION__); + // FIXME that one needs to move to the state machine class + utils::eOverlayState st = mState.state(); + switch (st) { + case utils::OV_2D_VIDEO_ON_PANEL: + case utils::OV_2D_VIDEO_ON_PANEL_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + case utils::OV_UI_MIRROR: + case utils::OV_2D_TRUE_UI_MIRROR: + case utils::OV_BYPASS_1_LAYER: + case utils::OV_BYPASS_2_LAYER: + case utils::OV_BYPASS_3_LAYER: + if(!mOv->dequeueBuffer(buf, dest)) { + ALOGE("Overlay %s failed", __FUNCTION__); + return false; + } + break; + default: + OVASSERT(false, "%s Unknown state %d", __FUNCTION__, st); + return false; + } + return true; +} + +bool Overlay::waitForVsync(utils::eDest dest) +{ + OVASSERT(mOv, + "%s Overlay and Rotator should be init at this point", + __FUNCTION__); + // FIXME that one needs to move to the state machine class + utils::eOverlayState st = mState.state(); + switch (st) { + case utils::OV_2D_VIDEO_ON_PANEL: + case utils::OV_2D_VIDEO_ON_PANEL_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + case utils::OV_UI_MIRROR: + case utils::OV_2D_TRUE_UI_MIRROR: + case utils::OV_BYPASS_1_LAYER: + case utils::OV_BYPASS_2_LAYER: + case utils::OV_BYPASS_3_LAYER: + if(!mOv->waitForVsync(dest)) { + ALOGE("Overlay %s failed", __FUNCTION__); + return false; + } + break; + default: + OVASSERT(false, "%s Unknown state %d", __FUNCTION__, st); + return false; + } + return true; +} + +bool Overlay::setCrop(const utils::Dim& d, + utils::eDest dest) +{ + OVASSERT(mOv, + "%s Overlay and Rotator should be init at this point", + __FUNCTION__); + // FIXME that one needs to move to the state machine class + utils::eOverlayState st = mState.state(); + switch (st) { + case utils::OV_2D_VIDEO_ON_PANEL: + case utils::OV_2D_VIDEO_ON_PANEL_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + case utils::OV_UI_MIRROR: + case utils::OV_2D_TRUE_UI_MIRROR: + case utils::OV_BYPASS_1_LAYER: + case utils::OV_BYPASS_2_LAYER: + case utils::OV_BYPASS_3_LAYER: + if(!mOv->setCrop(d, dest)) { + ALOGE("Overlay %s failed", __FUNCTION__); + return false; + } + break; + default: + OVASSERT(false, "%s Unknown state %d", __FUNCTION__, st); + return false; + } + return true; +} +bool Overlay::setPosition(const utils::Dim& d, + utils::eDest dest) +{ + OVASSERT(mOv, + "%s Overlay and Rotator should be init at this point", + __FUNCTION__); + // FIXME that one needs to move to the state machine class + utils::eOverlayState st = mState.state(); + switch (st) { + case utils::OV_2D_VIDEO_ON_PANEL: + case utils::OV_2D_VIDEO_ON_PANEL_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + case utils::OV_UI_MIRROR: + case utils::OV_2D_TRUE_UI_MIRROR: + case utils::OV_BYPASS_1_LAYER: + case utils::OV_BYPASS_2_LAYER: + case utils::OV_BYPASS_3_LAYER: + if(!mOv->setPosition(d, dest)) { + ALOGE("Overlay %s failed", __FUNCTION__); + return false; + } + break; + default: + OVASSERT(false, "setPos Unknown state %d", st); + return false; + } + return true; +} +bool Overlay::setParameter(const utils::Params& param, + utils::eDest dest) +{ + OVASSERT(mOv, + "%s Overlay and Rotator should be init at this point", + __FUNCTION__); + // FIXME that one needs to move to the state machine class + utils::eOverlayState st = mState.state(); + switch (st) { + case utils::OV_2D_VIDEO_ON_PANEL: + case utils::OV_2D_VIDEO_ON_PANEL_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + case utils::OV_UI_MIRROR: + case utils::OV_2D_TRUE_UI_MIRROR: + case utils::OV_BYPASS_1_LAYER: + case utils::OV_BYPASS_2_LAYER: + case utils::OV_BYPASS_3_LAYER: + if(!mOv->setParameter(param, dest)) { + ALOGE("Overlay %s failed", __FUNCTION__); + return false; + } + break; + default: + OVASSERT(false, "%s Unknown state %d", __FUNCTION__ , st); + return false; + } + return true; +} +bool Overlay::setSource(const utils::PipeArgs args[utils::MAX_PIPES], + utils::eDest dest) +{ + // FIXME that one needs to move to the state machine class + utils::PipeArgs margs[utils::MAX_PIPES] = { + args[0], args[1], args[2] }; + utils::eOverlayState st = mState.state(); + + switch (st) { + case utils::OV_CLOSED: + // if we get setSource when we are closed, then + // we will assume tranistion to OV_2D_VIDEO_ON_PANEL + // returns overlay + mOv = mState.handle_closed(utils::OV_2D_VIDEO_ON_PANEL); + if (!mOv) { + ALOGE("Overlay %s failed", __FUNCTION__); + this->reset(); // cleanup + return false; + } + break; + case utils::OV_2D_VIDEO_ON_PANEL: + case utils::OV_3D_VIDEO_ON_2D_PANEL: + case utils::OV_UI_MIRROR: + case utils::OV_BYPASS_1_LAYER: + case utils::OV_BYPASS_2_LAYER: + case utils::OV_BYPASS_3_LAYER: + // no tweaking + break; + case utils::OV_3D_VIDEO_ON_3D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_TV: + margs[utils::CHANNEL_1].zorder = utils::ZORDER_1; + break; + case utils::OV_2D_VIDEO_ON_PANEL_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + // If displaying on both, external VG pipe set to be no wait + margs[utils::CHANNEL_1].wait = utils::NO_WAIT; + break; + case utils::OV_2D_TRUE_UI_MIRROR: + // Set zorder -- external VG pipe (video) gets 0, RGB pipe (UI) gets 1 + margs[utils::CHANNEL_1].zorder = utils::ZORDER_0; + margs[utils::CHANNEL_2].zorder = utils::ZORDER_1; + // External VG (video) and RGB (UI) pipe set to be no wait + margs[utils::CHANNEL_0].wait = utils::WAIT; + margs[utils::CHANNEL_1].wait = utils::NO_WAIT; + margs[utils::CHANNEL_2].wait = utils::NO_WAIT; + break; + default: + OVASSERT(false, "%s Unknown state %d", __FUNCTION__, st); + return false; + } + + if (!mOv->setSource(margs, dest)) { + ALOGE("Overlay %s failed", __FUNCTION__); + return false; + } + + return true; +} +void Overlay::setMemoryId(int id, utils::eDest dest) +{ + OVASSERT(mOv, + "%s Overlay and Rotator should be init at this point", + __FUNCTION__); + // FIXME that one needs to move to the state machine class + utils::eOverlayState st = mState.state(); + switch (st) { + case utils::OV_2D_VIDEO_ON_PANEL: + case utils::OV_2D_VIDEO_ON_PANEL_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_PANEL: + case utils::OV_3D_VIDEO_ON_3D_TV: + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + case utils::OV_UI_MIRROR: + case utils::OV_2D_TRUE_UI_MIRROR: + case utils::OV_BYPASS_1_LAYER: + case utils::OV_BYPASS_2_LAYER: + case utils::OV_BYPASS_3_LAYER: + mOv->setMemoryId(id, dest); + break; + default: + OVASSERT(false, "setMemId Unknown state %d", st); + } +} + + +void Overlay::dump() const +{ + OVASSERT(mOv, + "%s Overlay and Rotator should be init at this point", + __FUNCTION__); + // FIXME dump tate object, factory + ALOGE("== Dump Overlay start =="); + mState.dump(); + mOv->dump(); + ALOGE("== Dump Overlay end =="); +} + +void Overlay::setState(utils::eOverlayState s) { + mOv = mState.handleEvent(s, mOv); +} + +utils::eOverlayState Overlay::getState() const { + return mState.state(); +} + +Overlay *Overlay::sInstance = 0; + +Overlay* Overlay::getInstance() { + if(sInstance == NULL) + sInstance = new Overlay(); + return sInstance; +} + +/**** NullPipe ****/ + +bool NullPipe::open(RotatorBase*) { + ALOGE_IF(DEBUG_OVERLAY, "NullPipe open"); + return true; +} +bool NullPipe::close() { return true; } +bool NullPipe::commit() { return true; } +bool NullPipe::start(const utils::PipeArgs&) { return true; } +bool NullPipe::setCrop(const utils::Dim&) { return true; } +bool NullPipe::setPosition(const utils::Dim&) { return true; } +bool NullPipe::setParameter(const utils::Params&) { return true; } +bool NullPipe::setSource(const utils::PipeArgs&) { return true; } +bool NullPipe::queueBuffer(uint32_t offset) { return true; } +bool NullPipe::dequeueBuffer(void*&) { return true; } +bool NullPipe::waitForVsync() { return true; } +void NullPipe::setMemoryId(int) {} +// NullPipe will return by val here as opposed to other Pipes. +utils::PipeArgs NullPipe::getArgs() const { return utils::PipeArgs(); } +utils::eOverlayPipeType NullPipe::getOvPipeType() const { + return utils::OV_PIPE_TYPE_NULL; +} +void NullPipe::dump() const { + ALOGE("== NullPipe (null) start/end =="); +} + +} // overlay diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h new file mode 100644 index 0000000..e2ee6cd --- /dev/null +++ b/liboverlay/overlay.h @@ -0,0 +1,103 @@ +/* +* Copyright (c) 2011-2012, 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 OVERLAY_H +#define OVERLAY_H + +#include "overlayUtils.h" +#include "overlayState.h" +#include "overlayImpl.h" + +namespace overlay { +/**/ +class Overlay : utils::NoCopy { +public: + /* dtor close */ + ~Overlay(); + + /* Overlay related func */ + + /* We need an empty open to just open the bare minimum for + * business. */ + bool open(); + + /* close rotator, state, overlayimpl*/ + bool close(); + + /* Following is the same as the pure virt interface in ov impl */ + + bool commit(utils::eDest dest = utils::OV_PIPE_ALL); + + bool queueBuffer(uint32_t offset, + utils::eDest dest = utils::OV_PIPE_ALL); + bool dequeueBuffer(void*& buf, + utils::eDest dest = utils::OV_PIPE_ALL); + bool waitForVsync(utils::eDest dest = utils::OV_PIPE1); + bool setCrop(const utils::Dim& d, + utils::eDest dest = utils::OV_PIPE_ALL); + bool setPosition(const utils::Dim& dim, + utils::eDest dest = utils::OV_PIPE_ALL); + bool setParameter(const utils::Params& param, + utils::eDest dest = utils::OV_PIPE_ALL); + bool setSource(const utils::PipeArgs args[utils::MAX_PIPES], + utils::eDest dest = utils::OV_PIPE_ALL); + void setMemoryId(int id, utils::eDest dest = utils::OV_PIPE_ALL); + void dump() const; + + /* state related functions */ + void setState(utils::eOverlayState s); + + /* expose state */ + utils::eOverlayState getState() const; + + /* Returns the singleton instance of overlay */ + static Overlay* getInstance(); + +private: + /* Ctor setup */ + Overlay(); + + /* reset all pointers */ + void reset(); + + /* Holds the state, state transition logic + * In the meantime, using simple enum rather than + * a class */ + OverlayState mState; + + /* Holds the actual overlay impl, set when changing state*/ + OverlayImplBase *mOv; + + /* Singleton Instance*/ + static Overlay *sInstance; +}; + +} // overlay + +#endif // OVERLAY_H diff --git a/liboverlay/overlayCtrl.cpp b/liboverlay/overlayCtrl.cpp new file mode 100644 index 0000000..6f84d07 --- /dev/null +++ b/liboverlay/overlayCtrl.cpp @@ -0,0 +1,349 @@ +/* +* Copyright (C) 2008 The Android Open Source Project +* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. +* +* 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. +*/ + +#include +#include "overlayCtrlData.h" +#include "fb_priv.h" + +namespace overlay{ + +bool Ctrl::open(uint32_t fbnum, + RotatorBase* rot) { + // MDP/FD open + if(!mMdp.open(fbnum)) { + ALOGE("Ctrl failed to open fbnum=%d", fbnum); + return false; + } + + if(!getScreenInfo(mInfo)) { + ALOGE("Ctrl failed to getScreenInfo"); + return false; + } + + OVASSERT(rot, "rot is null"); + mRot = rot; + // rot should be already opened + + return true; +} + +bool Ctrl::start(const utils::PipeArgs& args) +{ + int colorFormat = utils::getColorFormat(args.whf.format); + utils::eMdpFlags flags = args.mdpFlags; + + //XXX: Support for interlaced content + if (0) { + + setMdpFlags(flags, utils::OV_MDP_DEINTERLACE); + + // Get the actual format + colorFormat = args.whf.format ^ HAL_PIXEL_FORMAT_INTERLACE; + } + utils::Whf hwwhf(args.whf); + int fmt = utils::getMdpFormat(colorFormat); + // FIXME format should probably be int and not uint + if (fmt < 0) { + ALOGE("Ctrl failed getMdpFormat unsopported " + "colorFormat=%d format=%d flags=%d", + colorFormat, fmt, flags); + return false; + } + hwwhf.format = fmt; + + // devices should be already opened + // (by calling open earlier in the flow) + + const utils::PipeArgs newargs(flags, // mdp flags + args.orientation, // trans + hwwhf, + args.wait, + args.zorder, + args.isFg, + args.rotFlags); + if (!setInfo(newargs)) { + ALOGE("Ctrl failed to setInfo mdpflags=%d wait=%d zorder=%d", + newargs.mdpFlags, newargs.wait, newargs.zorder); + hwwhf.dump(); + return false; + } + + // FIXME, can we remove that and have it in + // setSource only when source changed? + if(!mRot->start(newargs)) { + ALOGE("Ctrl failed to start Rotation session"); + return false; + } + + // if geom is different, we need to prepare a new rot buffers. + // remap on demand when the current orientation is 90,180, etc. + // and the prev orientation was 0. It means we go from orient + if(!mRot->remap(utils::ROT_NUM_BUFS, newargs)) { + ALOGE("%s Error in remapping", __FUNCTION__); + } + + if(!mMdp.set()) { + ALOGE("Ctrl start failed set overlay"); + return false; + } + + // cache the src to be the current mCrop vals + mCrop.w = hwwhf.w; + mCrop.h = hwwhf.h; + + return true; +} + +inline void Ctrl::updateSource(RotatorBase* r, + const utils::PipeArgs& args, + utils::ScreenInfo& info) +{ + mMdp.updateSource(r, args, info); +} + +bool Ctrl::setSource(const utils::PipeArgs& args) +{ + mMdp.setWait(args.wait); + + utils::PipeArgs newargs(args); + utils::Whf whf(args.whf); + // check geom change + if(mOvBufInfo != whf) { + // whf.format is given as HAL, that is why it is + // needed to be MDP fmt. + whf.format = utils::getColorFormat(whf.format); + int fmt = utils::getMdpFormat(whf.format); + OVASSERT(-1 != fmt, "Ctrl setSource format is -1"); + whf.format = fmt; + newargs.whf = whf; + updateSource(mRot, newargs, mInfo); + mMdp.setUserData(0); + if(!mRot->start(newargs)) { + ALOGE("%s failed start rot", __FUNCTION__); + return false; + } + + // if geom is different, we need to prepare a new rot buffers. + // remap on demand when the current orientation is 90,180, etc. + // and the prev orientation was 0. It means we go from orient + if(!mRot->remap(utils::ROT_NUM_BUFS, newargs)) { + ALOGE("%s Error in remapping", __FUNCTION__); + } + } + + // needed for setSource + mOrient = args.orientation; + + // cache last whf from gralloc hnd + mOvBufInfo = args.whf; + + // orign impl is returning false here + // because they will close the overlay and reopen it. + // New design would not do that. + return true; +} + +bool Ctrl::setPosition(const utils::Dim& dim) +{ + if(!dim.check(mInfo.mFBWidth, mInfo.mFBHeight)) { + ALOGE("Ctrl setPosition error in dim"); + dim.dump(); + return false; + } + + if(!mMdp.setPosition(dim, mInfo.mFBWidth, mInfo.mFBHeight)) { + ALOGE("Ctrl failed MDP setPosition"); + return false; + } + return true; +} + +bool Ctrl::setParameter(const utils::Params& p) +{ + if (utils::OVERLAY_TRANSFORM == p.param && + p.value == mMdp.getUserData()) { + // nothing to do here + return true; + } + + utils::eTransform trns = static_cast(p.value); + switch (p.param) { + case utils::OVERLAY_DITHER: + // nothing here today + ALOGE("Ctrl setParameter OVERLAY_DITHER not impl"); + return true; + case utils::OVERLAY_TRANSFORM: + if(!mRot->overlayTransform(mMdp, trns)) { + ALOGE("Ctrl setParameter failed Rot overlayTransform"); + return false; + } + break; + default: + ALOGE("Ctrl setParameter unknown param %d", p.param); + return false; + } + return true; +} + +bool Ctrl::setCrop(const utils::Dim& d) +{ + // FIXME check channel validity + if(!mMdp.setCrop(d)) { + ALOGE("Data setCrop failed in MDP setCrop"); + return false; + } + mCrop = d; + return true; +} + +utils::Dim Ctrl::getAspectRatio(const utils::Whf& whf) const +{ + utils::Whf inWhf(whf.w, whf.h, mMdp.getSrcWhf().format); + utils::Whf tmpwhf(inWhf); + uint32_t fbWidth = mInfo.mFBWidth; + uint32_t fbHeight = mInfo.mFBHeight; + + /* Calculate the width and height if it is YUV TILE format*/ + if (inWhf.format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED) { + tmpwhf.w = whf.w - (utils::alignup(whf.w, 64) - whf.w); + tmpwhf.h = whf.h - (utils::alignup(whf.h, 32) - whf.h); + } + if (inWhf.w * fbHeight > fbWidth * inWhf.h) { + inWhf.h = fbWidth * inWhf.h / inWhf.w; + utils::even_out(inWhf.h); + inWhf.w = fbWidth; + } else if (inWhf.w * fbHeight < fbWidth * inWhf.h) { + inWhf.w = fbHeight * inWhf.w / inWhf.h; + utils::even_out(inWhf.w); + inWhf.h = fbHeight; + } else { + inWhf.w = fbWidth; + inWhf.h = fbHeight; + } + /* Scaling of upto a max of 8 times supported */ + if (inWhf.w > (tmpwhf.w * utils::HW_OV_MAGNIFICATION_LIMIT)){ + inWhf.w = utils::HW_OV_MAGNIFICATION_LIMIT * tmpwhf.w; + } + if(inWhf.h > (tmpwhf.h * utils::HW_OV_MAGNIFICATION_LIMIT)) { + inWhf.h = utils::HW_OV_MAGNIFICATION_LIMIT * tmpwhf.h; + } + if (inWhf.w > fbWidth) inWhf.w = fbWidth; + if (inWhf.h > fbHeight) inWhf.h = fbHeight; + + char value[PROPERTY_VALUE_MAX]; + property_get("hw.actionsafe.width", value, "0"); + float asWidth = atof(value); + property_get("hw.actionsafe.height", value, "0"); + float asHeight = atof(value); + inWhf.w = inWhf.w * (1.0f - asWidth / 100.0f); + inWhf.h = inWhf.h * (1.0f - asHeight / 100.0f); + + uint32_t x = (fbWidth - inWhf.w) / 2.0; + uint32_t y = (fbHeight - inWhf.h) / 2.0; + return utils::Dim(x, y, inWhf.w, inWhf.h); +} + +utils::FrameBufferInfo* utils::FrameBufferInfo::sFBInfoInstance = 0; + +// This function gets the destination position for external display +// based on the position and aspect ratio of the primary +utils::Dim Ctrl::getAspectRatio(const utils::Dim& dim) const { + float priWidth = utils::FrameBufferInfo::getInstance()->getWidth(); + float priHeight = utils::FrameBufferInfo::getInstance()->getHeight(); + float fbWidth = mInfo.mFBWidth; + float fbHeight = mInfo.mFBHeight; + float wRatio = 1.0; + float hRatio = 1.0; + float xRatio = 1.0; + float yRatio = 1.0; + utils::Dim inDim(dim); + + int xPos = 0; + int yPos = 0; + int tmp = 0; + utils::Dim tmpDim; + switch(inDim.o) { + case MDP_ROT_NOP: + case MDP_ROT_180: + { + utils::Whf whf((uint32_t) priWidth, (uint32_t) priHeight, 0); + tmpDim = getAspectRatio(whf); + xPos = tmpDim.x; + yPos = tmpDim.y; + fbWidth = tmpDim.w; + fbHeight = tmpDim.h; + + if (inDim.o == MDP_ROT_180) { + inDim.x = priWidth - (inDim.x + inDim.w); + inDim.y = priHeight - (inDim.y + inDim.h); + } + break; + } + case MDP_ROT_90: + case MDP_ROT_270: + { + if(inDim.o == MDP_ROT_90) { + tmp = inDim.y; + inDim.y = priWidth - (inDim.x + inDim.w); + inDim.x = tmp; + } + else if (inDim.o == MDP_ROT_270) { + tmp = inDim.x; + inDim.x = priHeight - (inDim.y + inDim.h); + inDim.y = tmp; + } + + // Swap the destination width/height + utils::swapWidthHeight(inDim.w, inDim.h); + // Swap width/height for primary + utils::swapWidthHeight(priWidth, priHeight); + utils::Whf whf((uint32_t) priWidth, (uint32_t) priHeight, 0); + tmpDim = getAspectRatio(whf); + xPos = tmpDim.x; + yPos = tmpDim.y; + fbWidth = tmpDim.w; + fbHeight = tmpDim.h; + break; + } + default: + ALOGE("%s: Unknown Orientation", __FUNCTION__); + break; + } + + // Calculate the position + xRatio = inDim.x/priWidth; + yRatio = inDim.y/priHeight; + wRatio = inDim.w/priWidth; + hRatio = inDim.h/priHeight; + + return utils::Dim((xRatio * fbWidth) + xPos, // x + (yRatio * fbHeight) + yPos, // y + (wRatio * fbWidth), // width + (hRatio * fbHeight), // height + inDim.o); // orientation +} + +void Ctrl::dump() const { + ALOGE("== Dump Ctrl start =="); + ALOGE("orient=%d", mOrient); + mInfo.dump("mInfo"); + mMdp.dump(); + mRot->dump(); + ALOGE("== Dump Ctrl end =="); +} + +} // overlay diff --git a/liboverlay/overlayCtrlData.h b/liboverlay/overlayCtrlData.h new file mode 100644 index 0000000..fbd701a --- /dev/null +++ b/liboverlay/overlayCtrlData.h @@ -0,0 +1,365 @@ +/* +* Copyright (c) 2012, 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 OVERLAY_CTRLDATA_H +#define OVERLAY_CTRLDATA_H + +#include "overlayUtils.h" +#include "overlayMdp.h" +#include "gralloc_priv.h" // INTERLACE_MASK + +namespace ovutils = overlay::utils; + +namespace overlay { + +// FIXME make int to be uint32 whenever possible + +class RotatorBase; + +/* +* FIXME do we want rot to be template parameter? +* It's already using inheritance... +* +* Sequence to use: +* open +* start +* setXXX +* close +* +* Can call setRot anytime to replace rotator on-the-fly +* */ +class Ctrl : utils::NoCopy { +public: + + /* ctor */ + explicit Ctrl(); + + /* dtor close */ + ~Ctrl(); + + /* should open devices? or start()? */ + bool open(uint32_t fbnum, RotatorBase* rot); + + /* close underlying mdp */ + bool close(); + + /* Invoke methods for opening underlying devices + * flags - PIPE SHARED + * wait - WAIT, NO_WAIT */ + bool start(const utils::PipeArgs& args); + + /* Dynamically set rotator*/ + void setRot(RotatorBase* rot); + + /* set mdp posision using dim */ + bool setPosition(const utils::Dim& dim); + + /* set param using Params (param,value pair) */ + bool setParameter(const utils::Params& p); + + /* set source using whf, orient and wait flag */ + bool setSource(const utils::PipeArgs& args); + + /* set crop info and pass it down to mdp */ + bool setCrop(const utils::Dim& d); + + /* mdp set overlay/commit changes */ + bool commit(); + + /* ctrl id */ + int getId() const; + /* ctrl fd */ + int getFd() const; + bool getRotSessId(int& id) const; + utils::Dim getAspectRatio(const utils::Whf& whf) const; + utils::Dim getAspectRatio(const utils::Dim& dim) const; + + /* access for screen info */ + utils::ScreenInfo getScreenInfo() const; + + /* retrieve cached crop data */ + utils::Dim getCrop() const; + + /* dump the state of the object */ + void dump() const; + +private: + /* Retrieve screen info from underlying mdp */ + bool getScreenInfo(utils::ScreenInfo& info); + + /* calls underlying mdp set info */ + bool setInfo(const utils::PipeArgs& args); + + /* given whf, update src */ + void updateSource(RotatorBase* r, + const utils::PipeArgs& args, + utils::ScreenInfo& info); + + // mdp ctrl struct(info e.g.) + MdpCtrl mMdp; + + // Rotator + RotatorBase* mRot; + + /* Cache cropped value */ + utils::Dim mCrop; + + /* Screen info */ + utils::ScreenInfo mInfo; + + /* orientation cache FIXME */ + utils::eTransform mOrient; + + /* Cache last known whfz. + * That would help us compare to a previous + * source that was submitted */ + utils::Whf mOvBufInfo; +}; + + +/* +* MDP = DataMdp, ROT = CtrlMdp usually since Rotator<> +* is instansiated with Ctrl data structure. +* */ +class Data : utils::NoCopy { +public: + /* init, reset */ + explicit Data(); + + /* calls close */ + ~Data(); + + /* should open devices? or start()? */ + bool open(uint32_t fbnum, RotatorBase* rot); + + /* calls underlying mdp close */ + bool close(); + + /* set the rotator */ + void setRot(RotatorBase* rot); + + /* set memory id in the mdp struct */ + void setMemoryId(int id); + + /* set overlay id in the mdp struct */ + void setId(int id); + + /* get overlay id in the mdp struct */ + int getId() const; + + /* queue buffer to the overlay */ + bool queueBuffer(uint32_t offset); + + /* wait for vsync to be done */ + bool waitForVsync(); + + /* sump the state of the obj */ + void dump() const; +private: + /* play wrapper */ + bool play(); + + /* playWait wrapper */ + bool playWait(); + + // mdp data struct + MdpData mMdp; + + // Rotator + RotatorBase* mRot; +}; + +/* This class just creates a Ctrl Data pair to be used by a pipe. + * Although this was legacy design, this separation still makes sense, since we + * need to use the Ctrl channel in hwc_prepare (i.e config stage) and Data + * channel in hwc_set (i.e draw stage) + */ +struct CtrlData { + Ctrl ctrl; + Data data; +}; + +//-------------Inlines------------------------------- + +inline Ctrl::Ctrl() : mRot(0), mOrient(utils::OVERLAY_TRANSFORM_0) { + mMdp.reset(); +} + +inline Ctrl::~Ctrl() { + close(); +} + +inline bool Ctrl::close() { + // do not close the rotator + if(!mMdp.close()) + return false; + return true; +} + +inline bool Ctrl::commit() { + if(!mMdp.set()) { + ALOGE("Ctrl commit failed set overlay"); + return false; + } + return true; +} + +inline bool Ctrl::getScreenInfo(utils::ScreenInfo& info) { + if(!mMdp.getScreenInfo(info)){ + ALOGE("Ctrl failed to get screen info"); + return false; + } + return true; +} + +inline bool Ctrl::setInfo(const utils::PipeArgs& args) +{ + // FIXME set flags, zorder and wait separtly + if(!mMdp.setInfo(mRot, args, mInfo)){ + ALOGE("Ctrl failed to setInfo wait=%d mdpflags=%d " + "zorder=%d", args.wait, args.mdpFlags, args.zorder); + return false; + } + return true; +} + +inline int Ctrl::getId() const { + // FIXME check channel up? + return mMdp.getId(); +} + +inline int Ctrl::getFd() const { + // FIXME check channel up? + return mMdp.getFd(); +} + +inline bool Ctrl::getRotSessId(int& id) const { + // FIXME check channel up? + // should be -1 in case of no rot session active + id = mRot->getSessId(); + return true; +} + +inline utils::ScreenInfo Ctrl::getScreenInfo() const { + return mInfo; +} + +inline utils::Dim Ctrl::getCrop() const { + return mCrop; +} + + + +inline Data::Data() : mRot(0) { + mMdp.reset(); +} + +inline Data::~Data() { close(); } + +inline void Data::setRot(RotatorBase* rot) { mRot = rot; } + +inline void Data::setMemoryId(int id) { mMdp.setMemoryId(id); } + +// really a reqid +inline void Data::setId(int id) { mMdp.setId(id); } + +inline int Data::getId() const { return mMdp.getId(); } + +inline bool Data::open(uint32_t fbnum, + RotatorBase* rot) { + if(!mMdp.open(fbnum)) { + ALOGE("Data cannot open mdp"); + return false; + } + + OVASSERT(rot, "rot is null"); + mRot = rot; + + // rotator should be already opened here + return true; +} + +inline bool Data::close() { + if(!mMdp.close()) { + ALOGE("Data close failed"); + return false; + } + return true; +} + +inline bool Data::queueBuffer(uint32_t offset) { + // FIXME asserts on state validity + + mMdp.setOffset(offset); + mRot->setRotDataSrcMemId(mMdp.getMemoryId()); + // will play if succeeded + if(!mRot->prepareQueueBuf(offset)) { + ALOGE("Data failed to prepareQueueBuf"); + return false; + } + // Play can go either from mdp or rot + if(!this->play()){ + ALOGE("Data error in MDP/ROT play"); + return false; + } + + return true; +} + +inline bool Data::waitForVsync() { + + // Call mdp playWait + if(!this->playWait()){ + ALOGE("Error in MDP playWait"); + return false; + } + + return true; +} + +inline bool Data::play() { + int fd = mMdp.getFd(); + return mRot->enabled() ? mRot->play(fd) : mMdp.play(); +} + +inline bool Data::playWait() { + return mMdp.playWait(); +} + +inline void Data::dump() const { + ALOGE("== Dump Data MDP start =="); + mMdp.dump(); + mRot->dump(); + ALOGE("== Dump Data MDP end =="); +} + + +} // overlay + +#endif diff --git a/liboverlay/overlayImpl.h b/liboverlay/overlayImpl.h new file mode 100644 index 0000000..5f999f2 --- /dev/null +++ b/liboverlay/overlayImpl.h @@ -0,0 +1,742 @@ +/* +* Copyright (c) 2011-2012, 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 OVERLAY_IMPL_H +#define OVERLAY_IMPL_H + +#include "overlayUtils.h" +#include "overlayRotator.h" + +// FIXME make int to be uint32 whenever possible + +namespace overlay { + +// Interface only. No member, no definiton (except ~ which can +// also be =0 with impl in cpp) +class OverlayImplBase { +public: + /* empty dtor. can be =0 with cpp impl*/ + virtual ~OverlayImplBase() {} + + /* Open pipe/rot for one dest */ + virtual bool openPipe(RotatorBase* rot, utils::eDest dest) = 0; + + /* Close pipe/rot for all specified dest */ + virtual bool closePipe(utils::eDest dest) = 0; + + /* Copy specified pipe/rot from ov passed in (used by state machine only) */ + virtual bool copyOvPipe(OverlayImplBase* ov, utils::eDest dest) = 0; + + /* TODO open func customized for RGBx pipes */ + + /* Open all pipes + * To open just one pipe, use openPipe() + * */ + virtual bool open(RotatorBase* rot0, + RotatorBase* rot1, + RotatorBase* rot2) = 0; + + /* Close all pipes + * To close just one pipe, use closePipe() + * */ + virtual bool close() = 0; + + /* + * Commit changes to the overlay + * */ + virtual bool commit(utils::eDest dest = utils::OV_PIPE_ALL) = 0; + + /* Queue buffer with offset*/ + virtual bool queueBuffer(uint32_t offset, + utils::eDest dest = utils::OV_PIPE_ALL) = 0; + + /* For RGBx pipes, dequeue buffer (that is fb chunk)*/ + virtual bool dequeueBuffer(void*& buf, + utils::eDest dest = utils::OV_PIPE_ALL) = 0; + + /* Wait for vsync to be done on dest */ + virtual bool waitForVsync(utils::eDest dest = utils::OV_PIPE1) = 0; + + /* Crop existing destination using Dim coordinates */ + virtual bool setCrop(const utils::Dim& d, + utils::eDest dest = utils::OV_PIPE_ALL) = 0; + + /* Set new position using Dim */ + virtual bool setPosition(const utils::Dim& dim, + utils::eDest dest = utils::OV_PIPE_ALL) = 0; + + /* Set parameters - usually needed for Rotator, but would + * be passed down the stack as well */ + virtual bool setParameter(const utils::Params& param, + utils::eDest dest = utils::OV_PIPE_ALL) = 0; + + /* Set new source including orientation */ + virtual bool setSource(const utils::PipeArgs[utils::MAX_PIPES], + utils::eDest dest = utils::OV_PIPE_ALL) = 0; + + /* set memory id to the underlying pipes */ + virtual void setMemoryId(int id, utils::eDest dest = utils::OV_PIPE_ALL) = 0; + + /* Get the overlay pipe type */ + virtual utils::eOverlayPipeType getOvPipeType(utils::eDest dest) const = 0; + + /* Dump underlying state */ + virtual void dump() const = 0; +}; + +class NullPipe { +public: + /* TODO open func customized for RGBx pipes */ + bool open(RotatorBase* rot); + bool close(); + bool start(const utils::PipeArgs& args); + bool commit(); + bool setCrop(const utils::Dim& d); + bool setPosition(const utils::Dim& dim); + bool setParameter(const utils::Params& param); + bool setSource(const utils::PipeArgs& args); + bool queueBuffer(uint32_t offset); + bool dequeueBuffer(void*& buf); + bool waitForVsync(); + void setMemoryId(int id); + utils::PipeArgs getArgs() const; + utils::eOverlayPipeType getOvPipeType() const; + void dump() const; +}; + +/* +* Each pipe is not specific to a display (primary/external). The order in the +* template params, will setup the priorities of the pipes. +* */ +template +class OverlayImpl : public OverlayImplBase { +public: + typedef P0 pipe0; + typedef P1 pipe1; + typedef P2 pipe2; + + /* ctor */ + OverlayImpl(); + OverlayImpl(P0* p0, P1* p1, P2* p2); + + /* + * Comments of the below functions are the same as the one + * in OverlayImplBase. + * */ + virtual ~OverlayImpl(); + + virtual bool openPipe(RotatorBase* rot, utils::eDest dest); + virtual bool closePipe(utils::eDest dest); + virtual bool copyOvPipe(OverlayImplBase* ov, utils::eDest dest); + + /* TODO open func customized for RGBx pipes */ + virtual bool open(RotatorBase* rot0, + RotatorBase* rot1, + RotatorBase* rot2); + virtual bool close(); + virtual bool commit(utils::eDest dest = utils::OV_PIPE_ALL); + virtual bool setCrop(const utils::Dim& d, + utils::eDest dest = utils::OV_PIPE_ALL); + virtual bool setPosition(const utils::Dim& dim, + utils::eDest dest = utils::OV_PIPE_ALL); + virtual bool setParameter(const utils::Params& param, + utils::eDest dest = utils::OV_PIPE_ALL); + virtual bool setSource(const utils::PipeArgs[utils::MAX_PIPES], + utils::eDest dest = utils::OV_PIPE_ALL); + virtual bool queueBuffer(uint32_t offset, + utils::eDest dest = utils::OV_PIPE_ALL); + virtual bool dequeueBuffer(void*& buf, + utils::eDest dest = utils::OV_PIPE_ALL); + virtual bool waitForVsync(utils::eDest dest = utils::OV_PIPE1); + virtual void setMemoryId(int id, utils::eDest dest = utils::OV_PIPE_ALL); + virtual utils::eOverlayPipeType getOvPipeType(utils::eDest dest) const; + virtual void dump() const; + +private: + P0* mPipe0; + P1* mPipe1; + P2* mPipe2; + // More Px here in the future as needed + + /* */ + + /* Each Px has it's own Rotator here. + * will pass rotator to the lower layer in stack + * but only overlay is allowed to control the lifetime + * of the rotator instace */ + RotatorBase* mRotP0; + RotatorBase* mRotP1; + RotatorBase* mRotP2; +}; + + + + + +//-----------Inlines and Template defn--------------------------------- + +template +OverlayImpl::OverlayImpl() : + mPipe0(new P0), mPipe1(new P1), mPipe2(new P2), + mRotP0(0), mRotP1(0), mRotP2(0) +{} + +template +OverlayImpl::OverlayImpl(P0* p0, P1* p1, P2* p2) : + mPipe0(p0), mPipe1(p1), mPipe2(p2), + mRotP0(0), mRotP1(0), mRotP2(0) +{} + +template +OverlayImpl::~OverlayImpl() +{ + // no op in the meantime. needed to be clean + // since state machine will do delete. so we + // do not want to close/delete pipes here +} + +/* Open only one pipe/rot pair per call */ +template +bool OverlayImpl::openPipe(RotatorBase* rot, utils::eDest dest) +{ + OVASSERT(rot, "%s: OverlayImpl rot is null", __FUNCTION__); + OVASSERT(utils::isValidDest(dest), "%s: OverlayImpl invalid dest=%d", + __FUNCTION__, dest); + + // Need to down case rotator to mdp one. + // we assume p0/p1/p2/px all use the _same_ underlying mdp structure. + // FIXME STATIC_ASSERT here + + bool ret = true; + + if (utils::OV_PIPE0 & dest) { + OVASSERT(mPipe0, "%s: OverlayImpl pipe0 is null", __FUNCTION__); + ALOGE_IF(DEBUG_OVERLAY, "Open pipe0"); + ret = mPipe0->open(rot); + mRotP0 = rot; + if(!ret) { + ALOGE("%s: OverlayImpl pipe0 failed to open", __FUNCTION__); + } + return ret; + } + + if (utils::OV_PIPE1 & dest) { + OVASSERT(mPipe1, "%s: OverlayImpl pipe1 is null", __FUNCTION__); + ALOGE_IF(DEBUG_OVERLAY, "Open pipe1"); + ret = mPipe1->open(rot); + mRotP1 = rot; + if(!ret) { + ALOGE("%s: OverlayImpl pipe1 failed to open", __FUNCTION__); + } + return ret; + } + + if (utils::OV_PIPE2 & dest) { + OVASSERT(mPipe2, "%s: OverlayImpl pipe2 is null", __FUNCTION__); + ALOGE_IF(DEBUG_OVERLAY, "Open pipe2"); + ret = mPipe2->open(rot); + mRotP2 = rot; + if(!ret) { + ALOGE("%s: OverlayImpl pipe2 failed to open", __FUNCTION__); + } + return ret; + } + + // Should have returned by here + return false; +} + +/* Close pipe/rot for all specified dest */ +template +bool OverlayImpl::closePipe(utils::eDest dest) +{ + OVASSERT(utils::isValidDest(dest), "%s: OverlayImpl invalid dest=%d", + __FUNCTION__, dest); + + if (utils::OV_PIPE0 & dest) { + // Close pipe0 + OVASSERT(mPipe0, "%s: OverlayImpl pipe0 is null", __FUNCTION__); + ALOGE_IF(DEBUG_OVERLAY, "Close pipe0"); + if (!mPipe0->close()) { + ALOGE("%s: OverlayImpl failed to close pipe0", __FUNCTION__); + return false; + } + delete mPipe0; + mPipe0 = 0; + + // Close the rotator for pipe0 + OVASSERT(mRotP0, "%s: OverlayImpl rot0 is null", __FUNCTION__); + if (!mRotP0->close()) { + ALOGE("%s: OverlayImpl failed to close rot for pipe0", __FUNCTION__); + } + delete mRotP0; + mRotP0 = 0; + } + + if (utils::OV_PIPE1 & dest) { + // Close pipe1 + OVASSERT(mPipe1, "%s: OverlayImpl pipe1 is null", __FUNCTION__); + ALOGE_IF(DEBUG_OVERLAY, "Close pipe1"); + if (!mPipe1->close()) { + ALOGE("%s: OverlayImpl failed to close pipe1", __FUNCTION__); + return false; + } + delete mPipe1; + mPipe1 = 0; + + // Close the rotator for pipe1 + OVASSERT(mRotP1, "%s: OverlayImpl rot1 is null", __FUNCTION__); + if (!mRotP1->close()) { + ALOGE("%s: OverlayImpl failed to close rot for pipe1", __FUNCTION__); + } + delete mRotP1; + mRotP1 = 0; + } + + if (utils::OV_PIPE2 & dest) { + // Close pipe2 + OVASSERT(mPipe2, "%s: OverlayImpl pipe2 is null", __FUNCTION__); + ALOGE_IF(DEBUG_OVERLAY, "Close pipe2"); + if (!mPipe2->close()) { + ALOGE("%s: OverlayImpl failed to close pipe2", __FUNCTION__); + return false; + } + delete mPipe2; + mPipe2 = 0; + + // Close the rotator for pipe2 + OVASSERT(mRotP2, "%s: OverlayImpl rot2 is null", __FUNCTION__); + if (!mRotP2->close()) { + ALOGE("%s: OverlayImpl failed to close rot for pipe2", __FUNCTION__); + } + delete mRotP2; + mRotP2 = 0; + } + + return true; +} + +/* Copy pipe/rot from ov for all specified dest */ +template +bool OverlayImpl::copyOvPipe(OverlayImplBase* ov, + utils::eDest dest) +{ + OVASSERT(ov, "%s: OverlayImpl ov is null", __FUNCTION__); + OVASSERT(utils::isValidDest(dest), "%s: OverlayImpl invalid dest=%d", + __FUNCTION__, dest); + + OverlayImpl* ovimpl = static_cast*>(ov); + + if (utils::OV_PIPE0 & dest) { + mPipe0 = ovimpl->mPipe0; + mRotP0 = ovimpl->mRotP0; + } + + if (utils::OV_PIPE1 & dest) { + mPipe1 = ovimpl->mPipe1; + mRotP1 = ovimpl->mRotP1; + } + + if (utils::OV_PIPE2 & dest) { + mPipe2 = ovimpl->mPipe2; + mRotP2 = ovimpl->mRotP2; + } + + return true; +} + +/* TODO open func customized for RGBx pipes */ + +/* Open all pipes/rot */ +template +bool OverlayImpl::open(RotatorBase* rot0, + RotatorBase* rot1, + RotatorBase* rot2) +{ + if (!this->openPipe(rot0, utils::OV_PIPE0)) { + if (!this->close()) { + ALOGE("%s: failed to close at least one pipe", __FUNCTION__); + } + return false; + } + + if (!this->openPipe(rot1, utils::OV_PIPE1)) { + if (!this->close()) { + ALOGE("%s: failed to close at least one pipe", __FUNCTION__); + } + return false; + } + + if (!this->openPipe(rot2, utils::OV_PIPE2)) { + if (!this->close()) { + ALOGE("%s: failed to close at least one pipe", __FUNCTION__); + } + return false; + } + + return true; +} + +/* Close all pipes/rot */ +template +bool OverlayImpl::close() +{ + if (!this->closePipe(utils::OV_PIPE_ALL)) { + return false; + } + + return true; +} + +template +bool OverlayImpl::commit(utils::eDest dest) +{ + OVASSERT(mPipe0 && mPipe1 && mPipe2, + "%s: Pipes are null p0=%p p1=%p p2=%p", + __FUNCTION__, mPipe0, mPipe1, mPipe2); + + if (utils::OV_PIPE0 & dest) { + if(!mPipe0->commit()) { + ALOGE("OverlayImpl p0 failed to commit"); + return false; + } + } + + if (utils::OV_PIPE1 & dest) { + if(!mPipe1->commit()) { + ALOGE("OverlayImpl p1 failed to commit"); + return false; + } + } + + if (utils::OV_PIPE2 & dest) { + if(!mPipe2->commit()) { + ALOGE("OverlayImpl p2 failed to commit"); + return false; + } + } + + return true; +} + +template +bool OverlayImpl::setCrop(const utils::Dim& d, utils::eDest dest) +{ + OVASSERT(mPipe0 && mPipe1 && mPipe2, + "%s: Pipes are null p0=%p p1=%p p2=%p", + __FUNCTION__, mPipe0, mPipe1, mPipe2); + + if (utils::OV_PIPE0 & dest) { + if(!mPipe0->setCrop(d)) { + ALOGE("OverlayImpl p0 failed to crop"); + return false; + } + } + + if (utils::OV_PIPE1 & dest) { + if(!mPipe1->setCrop(d)) { + ALOGE("OverlayImpl p1 failed to crop"); + return false; + } + } + + if (utils::OV_PIPE2 & dest) { + if(!mPipe2->setCrop(d)) { + ALOGE("OverlayImpl p2 failed to crop"); + return false; + } + } + + return true; +} + +template +bool OverlayImpl::setPosition(const utils::Dim& d, + utils::eDest dest) +{ + OVASSERT(mPipe0 && mPipe1 && mPipe2, + "%s: Pipes are null p0=%p p1=%p p2=%p", + __FUNCTION__, mPipe0, mPipe1, mPipe2); + + if (utils::OV_PIPE0 & dest) { + if(!mPipe0->setPosition(d)) { + ALOGE("OverlayImpl p0 failed to setpos"); + return false; + } + } + + if (utils::OV_PIPE1 & dest) { + if(!mPipe1->setPosition(d)) { + ALOGE("OverlayImpl p1 failed to setpos"); + return false; + } + } + + if (utils::OV_PIPE2 & dest) { + if(!mPipe2->setPosition(d)) { + ALOGE("OverlayImpl p2 failed to setpos"); + return false; + } + } + + return true; +} + +template +bool OverlayImpl::setParameter(const utils::Params& param, + utils::eDest dest) +{ + OVASSERT(mPipe0 && mPipe1 && mPipe2, + "%s: Pipes are null p0=%p p1=%p p2=%p", + __FUNCTION__, mPipe0, mPipe1, mPipe2); + + if (utils::OV_PIPE0 & dest) { + if(!mPipe0->setParameter(param)) { + ALOGE("OverlayImpl p0 failed to setparam"); + return false; + } + } + + if (utils::OV_PIPE1 & dest) { + if(!mPipe1->setParameter(param)) { + ALOGE("OverlayImpl p1 failed to setparam"); + return false; + } + } + + if (utils::OV_PIPE2 & dest) { + if(!mPipe2->setParameter(param)) { + ALOGE("OverlayImpl p2 failed to setparam"); + return false; + } + } + + return true; +} + +template +bool OverlayImpl::setSource(const utils::PipeArgs args[utils::MAX_PIPES], + utils::eDest dest) +{ + OVASSERT(mPipe0 && mPipe1 && mPipe2, + "%s: Pipes are null p0=%p p1=%p p2=%p", + __FUNCTION__, mPipe0, mPipe1, mPipe2); + + if (utils::OV_PIPE0 & dest) { + if(!mPipe0->setSource(args[0])) { + ALOGE("OverlayImpl p0 failed to setsrc"); + return false; + } + } + + if (utils::OV_PIPE1 & dest) { + if(!mPipe1->setSource(args[1])) { + ALOGE("OverlayImpl p1 failed to setsrc"); + return false; + } + } + + if (utils::OV_PIPE2 & dest) { + if(!mPipe2->setSource(args[2])) { + ALOGE("OverlayImpl p2 failed to setsrc"); + return false; + } + } + + return true; +} + +template +bool OverlayImpl::queueBuffer(uint32_t offset, utils::eDest dest) +{ + OVASSERT(mPipe0 && mPipe1 && mPipe2, + "%s: Pipes are null p0=%p p1=%p p2=%p", + __FUNCTION__, mPipe0, mPipe1, mPipe2); + + if (utils::OV_PIPE0 & dest) { + if(!mPipe0->queueBuffer(offset)) { + ALOGE("OverlayImpl p0 failed to queueBuffer"); + return false; + } + } + + if (utils::OV_PIPE1 & dest) { + if(!mPipe1->queueBuffer(offset)) { + ALOGE("OverlayImpl p1 failed to queueBuffer"); + return false; + } + } + + if (utils::OV_PIPE2 & dest) { + if(!mPipe2->queueBuffer(offset)) { + ALOGE("OverlayImpl p2 failed to queueBuffer"); + return false; + } + } + + return true; +} + +template +bool OverlayImpl::dequeueBuffer(void*& buf, utils::eDest dest) +{ + OVASSERT(mPipe0 && mPipe1 && mPipe2, + "%s: Pipes are null p0=%p p1=%p p2=%p", + __FUNCTION__, mPipe0, mPipe1, mPipe2); + + if (utils::OV_PIPE0 & dest) { + if(!mPipe0->dequeueBuffer(buf)) { + ALOGE("OverlayImpl p0 failed to dequeueBuffer"); + return false; + } + } + + if (utils::OV_PIPE1 & dest) { + if(!mPipe1->dequeueBuffer(buf)) { + ALOGE("OverlayImpl p1 failed to dequeueBuffer"); + return false; + } + } + + if (utils::OV_PIPE2 & dest) { + if(!mPipe2->dequeueBuffer(buf)) { + ALOGE("OverlayImpl p2 failed to dequeueBuffer"); + return false; + } + } + + return true; +} + +template +bool OverlayImpl::waitForVsync(utils::eDest dest) +{ + OVASSERT(mPipe0 && mPipe1 && mPipe2, + "%s: Pipes are null p0=%p p1=%p p2=%p", + __FUNCTION__, mPipe0, mPipe1, mPipe2); + + if (utils::OV_PIPE0 & dest) { + if(!mPipe0->waitForVsync()) { + ALOGE("OverlayImpl p0 failed to waitForVsync"); + return false; + } + } + + if (utils::OV_PIPE1 & dest) { + if(!mPipe1->waitForVsync()) { + ALOGE("OverlayImpl p1 failed to waitForVsync"); + return false; + } + } + + if (utils::OV_PIPE2 & dest) { + if(!mPipe2->waitForVsync()) { + ALOGE("OverlayImpl p2 failed to waitForVsync"); + return false; + } + } + + return true; +} + +template +void OverlayImpl::setMemoryId(int id, utils::eDest dest) +{ + OVASSERT(mPipe0 && mPipe1 && mPipe2, + "%s: Pipes are null p0=%p p1=%p p2=%p", + __FUNCTION__, mPipe0, mPipe1, mPipe2); + + if (utils::OV_PIPE0 & dest) { + mPipe0->setMemoryId(id); + } + + if (utils::OV_PIPE1 & dest) { + mPipe1->setMemoryId(id); + } + + if (utils::OV_PIPE2 & dest) { + mPipe2->setMemoryId(id); + } +} + +template +utils::eOverlayPipeType OverlayImpl::getOvPipeType(utils::eDest dest) const +{ + OVASSERT(utils::isValidDest(dest), "%s: OverlayImpl invalid dest=%d", + __FUNCTION__, dest); + + if (utils::OV_PIPE0 & dest) { + OVASSERT(mPipe0, "%s: OverlayImpl pipe0 is null", __FUNCTION__); + return mPipe0->getOvPipeType(); + } + + if (utils::OV_PIPE1 & dest) { + OVASSERT(mPipe1, "%s: OverlayImpl pipe1 is null", __FUNCTION__); + return mPipe1->getOvPipeType(); + } + + if (utils::OV_PIPE2 & dest) { + OVASSERT(mPipe2, "%s: OverlayImpl pipe2 is null", __FUNCTION__); + return mPipe2->getOvPipeType(); + } + + // Should never get here + return utils::OV_PIPE_TYPE_NULL; +} + +template +void OverlayImpl::dump() const +{ + OVASSERT(mPipe0 && mPipe1 && mPipe2, + "%s: Pipes are null p0=%p p1=%p p2=%p", + __FUNCTION__, mPipe0, mPipe1, mPipe2); + ALOGE("== Dump OverlayImpl dump start ROT p0 =="); + mRotP0->dump(); + ALOGE("== Dump OverlayImpl dump end ROT p0 =="); + ALOGE("== Dump OverlayImpl dump start ROT p1 =="); + mRotP1->dump(); + ALOGE("== Dump OverlayImpl dump end ROT p1 =="); + ALOGE("== Dump OverlayImpl dump start ROT p2 =="); + mRotP2->dump(); + ALOGE("== Dump OverlayImpl dump end ROT p2 =="); + ALOGE("== Dump OverlayImpl dump start p0 =="); + mPipe0->dump(); + ALOGE("== Dump OverlayImpl dump end p0 =="); + ALOGE("== Dump OverlayImpl dump start p1 =="); + mPipe1->dump(); + ALOGE("== Dump OverlayImpl dump end p1 =="); + ALOGE("== Dump OverlayImpl dump start p2 =="); + mPipe2->dump(); + ALOGE("== Dump OverlayImpl dump end p2 =="); +} + + +} // overlay + +#endif // OVERLAY_IMPL_H diff --git a/liboverlay/overlayLib.cpp b/liboverlay/overlayLib.cpp deleted file mode 100755 index fe5c3d3..0000000 --- a/liboverlay/overlayLib.cpp +++ /dev/null @@ -1,2352 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. - * - * 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. - */ - -#include "overlayLib.h" -#include "gralloc_priv.h" - -#define INTERLACE_MASK 0x80 -#define DEBUG_OVERLAY true -/* Helper functions */ -static inline size_t ALIGN(size_t x, size_t align) { - return (x + align-1) & ~(align-1); -} - -using namespace overlay; -using android::sp; -using gralloc::IMemAlloc; -using gralloc::IonController; -using gralloc::alloc_data; - -#ifdef HDMI_AS_PRIMARY -bool Overlay::sHDMIAsPrimary = true; -#else -bool Overlay::sHDMIAsPrimary = false; -#endif - -template -void swapWidthHeight(Type& width, Type& height) { - Type tmp = width; - width = height; - height = tmp; -} - -int overlay::get_mdp_format(int format) { - switch (format) { - case HAL_PIXEL_FORMAT_RGBA_8888 : - return MDP_RGBA_8888; - case HAL_PIXEL_FORMAT_BGRA_8888: - return MDP_BGRA_8888; - case HAL_PIXEL_FORMAT_RGB_565: - return MDP_RGB_565; - case HAL_PIXEL_FORMAT_RGBX_8888: - return MDP_RGBX_8888; - case HAL_PIXEL_FORMAT_YCbCr_422_SP: - return MDP_Y_CBCR_H2V1; - case HAL_PIXEL_FORMAT_YCbCr_420_SP: - return MDP_Y_CRCB_H2V2; - case HAL_PIXEL_FORMAT_YCrCb_420_SP: - return MDP_Y_CBCR_H2V2; - case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: - return MDP_Y_CRCB_H2V2_TILE; - case HAL_PIXEL_FORMAT_YV12: - return MDP_Y_CR_CB_GH2V2; - default: - LOGE("%s: unknown color format [0x%x]", __FUNCTION__, format); - return -1; - } - return -1; -} - -int overlay::get_mdp_orientation(int value) { - switch(value) { - case 0: return 0; - case HAL_TRANSFORM_FLIP_V: return MDP_FLIP_UD; - case HAL_TRANSFORM_FLIP_H: return MDP_FLIP_LR; - case HAL_TRANSFORM_ROT_90: return MDP_ROT_90; - case HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_V: - return MDP_ROT_90|MDP_FLIP_LR; - case HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_H: - return MDP_ROT_90|MDP_FLIP_UD; - case HAL_TRANSFORM_ROT_180: return MDP_ROT_180; - case HAL_TRANSFORM_ROT_270: return MDP_ROT_270; - default: - LOGE("%s: invalid rotation value (value = 0x%x", - __FUNCTION__, value); - return -1; - } - return -1; -} - -// Rotator - input to output mapping -int overlay::get_rot_output_format(int format) { - switch (format) { - case MDP_Y_CRCB_H2V2_TILE: - return MDP_Y_CRCB_H2V2; - case MDP_Y_CB_CR_H2V2: - return MDP_Y_CBCR_H2V2; - case MDP_Y_CR_CB_GH2V2: - return MDP_Y_CRCB_H2V2; - default: - return format; - } - return -1; -} - -// This function normalizes the crop values to be all even -void overlay::normalize_crop(uint32_t& xy, uint32_t& wh) { - - if (xy & 0x0001) { - // x or y is odd, increment it's value - xy += 1; - // Since we've incremented x(y), we need to decrement - // w(h) accordingly - if (wh & 0x0001) { - // w or h is odd, decrement it by 1, to make it even - EVEN_OUT(wh); - } else { - // w(h) is already even, hence we decrement by 2 - wh -=2; - } - } else { - EVEN_OUT(wh); - } -} - -#define LOG_TAG "OverlayLIB" -static void reportError(const char* message) { - LOGE( "%s", message); -} - -void overlay::dump(mdp_overlay& mOVInfo) { - if (!DEBUG_OVERLAY) - return; - LOGE("mOVInfo:"); - LOGE("src: width %d height %d format %s user_data[0] %d", mOVInfo.src.width, - mOVInfo.src.height, getFormatString(mOVInfo.src.format), - mOVInfo.user_data[0]); - LOGE("src_rect: x %d y %d w %d h %d", mOVInfo.src_rect.x, - mOVInfo.src_rect.y, mOVInfo.src_rect.w, mOVInfo.src_rect.h); - LOGE("dst_rect: x %d y %d w %d h %d", mOVInfo.dst_rect.x, - mOVInfo.dst_rect.y, mOVInfo.dst_rect.w, mOVInfo.dst_rect.h); - LOGE("z_order %d is_fg %d alpha %d transp_mask %d flags %x id %d", - mOVInfo.z_order, mOVInfo.is_fg, mOVInfo.alpha, mOVInfo.transp_mask, - mOVInfo.flags, mOVInfo.id); -} - -void overlay::dump(msm_rotator_img_info& mRotInfo) { - if (!DEBUG_OVERLAY) - return; - LOGE("mRotInfo:"); - LOGE("session_id %d dst_x %d dst_y %d rotations %d enable %d", - mRotInfo.session_id, mRotInfo.dst_x, mRotInfo.dst_y, - mRotInfo.rotations, mRotInfo.enable); - LOGE("src: width %d height %d format %s", mRotInfo.src.width, - mRotInfo.src.height, getFormatString(mRotInfo.src.format)); - LOGE("dst: width %d height %d format %s", mRotInfo.dst.width, - mRotInfo.dst.height, getFormatString(mRotInfo.src.format)); - LOGE("src_rect: x %d y %d w %d h %d", mRotInfo.src_rect.x, - mRotInfo.src_rect.y, mRotInfo.src_rect.w, mRotInfo.src_rect.h); -} - -const char* overlay::getFormatString(int format){ - static const char* formats[] = { - "MDP_RGB_565", - "MDP_XRGB_8888", - "MDP_Y_CBCR_H2V2", - "MDP_ARGB_8888", - "MDP_RGB_888", - "MDP_Y_CRCB_H2V2", - "MDP_YCRYCB_H2V1", - "MDP_Y_CRCB_H2V1", - "MDP_Y_CBCR_H2V1", - "MDP_RGBA_8888", - "MDP_BGRA_8888", - "MDP_RGBX_8888", - "MDP_Y_CRCB_H2V2_TILE", - "MDP_Y_CBCR_H2V2_TILE", - "MDP_Y_CR_CB_H2V2", - "MDP_Y_CR_CB_GH2V2", - "MDP_Y_CB_CR_H2V2", - "MDP_Y_CRCB_H1V1", - "MDP_Y_CBCR_H1V1", - "MDP_IMGTYPE_LIMIT", - "MDP_BGR_565", - "MDP_FB_FORMAT", - "MDP_IMGTYPE_LIMIT2" - }; - return formats[format]; -} -ZOrderManager* ZOrderManager::sInstance = 0; -FrameBufferInfo* FrameBufferInfo::sFBInfoInstance = 0; - -int ZOrderManager::getZ(int fbnum){ - int zorder = NO_PIPE;; - Mutex::Autolock objLock(mObjMutex); - if(mPipesInuse == mMaxPipes) { - LOGE("No free pipes available.. inUse = %d ", mPipesInuse); - return NO_PIPE; - } - switch(fbnum) { - case FRAMEBUFFER_0: - for (int i = 0;i < NUM_CHANNELS; i++) { - if(mFB0Pipes[i] == false) { - mFB0Pipes[i]= true; - zorder = i; - break; - } - } - break; - case FRAMEBUFFER_1: - case FRAMEBUFFER_2: - for (int i = 0;i < mMaxPipes; i++) { - if(mFB1Pipes[i] == false) { - mFB1Pipes[i]= true; - zorder = i; - break; - } - } - break; - default: - LOGE("getZ: Invalid framebuffer.."); - break; - } - mPipesInuse++; - LOGE("getZ: return zorder = %d for fbdev = %d, pipesinUse = %d", - zorder, fbnum, mPipesInuse); - return zorder; -} - -void ZOrderManager::decZ(int fbnum, int zorder){ - Mutex::Autolock objLock(mObjMutex); - switch(fbnum) { - case FRAMEBUFFER_0: - LOG_ASSERT(!mFB0Pipes[zorder],"channel with ZOrder does not exist"); - LOGE("decZ: freeing the pipe with zorder = %d for fbdev = %d", zorder, fbnum); - mFB0Pipes[zorder] = false; - break; - case FRAMEBUFFER_1: - case FRAMEBUFFER_2: - LOG_ASSERT(!mFB1Pipes[zorder],"channel with ZOrder does not exist"); - LOGE("decZ: freeing the pipe with zorder = %d for fbdev = %d", zorder, fbnum); - mFB1Pipes[zorder] = false; - break; - default: - LOGE("decZ: Invalid framebuffer "); - break; - } - if(mPipesInuse > 0) - mPipesInuse--; - LOGE("decZ: Pipes in use = %d", mPipesInuse); -} - -bool overlay::isHDMIConnected () { - char value[PROPERTY_VALUE_MAX]; - property_get("hw.hdmiON", value, "0"); - int isHDMI = atoi(value); - return isHDMI ? true : false; -} - -bool overlay::is3DTV() { - char is3DTV = '0'; - FILE *fp = fopen(EDID_3D_INFO_FILE, "r"); - if (fp) { - fread(&is3DTV, 1, 1, fp); - fclose(fp); - } - LOGI("3DTV EDID flag: %c", is3DTV); - return (is3DTV == '0') ? false : true; -} - -bool overlay::isPanel3D() { - int fd = open("/dev/graphics/fb0", O_RDWR, 0); - if (fd < 0) { - reportError("Can't open framebuffer 0"); - return false; - } - fb_fix_screeninfo finfo; - if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) { - reportError("FBIOGET_FSCREENINFO on fb0 failed"); - close(fd); - fd = -1; - return false; - } - close(fd); - return (FB_TYPE_3D_PANEL == finfo.type) ? true : false; -} - -bool overlay::usePanel3D() { - if (Overlay::sHDMIAsPrimary) - return is3DTV(); - - if(!isPanel3D()) - return false; - char value[PROPERTY_VALUE_MAX]; - property_get("persist.user.panel3D", value, "0"); - int usePanel3D = atoi(value); - return usePanel3D ? true : false; -} - -bool overlay::send3DInfoPacket (unsigned int format3D) { - FILE *fp = fopen(FORMAT_3D_FILE, "wb"); - if (fp) { - fprintf(fp, "%d", format3D); - fclose(fp); - fp = NULL; - return true; - } - LOGE("%s:no sysfs entry for setting 3d mode!", __FUNCTION__); - return false; -} - -bool overlay::enableBarrier (unsigned int orientation) { - FILE *fp = fopen(BARRIER_FILE, "wb"); - if (fp) { - fprintf(fp, "%d", orientation); - fclose(fp); - fp = NULL; - return true; - } - LOGE("%s:no sysfs entry for enabling barriers on 3D panel!", __FUNCTION__); - return false; -} - -int overlay::getColorFormat(int 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, - bool isHDMI) { - bool isTV3D = false; - unsigned int curState = 0; - if (poll) - isHDMI = isHDMIConnected(); - if (isHDMI) { - LOGD("%s: HDMI connected... checking the TV type", __FUNCTION__); - if (format3D) { - if (is3DTV()) - curState = OV_3D_VIDEO_3D_TV; - else - curState = OV_3D_VIDEO_2D_TV; - } else - curState = OV_2D_VIDEO_ON_TV; - } else { - LOGD("%s: HDMI not connected...", __FUNCTION__); - if(format3D) { - if (usePanel3D()) - curState = OV_3D_VIDEO_3D_PANEL; - else - curState = OV_3D_VIDEO_2D_PANEL; - } - else - curState = OV_2D_VIDEO_ON_PANEL; - } - return curState; -} - -/* clears any VG pipes allocated to the fb devices */ -int overlay::initOverlay() { - msmfb_mixer_info_req req; - mdp_mixer_info *minfo = NULL; - char name[64]; - int fd = -1; - for(int i = 0; i < NUM_FB_DEVICES; i++) { - snprintf(name, 64, FB_DEVICE_TEMPLATE, i); - LOGD("initoverlay:: opening the device:: %s", name); - fd = open(name, O_RDWR, 0); - if(fd < 0) { - LOGE("cannot open framebuffer(%d)", i); - return -1; - } - //Get the mixer configuration */ - req.mixer_num = i; - if (ioctl(fd, MSMFB_MIXER_INFO, &req) == -1) { - LOGE("ERROR: MSMFB_MIXER_INFO ioctl failed"); - close(fd); - return -1; - } - minfo = req.info; - for (int j = 0; j < req.cnt; j++) { - LOGD("ndx=%d num=%d z_order=%d", minfo->pndx, minfo->pnum, - minfo->z_order); - // except the RGB base layer with z_order of -1, clear any - // other pipes connected to mixer. - if((minfo->z_order) != -1) { - int index = minfo->pndx; - LOGD("Unset overlay with index: %d at mixer %d", index, i); - if(ioctl(fd, MSMFB_OVERLAY_UNSET, &index) == -1) { - LOGE("ERROR: MSMFB_OVERLAY_UNSET failed"); - close(fd); - return -1; - } - } - minfo++; - } - close(fd); - fd = -1; - } - return 0; -} - -Overlay::Overlay() : mChannelUP(false), mExternalDisplay(false), - mS3DFormat(0), mCroppedSrcWidth(0), - mCroppedSrcHeight(0), mState(-1) { - mOVBufferInfo.width = mOVBufferInfo.height = 0; - mOVBufferInfo.format = mOVBufferInfo.size = 0; -} - -Overlay::~Overlay() { - closeChannel(); -} - -int Overlay::getFBWidth(int channel) const { - return objOvCtrlChannel[channel].getFBWidth(); -} - -int Overlay::getFBHeight(int channel) const { - return objOvCtrlChannel[channel].getFBHeight(); -} - -bool Overlay::startChannel(const overlay_buffer_info& info, int fbnum, - bool norot, bool uichannel, - unsigned int format3D, int channel, - int flags, int num_buffers) { - int zorder = 0; - mCroppedSrcWidth = info.width; - mCroppedSrcHeight = info.height; - if (format3D) - zorder = channel; - if (mState == -1) - mState = OV_UI_MIRROR_TV; - - mChannelUP = objOvCtrlChannel[channel].startControlChannel(info, fbnum, - norot, uichannel, - format3D, zorder, flags); - if (!mChannelUP) { - LOGE("startChannel for fb%d failed", fbnum); - return mChannelUP; - } - bool secure = flags & SECURE_OVERLAY_SESSION; - objOvCtrlChannel[channel].setSize(info.size); - return objOvDataChannel[channel].startDataChannel(objOvCtrlChannel[channel], fbnum, - norot, secure, uichannel, num_buffers); -} - -bool Overlay::closeChannel() { - - if (!mChannelUP) - return true; - - if(mS3DFormat) { - if (mExternalDisplay) - overlay::send3DInfoPacket(0); - else if (mState == OV_3D_VIDEO_3D_PANEL) { - if (sHDMIAsPrimary) - overlay::send3DInfoPacket(0); - else - enableBarrier(0); - } - } - for (int i = 0; i < NUM_CHANNELS; i++) { - objOvCtrlChannel[i].closeControlChannel(); - objOvDataChannel[i].closeDataChannel(); - } - mChannelUP = false; - mS3DFormat = 0; - mOVBufferInfo.width = 0; - mOVBufferInfo.height = 0; - mOVBufferInfo.format = 0; - mOVBufferInfo.size = 0; - mState = -1; - return true; -} - -void Overlay::closeExternalChannel() { - if (objOvCtrlChannel[VG1_PIPE].isChannelUP()) { - objOvCtrlChannel[VG1_PIPE].closeControlChannel(); - objOvDataChannel[VG1_PIPE].closeDataChannel(); - } -} - -bool Overlay::getPosition(int& x, int& y, uint32_t& w, uint32_t& h, int channel) { - return objOvCtrlChannel[channel].getPosition(x, y, w, h); -} - -bool Overlay::getOrientation(int& orientation, int channel) const { - return objOvCtrlChannel[channel].getOrientation(orientation); -} - -bool Overlay::setDeviceOrientation(int orientation) { - // Use this to calculate the position on HDMI - mDevOrientation = orientation; - return true; -} - -bool Overlay::setPosition(int x, int y, uint32_t w, uint32_t h) { - bool ret = false; - overlay_rect secDest; - overlay_rect priDest; - int currX, currY; - uint32_t currW, currH; - // Set even destination co-ordinates - EVEN_OUT(x); EVEN_OUT(y); - EVEN_OUT(w); EVEN_OUT(h); - objOvCtrlChannel[VG0_PIPE].getPosition(currX, currY, currW, currH); - priDest.x = x, priDest.y = y; - priDest.w = w, priDest.h = h; - if(x != currX || y != currY || w != currW || h != currH) { - switch (mState) { - case OV_UI_MIRROR_TV: - case OV_2D_VIDEO_ON_PANEL: - case OV_3D_VIDEO_2D_PANEL: - return setChannelPosition(x, y, w, h, VG0_PIPE); - break; - case OV_2D_VIDEO_ON_TV: - if (FrameBufferInfo::getInstance()->canSupportTrueMirroring()) { - objOvCtrlChannel[VG1_PIPE].getAspectRatioPosition( - mCroppedSrcWidth, mCroppedSrcHeight, mDevOrientation, - &priDest, &secDest); - } else { - objOvCtrlChannel[VG1_PIPE].getAspectRatioPosition( - mCroppedSrcWidth, mCroppedSrcHeight, &secDest); - } - setChannelPosition(secDest.x, secDest.y, secDest.w, secDest.h, - VG1_PIPE); - return setChannelPosition(x, y, w, h, VG0_PIPE); - break; - case OV_3D_VIDEO_3D_PANEL: - for (int i = 0; i < NUM_CHANNELS; i++) { - if (sHDMIAsPrimary) - objOvCtrlChannel[i].getPositionS3D(i, mS3DFormat, &secDest); - else { - if (!objOvCtrlChannel[i].useVirtualFB()) { - LOGE("%s: failed virtual fb for channel %d", __FUNCTION__, i); - return false; - } - objOvCtrlChannel[i].getPositionS3D(i, 0x1, &secDest); - } - if(!setChannelPosition(secDest.x, secDest.y, secDest.w, - secDest.h, i)) { - LOGE("%s: failed for channel %d", __FUNCTION__, i); - return false; - } - } - break; - case OV_3D_VIDEO_2D_TV: - case OV_3D_VIDEO_3D_TV: - for (int i = 0; i < NUM_CHANNELS; i++) { - ret = objOvCtrlChannel[i].getPositionS3D(i, mS3DFormat, - &secDest); - if (!ret) - ret = setChannelPosition(x, y, w, h, i); - else - ret = setChannelPosition(secDest.x, secDest.y, secDest.w, - secDest.h, i); - if (!ret) { - LOGE("%s: failed for channel %d", __FUNCTION__, i); - return ret; - } - } - break; - default: - LOGE("%s:Unknown state %d", __FUNCTION__, mState); - break; - } - } - return true; -} - -bool Overlay::setChannelPosition(int x, int y, uint32_t w, uint32_t h, int channel) { - return objOvCtrlChannel[channel].setPosition(x, y, w, h); -} - -bool Overlay::updateOverlaySource(const overlay_buffer_info& info, int orientation, - int flags) { - bool ret = false; - int currentFlags = 0; - - bool needUpdateFlags = false; - if (objOvCtrlChannel[0].isChannelUP()) { - needUpdateFlags = objOvCtrlChannel[0].doFlagsNeedUpdate(flags); - } - - bool geometryChanged = true; - if (info.width == mOVBufferInfo.width && - info.height == mOVBufferInfo.height && - info.format == mOVBufferInfo.format) { - geometryChanged = false; - } - - if (sHDMIAsPrimary) - needUpdateFlags = false; - - if ((false == needUpdateFlags) && (false == geometryChanged)) { - return true; - } - - // Disable rotation for the HDMI channels - int orientHdmi = 0; - int orientPrimary = sHDMIAsPrimary ? 0 : orientation; - int orient[2] = {orientPrimary, orientHdmi}; - // disable waitForVsync on HDMI, since we call the wait ioctl - int ovFlagsExternal = 0; - int ovFlagsPrimary = sHDMIAsPrimary ? (flags |= WAIT_FOR_VSYNC): flags; - int ovFlags[2] = {flags, ovFlagsExternal}; - switch(mState) { - case OV_3D_VIDEO_3D_PANEL: - orient[1] = sHDMIAsPrimary ? 0 : orientation; - break; - case OV_3D_VIDEO_3D_TV: - orient[0] = 0; - break; - default: - break; - } - - int numChannelsToUpdate = NUM_CHANNELS; - if (!geometryChanged) { - // Only update the primary channel - we only need to update the - // wait/no-wait flags - if (objOvCtrlChannel[0].isChannelUP()) { - return objOvCtrlChannel[0].updateOverlayFlags(flags); - } - } - - // Set the overlay source info - for (int i = 0; i < NUM_CHANNELS; i++) { - if (objOvCtrlChannel[i].isChannelUP()) { - ret = objOvCtrlChannel[i].updateOverlaySource(info, orient[i], ovFlags[i]); - if (!ret) { - LOGE("objOvCtrlChannel[%d].updateOverlaySource failed", i); - return false; - } - objOvCtrlChannel[i].setSize(info.size); - ret = objOvDataChannel[i].updateDataChannel(info.size); - } - } - if (ret) { - mOVBufferInfo = info; - } else - LOGE("update failed"); - return ret; -} - -bool Overlay::getAspectRatioPosition(int w, int h, overlay_rect *rect, int channel) { - return objOvCtrlChannel[channel].getAspectRatioPosition(w, h, rect); -} - -int Overlay::getS3DFormat(int format) { - // The S3D is part of the HAL_PIXEL_FORMAT_YV12 value. Add - // an explicit check for the format - if (format == HAL_PIXEL_FORMAT_YV12) { - return 0; - } - int format3D = FORMAT_3D(format); - int fIn3D = FORMAT_3D_INPUT(format3D); // MSB 2 bytes are input format - int fOut3D = FORMAT_3D_OUTPUT(format3D); // LSB 2 bytes are output format - format3D = fIn3D | fOut3D; - if (!fIn3D) { - format3D |= fOut3D << SHIFT_3D; //Set the input format - } - if (!fOut3D) { - format3D |= fIn3D >> SHIFT_3D; //Set the output format - } - return format3D; -} - -bool Overlay::setSource(const overlay_buffer_info& info, int orientation, - int hdmiConnected, int flags, int num_buffers) { - // Separate the color format from the 3D format. - // If there is 3D content; the effective format passed by the client is: - // effectiveFormat = 3D_IN | 3D_OUT | ColorFormat - int newState = mState; - bool stateChange = false, ret = true; - bool isHDMIStateChange = (mExternalDisplay != hdmiConnected) && (mState != -1); - unsigned int format3D = getS3DFormat(info.format); - int colorFormat = getColorFormat(info.format); - if (isHDMIStateChange || -1 == mState) { - // we were mirroring UI. Also HDMI state stored was stale - newState = getOverlayConfig (format3D, false, hdmiConnected); - stateChange = (mState == newState) ? false : true; - } - - if (stateChange) { - mExternalDisplay = hdmiConnected; - mState = newState; - mS3DFormat = format3D; - if (mState == OV_3D_VIDEO_2D_PANEL || mState == OV_3D_VIDEO_2D_TV) { - LOGI("3D content on 2D display: set the output format as monoscopic"); - mS3DFormat = FORMAT_3D_INPUT(format3D) | HAL_3D_OUT_MONOSCOPIC_MASK; - } - // We always enable the rotator for the primary. - bool noRot = false; - bool uiChannel = false; - int fbnum = 0; - switch(mState) { - case OV_2D_VIDEO_ON_PANEL: - if(isHDMIStateChange) { - //close HDMI Only - closeExternalChannel(); - break; - } - case OV_3D_VIDEO_2D_PANEL: - closeChannel(); - return startChannel(info, FRAMEBUFFER_0, noRot, false, - mS3DFormat, VG0_PIPE, flags, num_buffers); - break; - case OV_3D_VIDEO_3D_PANEL: - closeChannel(); - if (sHDMIAsPrimary) { - noRot = true; - flags |= WAIT_FOR_VSYNC; - send3DInfoPacket(mS3DFormat & OUTPUT_MASK_3D); - } - for (int i=0; icanSupportTrueMirroring()) { - objOvCtrlChannel[VG1_PIPE].getAspectRatioPosition( - mCroppedSrcWidth, mCroppedSrcHeight, mDevOrientation, - &priDest, &secDest); - } else { - objOvCtrlChannel[VG1_PIPE].getAspectRatioPosition( - mCroppedSrcWidth, mCroppedSrcHeight, &secDest); - } - return setChannelPosition(secDest.x, secDest.y, secDest.w, secDest.h, VG1_PIPE); - } - case OV_3D_VIDEO_2D_TV: - closeChannel(); - for (int i=0; i(buffer); - if (!hnd) { - LOGE("Overlay::queueBuffer invalid handle"); - return false; - } - const size_t offset = hnd->offset; - const int fd = hnd->fd; - switch (mState) { - case OV_UI_MIRROR_TV: - case OV_2D_VIDEO_ON_PANEL: - case OV_3D_VIDEO_2D_PANEL: - if(!queueBuffer(fd, offset, VG0_PIPE)) { - LOGE("%s:failed for channel 0", __FUNCTION__); - return false; - } - break; - case OV_2D_VIDEO_ON_TV: - case OV_3D_VIDEO_3D_PANEL: - case OV_3D_VIDEO_2D_TV: - case OV_3D_VIDEO_3D_TV: - for (int i=NUM_CHANNELS-1; i>=0; i--) { - if(!queueBuffer(fd, offset, i)) { - LOGE("%s:failed for channel %d", __FUNCTION__, i); - return false; - } - } - //Wait for HDMI done.. - if(!waitForHdmiVsync(VG1_PIPE)) { - LOGE("%s: waitforHdmiVsync failed", __FUNCTION__); - return false; - } - break; - default: - LOGE("%s:Unknown state %d", __FUNCTION__, mState); - break; - } - return true; -} - -bool Overlay::queueBuffer(int fd, uint32_t offset, int channel) { - bool ret = false; - ret = setFd(fd, channel); - if(!ret) { - LOGE("Overlay::queueBuffer channel %d setFd failed", channel); - return false; - } - ret = queueBuffer(offset, channel); - if(!ret) { - LOGE("Overlay::queueBuffer channel %d queueBuffer failed", channel); - return false; - } - return ret; -} - -OverlayControlChannel::OverlayControlChannel() : mNoRot(false), mFD(-1), mRotFD(-1), - mFormat3D(0), mIsChannelUpdated(true) { - memset(&mOVInfo, 0, sizeof(mOVInfo)); - memset(&m3DOVInfo, 0, sizeof(m3DOVInfo)); - memset(&mRotInfo, 0, sizeof(mRotInfo)); -} - - -OverlayControlChannel::~OverlayControlChannel() { - closeControlChannel(); -} - -bool OverlayControlChannel::getAspectRatioPosition(int w, int h, overlay_rect *rect) -{ - int width = w, height = h, x, y; - int fbWidth = getFBWidth(); - int fbHeight = getFBHeight(); - // width and height for YUV TILE format - int tempWidth = w, tempHeight = h; - /* Calculate the width and height if it is YUV TILE format*/ - if(getFormat() == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED) { - tempWidth = w - ( (((w-1)/64 +1)*64) - w); - tempHeight = h - ((((h-1)/32 +1)*32) - h); - } - if (width * fbHeight > fbWidth * height) { - height = fbWidth * height / width; - EVEN_OUT(height); - width = fbWidth; - } else if (width * fbHeight < fbWidth * height) { - width = fbHeight * width / height; - EVEN_OUT(width); - height = fbHeight; - } else { - width = fbWidth; - height = fbHeight; - } - /* Scaling of upto a max of 8 times supported */ - if(width >(tempWidth * HW_OVERLAY_MAGNIFICATION_LIMIT)){ - width = HW_OVERLAY_MAGNIFICATION_LIMIT * tempWidth; - } - if(height >(tempHeight*HW_OVERLAY_MAGNIFICATION_LIMIT)) { - height = HW_OVERLAY_MAGNIFICATION_LIMIT * tempHeight; - } - if (width > fbWidth) width = fbWidth; - if (height > fbHeight) height = fbHeight; - - char value[PROPERTY_VALUE_MAX]; - property_get("hw.actionsafe.width", value, "0"); - float asWidth = atof(value); - property_get("hw.actionsafe.height", value, "0"); - float asHeight = atof(value); - width = width * (1.0f - asWidth / 100.0f); - height = height * (1.0f - asHeight / 100.0f); - - x = (fbWidth - width) / 2; - y = (fbHeight - height) / 2; - rect->x = x; - rect->y = y; - rect->w = width; - rect->h = height; - return true; -} - - -// This function gets the destination position for Seconday display -// based on the position and aspect ratio of the primary -bool OverlayControlChannel::getAspectRatioPosition(int w, int h, int orientation, - overlay_rect *inRect, overlay_rect *outRect) { - float priWidth = FrameBufferInfo::getInstance()->getWidth(); - float priHeight = FrameBufferInfo::getInstance()->getHeight(); - float fbWidth = getFBWidth(); - float fbHeight = getFBHeight(); - float wRatio = 1.0; - float hRatio = 1.0; - float xRatio = 1.0; - float yRatio = 1.0; - - int xPos = 0; - int yPos = 0; - int tmp = 0; - overlay_rect rect; - switch(orientation) { - case MDP_ROT_NOP: - case MDP_ROT_180: - getAspectRatioPosition((int)priWidth, (int)priHeight, &rect); - xPos = rect.x; - yPos = rect.y; - fbWidth = rect.w; - fbHeight = rect.h; - - if(orientation == MDP_ROT_180) { - inRect->x = priWidth - (inRect->x + inRect->w); - inRect->y = priHeight - (inRect->y + inRect->h); - } - break; - case MDP_ROT_90: - case MDP_ROT_270: - if(orientation == MDP_ROT_90) { - tmp = inRect->y; - inRect->y = priWidth - (inRect->x + inRect->w); - inRect->x = tmp; - } - else if(orientation == MDP_ROT_270) { - tmp = inRect->x; - inRect->x = priHeight - (inRect->y + inRect->h); - inRect->y = tmp; - } - //Swap the destination width/height - swapWidthHeight(inRect->w, inRect->h); - // Swap width/height for primary - swapWidthHeight(priWidth, priHeight); - getAspectRatioPosition((int)priWidth, (int)priHeight, &rect); - xPos = rect.x; - yPos = rect.y; - fbWidth = rect.w; - fbHeight = rect.h; - break; - default: - LOGE("In %s: Unknown Orientation", __FUNCTION__); - break; - } - //Calculate the position... - xRatio = inRect->x/priWidth; - yRatio = inRect->y/priHeight; - - wRatio = inRect->w/priWidth; - hRatio = inRect->h/priHeight; - outRect->x = (xRatio * fbWidth) + xPos; - outRect->y = (yRatio * fbHeight) + yPos; - - outRect->w = (wRatio * fbWidth); - outRect->h = hRatio * fbHeight; - LOGD("Calculated AS Position for HDMI: X= %d, y = %d w = %d h = %d", - outRect->x, outRect->y,outRect->w, outRect->h); - return true; -} - - -bool OverlayControlChannel::getPositionS3D(int channel, int format, overlay_rect *rect) { - int wDisp = getFBWidth(); - int hDisp = getFBHeight(); - switch (format & OUTPUT_MASK_3D) { - case HAL_3D_OUT_SIDE_BY_SIDE_MASK: - if (channel == VG0_PIPE) { - rect->x = 0; - rect->y = 0; - rect->w = wDisp/2; - rect->h = hDisp; - } else { - rect->x = wDisp/2; - rect->y = 0; - rect->w = wDisp/2; - rect->h = hDisp; - } - break; - case HAL_3D_OUT_TOP_BOTTOM_MASK: - if (channel == VG0_PIPE) { - rect->x = 0; - rect->y = 0; - rect->w = wDisp; - rect->h = hDisp/2; - } else { - rect->x = 0; - rect->y = hDisp/2; - rect->w = wDisp; - rect->h = hDisp/2; - } - break; - case HAL_3D_OUT_MONOSCOPIC_MASK: - if (channel == VG1_PIPE) { - rect->x = 0; - rect->y = 0; - rect->w = wDisp; - rect->h = hDisp; - } - else - return false; - break; - case HAL_3D_OUT_INTERLEAVE_MASK: - break; - default: - reportError("Unsupported 3D output format"); - break; - } - return true; -} - -bool OverlayControlChannel::openDevices(int fbnum) { - if (fbnum < 0) - return false; - - char dev_name[64]; - snprintf(dev_name, 64, FB_DEVICE_TEMPLATE, fbnum); - mFD = open(dev_name, O_RDWR, 0); - if (mFD < 0) { - reportError("Cant open framebuffer "); - return false; - } - - fb_fix_screeninfo finfo; - if (ioctl(mFD, FBIOGET_FSCREENINFO, &finfo) == -1) { - reportError("FBIOGET_FSCREENINFO on fb1 failed"); - close(mFD); - mFD = -1; - return false; - } - - fb_var_screeninfo vinfo; - if (ioctl(mFD, FBIOGET_VSCREENINFO, &vinfo) == -1) { - reportError("FBIOGET_VSCREENINFO on fb1 failed"); - close(mFD); - mFD = -1; - return false; - } - mFBWidth = vinfo.xres; - mFBHeight = vinfo.yres; - mFBbpp = vinfo.bits_per_pixel; - mFBystride = finfo.line_length; - - if (!mNoRot) { - mRotFD = open("/dev/msm_rotator", O_RDWR, 0); - if (mRotFD < 0) { - reportError("Cant open rotator device"); - close(mFD); - mFD = -1; - return false; - } - } - - return true; -} - -bool OverlayControlChannel::setOverlayInformation(const overlay_buffer_info& info, - int zorder, int flags, int requestType) { - int w = info.width; - int h = info.height; - int format = info.format; - - mOVInfo.src.width = w; - mOVInfo.src.height = h; - mOVInfo.src_rect.x = 0; - mOVInfo.src_rect.y = 0; - mOVInfo.dst_rect.x = 0; - mOVInfo.dst_rect.y = 0; - mOVInfo.dst_rect.w = w; - mOVInfo.dst_rect.h = h; - if(format == MDP_Y_CRCB_H2V2_TILE) { - if (mNoRot) { - mOVInfo.src_rect.w = w - ((((w-1)/64 +1)*64) - w); - mOVInfo.src_rect.h = h - ((((h-1)/32 +1)*32) - h); - } else { - mOVInfo.src_rect.w = w; - mOVInfo.src_rect.h = h; - mOVInfo.src.width = (((w-1)/64 +1)*64); - mOVInfo.src.height = (((h-1)/32 +1)*32); - mOVInfo.src_rect.x = mOVInfo.src.width - w; - mOVInfo.src_rect.y = mOVInfo.src.height - h; - } - } else { - mOVInfo.src_rect.w = w; - mOVInfo.src_rect.h = h; - } - - mOVInfo.src.format = format; - int dst_w = w; - int dst_h = h; - - if (dst_w > mFBWidth) { - dst_w = mFBWidth; - dst_h = dst_h * mFBWidth / w; - } - if (dst_h > mFBHeight) { - dst_h = mFBHeight; - dst_w = dst_w * mFBHeight / h; - } - mOVInfo.dst_rect.w = dst_w; - mOVInfo.dst_rect.h = dst_h; - mOVInfo.user_data[0] = 0; - if (requestType == NEW_REQUEST) { - mOVInfo.id = MSMFB_NEW_REQUEST; - mOVInfo.z_order = zorder; - mOVInfo.alpha = 0xff; - mOVInfo.transp_mask = 0xffffffff; - } - mOVInfo.flags = 0; - setInformationFromFlags(flags, mOVInfo); - mOVInfo.dpp.sharp_strength = 0; - return true; -} - -void OverlayControlChannel::setInformationFromFlags(int flags, mdp_overlay& ov) -{ - if (flags & INTERLACED_CONTENT) { - mOVInfo.flags |= MDP_DEINTERLACE; - } else { - mOVInfo.flags &= ~MDP_DEINTERLACE; - } - - if ((flags & WAIT_FOR_VSYNC) == 0) - mOVInfo.flags |= MDP_OV_PLAY_NOWAIT; - else - mOVInfo.flags &= ~MDP_OV_PLAY_NOWAIT; - - if(flags & SECURE_OVERLAY_SESSION) - mOVInfo.flags |= MDP_SECURE_OVERLAY_SESSION; - else - mOVInfo.flags &= ~MDP_SECURE_OVERLAY_SESSION; - - //set the default sharpening settings - mOVInfo.flags |= MDP_SHARPENING; - - if (flags & DISABLE_FRAMEBUFFER_FETCH) - mOVInfo.is_fg = 1; - else - mOVInfo.is_fg = 0; - - if (flags & OVERLAY_PIPE_SHARE) { - mOVInfo.flags |= MDP_OV_PIPE_SHARE; - } else { - mOVInfo.flags &= ~MDP_OV_PIPE_SHARE; - } - mOVInfo.dpp.sharp_strength = 0; - -} - -bool OverlayControlChannel::doFlagsNeedUpdate(int flags) { - bool needUpdate = false; - - if ((flags & WAIT_FOR_VSYNC) == 0) { - if (!(mOVInfo.flags & MDP_OV_PLAY_NOWAIT)) { - needUpdate = true; - } - } - if (flags & WAIT_FOR_VSYNC) { - if (mOVInfo.flags & MDP_OV_PLAY_NOWAIT) { - needUpdate = true; - } - } - - if ((flags & DISABLE_FRAMEBUFFER_FETCH) == 0) { - if (mOVInfo.is_fg == 1) { - needUpdate = true; - } - } - if (flags & DISABLE_FRAMEBUFFER_FETCH) { - if (mOVInfo.is_fg == 0) { - needUpdate = true; - } - } - return needUpdate; -} - -bool OverlayControlChannel::startOVRotatorSessions( - const overlay_buffer_info& info, - int requestType) { - bool ret = true; - int w = info.width; - int h = info.height; - int format = info.format; - - if (!mNoRot) { - mRotInfo.src.format = format; - mRotInfo.src.width = w; - mRotInfo.src.height = h; - mRotInfo.src_rect.w = w; - mRotInfo.src_rect.h = h; - mRotInfo.dst.width = w; - mRotInfo.dst.height = h; - if(format == MDP_Y_CRCB_H2V2_TILE) { - mRotInfo.src.width = (((w-1)/64 +1)*64); - mRotInfo.src.height = (((h-1)/32 +1)*32); - mRotInfo.src_rect.w = (((w-1)/64 +1)*64); - mRotInfo.src_rect.h = (((h-1)/32 +1)*32); - mRotInfo.dst.width = (((w-1)/64 +1)*64); - mRotInfo.dst.height = (((h-1)/32 +1)*32); - mRotInfo.dst.format = MDP_Y_CRCB_H2V2; - } - mRotInfo.dst.format = get_rot_output_format(format); - mRotInfo.dst_x = 0; - mRotInfo.dst_y = 0; - mRotInfo.src_rect.x = 0; - mRotInfo.src_rect.y = 0; - mRotInfo.rotations = 0; - - if (requestType == NEW_REQUEST) { - mRotInfo.enable = 0; - if(mUIChannel) - mRotInfo.enable = 1; - mRotInfo.session_id = 0; - } else - mRotInfo.enable = 1; - - int result = ioctl(mRotFD, MSM_ROTATOR_IOCTL_START, &mRotInfo); - if (result) { - reportError("Rotator session failed"); - dump(mRotInfo); - ret = false; - } - } - - if (ret && ioctl(mFD, MSMFB_OVERLAY_SET, &mOVInfo)) { - reportError("startOVRotatorSessions, Overlay set failed"); - dump(mOVInfo); - ret = false; - } - - if (!ret) - closeControlChannel(); - else - mIsChannelUpdated = true; - return ret; -} - -bool OverlayControlChannel::updateOverlaySource(const overlay_buffer_info& info, - int orientation, int flags) -{ - int colorFormat = getColorFormat(info.format); - int hw_format = get_mdp_format(colorFormat); - overlay_buffer_info ovBufInfo; - ovBufInfo.width = info.width; - ovBufInfo.height = info.height; - ovBufInfo.format = hw_format; - - if (isInterlacedContent(info.format)) { - flags |= INTERLACED_CONTENT; - } - if (!setOverlayInformation(ovBufInfo, 0, flags, - UPDATE_REQUEST)) - return false; - - return startOVRotatorSessions(ovBufInfo, UPDATE_REQUEST); -} - -bool OverlayControlChannel::startControlChannel(const overlay_buffer_info& info, - int fbnum, bool norot, - bool uichannel, - unsigned int format3D, int zorder, - int flags) { - int colorFormat = getColorFormat(info.format); - mNoRot = norot; - mFormat = colorFormat; - mUIChannel = uichannel; - mFBNum = fbnum; - fb_fix_screeninfo finfo; - fb_var_screeninfo vinfo; - int hw_format; - - // The interlace mask is part of the HAL_PIXEL_FORMAT_YV12 value. Add - // an explicit check for the format - if (isInterlacedContent(colorFormat)) { - flags |= MDP_DEINTERLACE; - - // Get the actual format - colorFormat = colorFormat ^ HAL_PIXEL_FORMAT_INTERLACE; - } - hw_format = get_mdp_format(colorFormat); - if (hw_format < 0) { - reportError("Unsupported format"); - return false; - } - - mFormat3D = format3D; - if ( !mFormat3D || (mFormat3D & HAL_3D_OUT_MONOSCOPIC_MASK) ) { - // Set the share bit for sharing the VG pipe - flags |= OVERLAY_PIPE_SHARE; - } - //do not set the PIPE SHARE bit for true mirroring - if(uichannel && FrameBufferInfo::getInstance()->canSupportTrueMirroring()) - flags &= ~OVERLAY_PIPE_SHARE; - if (!openDevices(fbnum)) - return false; - - //get Z order - zorder = ZOrderManager::getInstance()->getZ(fbnum); - if (zorder == NO_PIPE) - return false; - - overlay_buffer_info ovBufInfo; - ovBufInfo.width = info.width; - ovBufInfo.height = info.height; - ovBufInfo.format = hw_format; - if (!setOverlayInformation(ovBufInfo, zorder, flags, NEW_REQUEST)) - return false; - - return startOVRotatorSessions(ovBufInfo, NEW_REQUEST); -} - -bool OverlayControlChannel::closeControlChannel() { - if (!isChannelUP()) - return true; - - if (!mNoRot && mRotFD > 0) { - ioctl(mRotFD, MSM_ROTATOR_IOCTL_FINISH, &(mRotInfo.session_id)); - close(mRotFD); - mRotFD = -1; - } - - int ovid = mOVInfo.id; - ioctl(mFD, MSMFB_OVERLAY_UNSET, &ovid); - if (m3DOVInfo.is_3d) { - m3DOVInfo.is_3d = 0; - ioctl(mFD, MSMFB_OVERLAY_3D, &m3DOVInfo); - } - - close(mFD); - - if(NO_PIPE != mOVInfo.z_order){ - ZOrderManager::getInstance()->decZ(mFBNum, mOVInfo.z_order); - } - memset(&mOVInfo, 0, sizeof(mOVInfo)); - memset(&mRotInfo, 0, sizeof(mRotInfo)); - memset(&m3DOVInfo, 0, sizeof(m3DOVInfo)); - - mOVInfo.z_order = NO_PIPE; - mFD = -1; - - return true; -} - -bool OverlayControlChannel::updateOverlayFlags(int flags) { - if ((flags & WAIT_FOR_VSYNC) == 0) - mOVInfo.flags |= MDP_OV_PLAY_NOWAIT; - else - mOVInfo.flags &= ~MDP_OV_PLAY_NOWAIT; - - if (flags & DISABLE_FRAMEBUFFER_FETCH) - mOVInfo.is_fg = 1; - else - mOVInfo.is_fg = 0; - - if (ioctl(mFD, MSMFB_OVERLAY_SET, &mOVInfo)) { - LOGE("%s: OVERLAY_SET failed", __FUNCTION__); - dump(mOVInfo); - return false; - } - return true; -} - -bool OverlayControlChannel::setPosition(int x, int y, uint32_t w, uint32_t h) { - - if (!isChannelUP() || - (x < 0) || (y < 0) || ((x + w) > mFBWidth) || - ((y + h) > mFBHeight)) { - reportError("setPosition failed"); - LOGW("x %d y %d (x+w) %d (y+h) %d FBWidth %d FBHeight %d", x, y, x+w, y+h, - mFBWidth,mFBHeight); - return false; - } - if( x != mOVInfo.dst_rect.x || y != mOVInfo.dst_rect.y || - w != mOVInfo.dst_rect.w || h != mOVInfo.dst_rect.h ) { - mdp_overlay ov; - ov.id = mOVInfo.id; - if (ioctl(mFD, MSMFB_OVERLAY_GET, &ov)) { - reportError("setPosition, overlay GET failed"); - return false; - } - -// LGE_CHANGE_S, [G1_Player][mukyung.jung@lge.com], 20120206, Apply SR 00718706 to fix noise of QCIF contents { - // can not scale-up 8 times over original source - // return false to compose with GPU -#if 1 - if(w > (ov.src_rect.w * HW_OVERLAY_MAGNIFICATION_LIMIT)){ - LOGE("[TJ] setPosition : too big width, back to GPU comp %d => %d", ov.src_rect.w, w); - return false; - } - if(h > (ov.src_rect.h * HW_OVERLAY_MAGNIFICATION_LIMIT)) { - LOGE("[TJ] setPosition : too big height, back to GPU comp %d => %d", ov.src_rect.h, h); - return false; - } -#else -// LGE_CHANGE_E, [G1_Player][mukyung.jung@lge.com], 20120206, Apply SR 00718706 to fix noise of QCIF contents } - - /* Scaling of upto a max of 8 times supported */ - if(w >(ov.src_rect.w * HW_OVERLAY_MAGNIFICATION_LIMIT)){ - w = HW_OVERLAY_MAGNIFICATION_LIMIT * ov.src_rect.w; - x = (mFBWidth - w) / 2; - } - if(h >(ov.src_rect.h * HW_OVERLAY_MAGNIFICATION_LIMIT)) { - h = HW_OVERLAY_MAGNIFICATION_LIMIT * ov.src_rect.h; - y = (mFBHeight - h) / 2; - } -// LGE_CHANGE_S, [G1_Player][mukyung.jung@lge.com], 20120206, Apply SR 00718706 to fix noise of QCIF contents { -#endif -// LGE_CHANGE_E, [G1_Player][mukyung.jung@lge.com], 20120206, Apply SR 00718706 to fix noise of QCIF contents } - - ov.dst_rect.x = x; - ov.dst_rect.y = y; - ov.dst_rect.w = w; - ov.dst_rect.h = h; - if (ioctl(mFD, MSMFB_OVERLAY_SET, &ov)) { - reportError("setPosition, Overlay SET failed"); - dump(ov); - return false; - } - mOVInfo = ov; -// LGE_CHANGE_S, [G1_Player][mukyung.jung@lge.com], 20120206, Apply SR 00718706 to fix noise of QCIF contents { - LOGE("setPosition"); - dump(ov); -// LGE_CHANGE_E, [G1_Player][mukyung.jung@lge.com], 20120206, Apply SR 00718706 to fix noise of QCIF contents } - } - return true; -} - -void OverlayControlChannel::swapOVRotWidthHeight() { - int tmp = mOVInfo.src.width; - mOVInfo.src.width = mOVInfo.src.height; - mOVInfo.src.height = tmp; - - tmp = mOVInfo.src_rect.h; - mOVInfo.src_rect.h = mOVInfo.src_rect.w; - mOVInfo.src_rect.w = tmp; - - tmp = mRotInfo.dst.width; - mRotInfo.dst.width = mRotInfo.dst.height; - mRotInfo.dst.height = tmp; -} - -bool OverlayControlChannel::useVirtualFB() { - if(!m3DOVInfo.is_3d) { - m3DOVInfo.is_3d = 1; - mFBWidth *= 2; - mFBHeight /= 2; - m3DOVInfo.width = mFBWidth; - m3DOVInfo.height = mFBHeight; - return ioctl(mFD, MSMFB_OVERLAY_3D, &m3DOVInfo) ? false : true; - } - return true; -} - -bool OverlayControlChannel::setTransform(int value, bool fetch) { - if (!isChannelUP()) { - LOGE("%s: channel is not up", __FUNCTION__); - return false; - } - - mdp_overlay ov = mOVInfo; - if (fetch && ioctl(mFD, MSMFB_OVERLAY_GET, &ov)) { - reportError("setParameter, overlay GET failed"); - return false; - } - mOVInfo = ov; - if (!mIsChannelUpdated) { - int orientation = get_mdp_orientation(value); - if (orientation == mOVInfo.user_data[0]) { - return true; - } - } - mIsChannelUpdated = false; - - int val = mOVInfo.user_data[0]; - if (mNoRot) - return true; - - int rot = value; - - switch(rot) { - case 0: - case HAL_TRANSFORM_FLIP_H: - case HAL_TRANSFORM_FLIP_V: - { - if (val == MDP_ROT_90) { - int tmp = mOVInfo.src_rect.y; - mOVInfo.src_rect.y = mOVInfo.src.width - - (mOVInfo.src_rect.x + mOVInfo.src_rect.w); - mOVInfo.src_rect.x = tmp; - swapOVRotWidthHeight(); - } - else if (val == MDP_ROT_270) { - int tmp = mOVInfo.src_rect.x; - mOVInfo.src_rect.x = mOVInfo.src.height - ( - mOVInfo.src_rect.y + mOVInfo.src_rect.h); - mOVInfo.src_rect.y = tmp; - swapOVRotWidthHeight(); - } - break; - } - case HAL_TRANSFORM_ROT_90: - case (HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_H): - case (HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_V): - { - if (val == MDP_ROT_270) { - mOVInfo.src_rect.x = mOVInfo.src.width - ( - mOVInfo.src_rect.x + mOVInfo.src_rect.w); - mOVInfo.src_rect.y = mOVInfo.src.height - ( - mOVInfo.src_rect.y + mOVInfo.src_rect.h); - } - else if (val == MDP_ROT_NOP || val == MDP_ROT_180) { - int tmp = mOVInfo.src_rect.x; - mOVInfo.src_rect.x = mOVInfo.src.height - - (mOVInfo.src_rect.y + mOVInfo.src_rect.h); - mOVInfo.src_rect.y = tmp; - swapOVRotWidthHeight(); - } - break; - } - case HAL_TRANSFORM_ROT_180: - { - if (val == MDP_ROT_270) { - int tmp = mOVInfo.src_rect.y; - mOVInfo.src_rect.y = mOVInfo.src.width - - (mOVInfo.src_rect.x + mOVInfo.src_rect.w); - mOVInfo.src_rect.x = tmp; - swapOVRotWidthHeight(); - } - else if (val == MDP_ROT_90) { - int tmp = mOVInfo.src_rect.x; - mOVInfo.src_rect.x = mOVInfo.src.height - ( - mOVInfo.src_rect.y + mOVInfo.src_rect.h); - mOVInfo.src_rect.y = tmp; - swapOVRotWidthHeight(); - } - break; - } - case HAL_TRANSFORM_ROT_270: - { - if (val == MDP_ROT_90) { - mOVInfo.src_rect.y = mOVInfo.src.height - - (mOVInfo.src_rect.y + mOVInfo.src_rect.h); - mOVInfo.src_rect.x = mOVInfo.src.width - - (mOVInfo.src_rect.x + mOVInfo.src_rect.w); - } - else if (val == MDP_ROT_NOP || val == MDP_ROT_180) { - int tmp = mOVInfo.src_rect.y; - mOVInfo.src_rect.y = mOVInfo.src.width - ( - mOVInfo.src_rect.x + mOVInfo.src_rect.w); - mOVInfo.src_rect.x = tmp; - swapOVRotWidthHeight(); - } - break; - } - default: return false; - } - - int mdp_rotation = get_mdp_orientation(rot); - if (mdp_rotation == -1) - return false; - - mOVInfo.user_data[0] = mdp_rotation; - mRotInfo.rotations = mOVInfo.user_data[0]; - - /* Rotator always outputs non-tiled formats. - If rotator is used, set Overlay input to non-tiled - Else, overlay input remains tiled */ - if (mOVInfo.user_data[0]) { - mOVInfo.src.format = get_rot_output_format(mRotInfo.src.format); - mRotInfo.enable = 1; - } - else { - //We can switch between rotator ON and OFF. Reset overlay - //i/p format whenever this happens - if(mRotInfo.dst.format == mOVInfo.src.format) - mOVInfo.src.format = mRotInfo.src.format; - mRotInfo.enable = 0; - //Always enable rotation for UI mirror usecase - if(mUIChannel) - mRotInfo.enable = 1; - } - -// LGE_CHANGE_S, [G1_Player][mukyung.jung@lge.com], 20120206, Apply SR 00718706 to fix noise of QCIF contents { - // can not scale-up 8 times over original source - // return false to compose with GPU -#if 1 - if(mOVInfo.dst_rect.w > (mOVInfo.src_rect.w * HW_OVERLAY_MAGNIFICATION_LIMIT)){ - LOGE("[TJ] setTransform : too big width, back to GPU comp %d => %d", mOVInfo.src_rect.w, mOVInfo.dst_rect.w); - return false; - } - if(mOVInfo.dst_rect.h > (mOVInfo.src_rect.h * HW_OVERLAY_MAGNIFICATION_LIMIT)) { - LOGE("[TJ] setTransform : too big height, back to GPU comp %d => %d", mOVInfo.src_rect.h, mOVInfo.dst_rect.h); - return false; - } -#endif -// LGE_CHANGE_E, [G1_Player][mukyung.jung@lge.com], 20120206, Apply SR 00718706 to fix noise of QCIF contents } - - //dump(mRotInfo); // TJ - if (ioctl(mRotFD, MSM_ROTATOR_IOCTL_START, &mRotInfo)) { - reportError("setTransform, rotator start failed"); - dump(mRotInfo); - return false; - } - - if ((mOVInfo.user_data[0] == MDP_ROT_90) || - (mOVInfo.user_data[0] == MDP_ROT_270)) - mOVInfo.flags |= MDP_SOURCE_ROTATED_90; - else - mOVInfo.flags &= ~MDP_SOURCE_ROTATED_90; - -// LGE_CHANGE_S, [G1_Player][mukyung.jung@lge.com], 20120206, Apply SR 00718706 to fix noise of QCIF contents { - LOGE("setTransform"); // TJ - dump(mOVInfo); // TJ -// LGE_CHANGE_E, [G1_Player][mukyung.jung@lge.com], 20120206, Apply SR 00718706 to fix noise of QCIF contents } - - if (ioctl(mFD, MSMFB_OVERLAY_SET, &mOVInfo)) { - reportError("setTransform, overlay set failed"); - dump(mOVInfo); - return false; - } - - return true; -} - -bool OverlayControlChannel::getPosition(int& x, int& y, - uint32_t& w, uint32_t& h) { - if (!isChannelUP()) - return false; - //mOVInfo has the current Overlay Position - x = mOVInfo.dst_rect.x; - y = mOVInfo.dst_rect.y; - w = mOVInfo.dst_rect.w; - h = mOVInfo.dst_rect.h; - - return true; -} - -bool OverlayControlChannel::getOrientation(int& orientation) const { - if (!isChannelUP()) - return false; - // mOVInfo has the current orientation - orientation = mOVInfo.user_data[0]; - return true; -} -bool OverlayControlChannel::getOvSessionID(int& sessionID) const { - if (!isChannelUP()) - return false; - sessionID = mOVInfo.id; - return true; -} - -bool OverlayControlChannel::getRotSessionID(int& sessionID) const { - if (!isChannelUP()) - return false; - sessionID = mRotInfo.session_id; - return true; -} - -bool OverlayControlChannel::getSize(int& size) const { - if (!isChannelUP()) - return false; - size = mSize; - return true; -} - -OverlayDataChannel::OverlayDataChannel() : mNoRot(false), mFD(-1), mRotFD(-1), - mPmemFD(-1), mPmemAddr(0), mUpdateDataChannel(false) -{ - //XXX: getInstance(false) implies that it should only - // use the kernel allocator. Change it to something - // more descriptive later. - mAlloc = gralloc::IAllocController::getInstance(false); -} - -OverlayDataChannel::~OverlayDataChannel() { - closeDataChannel(); -} - -bool OverlayDataChannel::startDataChannel( - const OverlayControlChannel& objOvCtrlChannel, - int fbnum, bool norot, bool secure, bool uichannel, - int num_buffers) { - int ovid, rotid, size; - mNoRot = norot; - mSecure = secure; - memset(&mOvData, 0, sizeof(mOvData)); - memset(&mOvDataRot, 0, sizeof(mOvDataRot)); - memset(&mRotData, 0, sizeof(mRotData)); - if (objOvCtrlChannel.getOvSessionID(ovid) && - objOvCtrlChannel.getRotSessionID(rotid) && - objOvCtrlChannel.getSize(size)) { - return startDataChannel(ovid, rotid, size, fbnum, - norot, uichannel, num_buffers); - } - else - return false; -} - -bool OverlayDataChannel::openDevices(int fbnum, bool uichannel, int num_buffers) { - if (fbnum < 0) - return false; - char dev_name[64]; - snprintf(dev_name, 64, FB_DEVICE_TEMPLATE, fbnum); - - mFD = open(dev_name, O_RDWR, 0); - if (mFD < 0) { - reportError("Cant open framebuffer "); - return false; - } - if (!mNoRot) { - mRotFD = open("/dev/msm_rotator", O_RDWR, 0); - if (mRotFD < 0) { - reportError("Cant open rotator device"); - close(mFD); - mFD = -1; - return false; - } - - return mapRotatorMemory(num_buffers, uichannel, NEW_REQUEST); - } - return true; -} - -bool OverlayDataChannel::mapRotatorMemory(int num_buffers, bool uiChannel, int requestType) -{ - mPmemAddr = MAP_FAILED; - - alloc_data data; - data.base = 0; - data.fd = -1; - data.offset = 0; - data.size = mPmemOffset * num_buffers; - data.align = getpagesize(); - data.uncached = true; - - int allocFlags = GRALLOC_USAGE_PRIVATE_MM_HEAP | - GRALLOC_USAGE_PRIVATE_WRITEBACK_HEAP| - GRALLOC_USAGE_PRIVATE_DO_NOT_MAP; - - if(mSecure) { - allocFlags |= GRALLOC_USAGE_PROTECTED; - } else { - allocFlags |= GRALLOC_USAGE_PRIVATE_ADSP_HEAP | - GRALLOC_USAGE_PRIVATE_IOMMU_HEAP; - if((requestType == NEW_REQUEST) && !uiChannel) - allocFlags |= GRALLOC_USAGE_PRIVATE_SMI_HEAP; - } - - int err = mAlloc->allocate(data, allocFlags, 0); - if(err) { - reportError("Cant allocate rotatory memory"); - close(mFD); - mFD = -1; - close(mRotFD); - mRotFD = -1; - return false; - } - mPmemFD = data.fd; - mPmemAddr = data.base; - mBufferType = data.allocType; - - // Set this flag if source memory is fb - if(uiChannel) - mRotData.src.flags |= MDP_MEMORY_ID_TYPE_FB; - - mOvDataRot.data.memory_id = mPmemFD; - mRotData.dst.memory_id = mPmemFD; - mRotData.dst.offset = 0; - mNumBuffers = num_buffers; - mCurrentItem = 0; - for (int i = 0; i < num_buffers; i++) - mRotOffset[i] = i * mPmemOffset; - - return true; -} - -bool OverlayDataChannel::updateDataChannel(int size) { - mUpdateDataChannel = true; - mNewPmemOffset = size; - return true; -} - -bool OverlayDataChannel::startDataChannel(int ovid, int rotid, int size, - int fbnum, bool norot, - bool uichannel, int num_buffers) { - memset(&mOvData, 0, sizeof(mOvData)); - memset(&mOvDataRot, 0, sizeof(mOvDataRot)); - memset(&mRotData, 0, sizeof(mRotData)); - mNoRot = norot; - mOvData.data.memory_id = -1; - mOvData.id = ovid; - mOvDataRot = mOvData; - mPmemOffset = size; - mRotData.session_id = rotid; - mNumBuffers = 0; - mCurrentItem = 0; - - return openDevices(fbnum, uichannel, num_buffers); -} - -bool OverlayDataChannel::closeDataChannel() { - if (!isChannelUP()) - return true; - - if (!mNoRot && mRotFD > 0) { - sp memalloc = mAlloc->getAllocator(mBufferType); - memalloc->free_buffer(mPmemAddr, mPmemOffset * mNumBuffers, 0, mPmemFD); - close(mPmemFD); - mPmemFD = -1; - close(mRotFD); - mRotFD = -1; - } - close(mFD); - mFD = -1; - memset(&mOvData, 0, sizeof(mOvData)); - memset(&mOvDataRot, 0, sizeof(mOvDataRot)); - memset(&mRotData, 0, sizeof(mRotData)); - - mNumBuffers = 0; - mCurrentItem = 0; - - return true; -} - -bool OverlayDataChannel::setFd(int fd) { - mOvData.data.memory_id = fd; - return true; -} - -bool OverlayDataChannel::queueBuffer(uint32_t offset) { - if ((!isChannelUP()) || mOvData.data.memory_id < 0) { - reportError("QueueBuffer failed, either channel is not set or no file descriptor to read from"); - return false; - } - - int oldPmemFD = -1; - void* oldPmemAddr = MAP_FAILED; - uint32_t oldPmemOffset = -1; - bool result; - if (!mNoRot) { - if (mUpdateDataChannel) { - oldPmemFD = mPmemFD; - oldPmemAddr = mPmemAddr; - oldPmemOffset = mPmemOffset; - mPmemOffset = mNewPmemOffset; - mNewPmemOffset = -1; - // Map the new PMEM memory - result = mapRotatorMemory(mNumBuffers, 0, UPDATE_REQUEST); - if (!result) { - LOGE("queueBuffer: mapRotatorMemory failed"); - return false; - } - mUpdateDataChannel = false; - } - } - - result = queue(offset); - - // Unmap the old PMEM memory after the queueBuffer has returned - if (oldPmemFD != -1 && oldPmemAddr != MAP_FAILED) { - sp memalloc = mAlloc->getAllocator(mBufferType); - memalloc->free_buffer(oldPmemAddr, oldPmemOffset * mNumBuffers, 0, oldPmemFD); - oldPmemFD = -1; - } - return result; -} - -bool OverlayDataChannel::queue(uint32_t offset) { - msmfb_overlay_data *odPtr; - mOvData.data.offset = offset; - odPtr = &mOvData; - if (!mNoRot) { - mRotData.src.memory_id = mOvData.data.memory_id; - mRotData.src.offset = offset; - mRotData.dst.offset = (mRotData.dst.offset) ? 0 : mPmemOffset; - mRotData.dst.offset = mRotOffset[mCurrentItem]; - mCurrentItem = (mCurrentItem + 1) % mNumBuffers; - - int result = ioctl(mRotFD, - MSM_ROTATOR_IOCTL_ROTATE, &mRotData); - - if (!result) { - mOvDataRot.data.offset = (uint32_t) mRotData.dst.offset; - odPtr = &mOvDataRot; - } - } - - if (ioctl(mFD, MSMFB_OVERLAY_PLAY, odPtr)) { - reportError("overlay play failed."); - return false; - } - - return true; -} - -bool OverlayDataChannel::waitForHdmiVsync() { - if (!isChannelUP()) { - LOGE("%s: channel not up", __FUNCTION__); - return false; - } - if (ioctl(mFD, MSMFB_OVERLAY_PLAY_WAIT, &mOvData)) { - LOGE("%s: MSMFB_OVERLAY_PLAY_WAIT failed", __FUNCTION__); - return false; - } - return true; -} - -bool OverlayDataChannel::getCropS3D(overlay_rect *inRect, int channel, int format, - overlay_rect *rect) { - // for the 3D usecase extract channels from a frame - switch (format & INPUT_MASK_3D) { - case HAL_3D_IN_SIDE_BY_SIDE_L_R: - if(channel == 0) { - rect->x = 0; - rect->y = 0; - rect->w = inRect->w/2; - rect->h = inRect->h; - } else { - rect->x = inRect->w/2; - rect->y = 0; - rect->w = inRect->w/2; - rect->h = inRect->h; - } - break; - case HAL_3D_IN_SIDE_BY_SIDE_R_L: - if(channel == 1) { - rect->x = 0; - rect->y = 0; - rect->w = inRect->w/2; - rect->h = inRect->h; - } else { - rect->x = inRect->w/2; - rect->y = 0; - rect->w = inRect->w/2; - rect->h = inRect->h; - } - break; - case HAL_3D_IN_TOP_BOTTOM: - if(channel == 0) { - rect->x = 0; - rect->y = 0; - rect->w = inRect->w; - rect->h = inRect->h/2; - } else { - rect->x = 0; - rect->y = inRect->h/2; - rect->w = inRect->w; - rect->h = inRect->h/2; - } - break; - case HAL_3D_IN_INTERLEAVE: - break; - default: - reportError("Unsupported 3D format..."); - break; - } - return true; -} - -bool OverlayDataChannel::setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h) { - if (!isChannelUP()) { - reportError("Channel not set"); - return false; - } - - mdp_overlay ov; - ov.id = mOvData.id; - if (ioctl(mFD, MSMFB_OVERLAY_GET, &ov)) { - reportError("setCrop, overlay GET failed"); - return false; - } - - if ((ov.user_data[0] == MDP_ROT_90) || - (ov.user_data[0] == (MDP_ROT_90 | MDP_FLIP_UD)) || - (ov.user_data[0] == (MDP_ROT_90 | MDP_FLIP_LR))){ - if (ov.src.width < (y + h)) - return false; - - uint32_t tmp = x; - x = ov.src.width - (y + h); - y = tmp; - - tmp = w; - w = h; - h = tmp; - } - else if (ov.user_data[0] == MDP_ROT_270) { - if (ov.src.height < (x + w)) - return false; - - uint32_t tmp = y; - y = ov.src.height - (x + w); - x = tmp; - - tmp = w; - w = h; - h = tmp; - } - else if(ov.user_data[0] == MDP_ROT_180) { - if ((ov.src.height < (y + h)) || (ov.src.width < ( x + w))) - return false; - - x = ov.src.width - (x + w); - y = ov.src.height - (y + h); - } - - - normalize_crop(x, w); - normalize_crop(y, h); - - if ((ov.src_rect.x == x) && - (ov.src_rect.y == y) && - (ov.src_rect.w == w) && - (ov.src_rect.h == h)) - return true; - - ov.src_rect.x = x; - ov.src_rect.y = y; - ov.src_rect.w = w; - ov.src_rect.h = h; - -// LGE_CHANGE_S, [G1_Player][mukyung.jung@lge.com], 20120206, Apply SR 00718706 to fix noise of QCIF contents { - // can not scale-up 8 times over original source - // return false to compose with GPU -#if 1 - if(ov.dst_rect.w > (ov.src_rect.w * HW_OVERLAY_MAGNIFICATION_LIMIT)){ - LOGE("[TJ] setCrop : too big width, back to GPU comp %d => %d", ov.src_rect.w, ov.dst_rect.w); - return false; - } - if(ov.dst_rect.h > (ov.src_rect.h * HW_OVERLAY_MAGNIFICATION_LIMIT)) { - LOGE("[TJ] setCrop : too big height, back to GPU comp %d => %d", ov.src_rect.h, ov.dst_rect.h); - return false; - } -#else -// LGE_CHANGE_E, [G1_Player][mukyung.jung@lge.com], 20120206, Apply SR 00718706 to fix noise of QCIF contents } - - /* Scaling of upto a max of 8 times supported */ - if(ov.dst_rect.w >(ov.src_rect.w * HW_OVERLAY_MAGNIFICATION_LIMIT)){ - ov.dst_rect.w = HW_OVERLAY_MAGNIFICATION_LIMIT * ov.src_rect.w; - } - if(ov.dst_rect.h >(ov.src_rect.h * HW_OVERLAY_MAGNIFICATION_LIMIT)) { - ov.dst_rect.h = HW_OVERLAY_MAGNIFICATION_LIMIT * ov.src_rect.h; - } -// LGE_CHANGE_S, [G1_Player][mukyung.jung@lge.com], 20120206, Apply SR 00718706 to fix noise of QCIF contents { -#endif - - LOGE("setCrop"); - dump(ov); -// LGE_CHANGE_E, [G1_Player][mukyung.jung@lge.com], 20120206, Apply SR 00718706 to fix noise of QCIF contents } - - if (ioctl(mFD, MSMFB_OVERLAY_SET, &ov)) { - reportError("setCrop, overlay set error"); - dump(ov); - return false; - } - - return true; -} - -/* setVisualParam can be called to set the configuration value of a post - * processing feature (HUE,SATURATION,BRIGHTNESS,CONTRAST,SMOOTHING/SHARPENING) - * for the first 4, the setting will stay set until the parameter is changed - * by another call to setVisualParam with that same paramType */ -void Overlay::setVisualParam(int8_t paramType, float paramValue) { - switch (mState) { - case OV_UI_MIRROR_TV: - case OV_2D_VIDEO_ON_PANEL: - case OV_3D_VIDEO_2D_PANEL: - // set the parameter value for the given parameter type. - if(!objOvCtrlChannel[VG0_PIPE].setVisualParam(paramType, paramValue)) { - LOGE("Failed to set param %d for value %f", paramType, paramValue); - } - break; - case OV_2D_VIDEO_ON_TV: - case OV_3D_VIDEO_3D_PANEL: - case OV_3D_VIDEO_2D_TV: - case OV_3D_VIDEO_3D_TV: - for (int i=0; i -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#ifdef USES_POST_PROCESSING -#include "lib-postproc.h" -#endif - -#define HW_OVERLAY_MAGNIFICATION_LIMIT 8 -#define HW_OVERLAY_MINIFICATION_LIMIT HW_OVERLAY_MAGNIFICATION_LIMIT - -#define EVEN_OUT(x) if (x & 0x0001) {x--;} -#define NO_PIPE -1 -#define VG0_PIPE 0 -#define VG1_PIPE 1 -#define NUM_CHANNELS 2 -#define NUM_FB_DEVICES 3 -#define FRAMEBUFFER_0 0 -#define FRAMEBUFFER_1 1 -#define FRAMEBUFFER_2 2 -#define NUM_SHARPNESS_VALS 256 -#define SHARPNESS_RANGE 1.0f -#define HUE_RANGE 180 -#define BRIGHTNESS_RANGE 255 -#define CON_SAT_RANGE 1.0f -#define CAP_RANGE(value,max,min) do { if (value - min < -0.0001)\ - {value = min;}\ - else if(value - max > 0.0001)\ - {value = max;}\ - } while(0); - -enum { - HDMI_OFF, - HDMI_ON -}; - -enum { - OVERLAY_CHANNEL_DOWN, - OVERLAY_CHANNEL_UP -}; - -enum { - NEW_REQUEST, - UPDATE_REQUEST -}; - -enum { - WAIT_FOR_VSYNC = 1<<0, - DISABLE_FRAMEBUFFER_FETCH = 1<<1, - INTERLACED_CONTENT = 1<<2, - OVERLAY_PIPE_SHARE = 1<<3, - SECURE_OVERLAY_SESSION = 1<<4, -}; - -/* ------------------------------- 3D defines ---------------------------------------*/ -// The compound format passed to the overlay is -// ABCCC where A is the input 3D format, -// B is the output 3D format -// CCC is the color format e.g YCbCr420SP YCrCb420SP etc. -#define FORMAT_3D(x) (x & 0xFF000) -#define COLOR_FORMAT(x) (x & 0xFFF) -// in the final 3D format, the MSB 2Bytes are the input format and the -// LSB 2bytes are the output format. Shift the output byte 12 bits. -#define SHIFT_OUTPUT_3D 12 -#define FORMAT_3D_OUTPUT(x) ((x & 0xF000) >> SHIFT_OUTPUT_3D) -#define FORMAT_3D_INPUT(x) (x & 0xF0000) -#define INPUT_MASK_3D 0xFFFF0000 -#define OUTPUT_MASK_3D 0x0000FFFF -#define SHIFT_3D 16 -// The output format is the 2MSB bytes. Shift the format by 12 to reflect this -#define HAL_3D_OUT_SIDE_BY_SIDE_MASK (HAL_3D_OUT_SIDE_BY_SIDE >> SHIFT_OUTPUT_3D) -#define HAL_3D_OUT_TOP_BOTTOM_MASK (HAL_3D_OUT_TOP_BOTTOM >> SHIFT_OUTPUT_3D) -#define HAL_3D_OUT_INTERLEAVE_MASK (HAL_3D_OUT_INTERLEAVE >> SHIFT_OUTPUT_3D) -#define HAL_3D_OUT_MONOSCOPIC_MASK (HAL_3D_OUT_MONOSCOPIC >> SHIFT_OUTPUT_3D) - -// 3D panel barrier orientation -#define BARRIER_LANDSCAPE 1 -#define BARRIER_PORTRAIT 2 - -#ifdef HDMI_AS_PRIMARY -#define FORMAT_3D_FILE "/sys/class/graphics/fb0/format_3d" -#define EDID_3D_INFO_FILE "/sys/class/graphics/fb0/3d_present" -#else -#define FORMAT_3D_FILE "/sys/class/graphics/fb1/format_3d" -#define EDID_3D_INFO_FILE "/sys/class/graphics/fb1/3d_present" -#endif -#define BARRIER_FILE "/sys/devices/platform/mipi_novatek.0/enable_3d_barrier" -/* -------------------------- end 3D defines ----------------------------------------*/ - -// Struct to hold the buffer info: geometry and size -struct overlay_buffer_info { - int width; - int height; - int format; - int size; -}; - -using android::Mutex; -namespace overlay { - -#define FB_DEVICE_TEMPLATE "/dev/graphics/fb%u" - - //Utility Class to query the framebuffer info - class FrameBufferInfo { - int mFBWidth; - int mFBHeight; - bool mBorderFillSupported; - static FrameBufferInfo *sFBInfoInstance; - - FrameBufferInfo():mFBWidth(0),mFBHeight(0), mBorderFillSupported(false) { - char const * const device_name = - "/dev/graphics/fb0"; - int fd = open(device_name, O_RDWR, 0); - mdp_overlay ov; - memset(&ov, 0, sizeof(ov)); - if (fd < 0) { - LOGE("FrameBufferInfo: Cant open framebuffer "); - return; - } - fb_var_screeninfo vinfo; - if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1) { - LOGE("FrameBufferInfo: FBIOGET_VSCREENINFO on fb0 failed"); - close(fd); - fd = -1; - return; - } - ov.id = 1; - if(ioctl(fd, MSMFB_OVERLAY_GET, &ov)) { - LOGE("FrameBufferInfo: MSMFB_OVERLAY_GET on fb0 failed"); - close(fd); - fd = -1; - return; - } - close(fd); - fd = -1; - mFBWidth = vinfo.xres; - mFBHeight = vinfo.yres; - mBorderFillSupported = (ov.flags & MDP_BORDERFILL_SUPPORTED) ? - true : false; - } - public: - static FrameBufferInfo* getInstance(){ - if (!sFBInfoInstance){ - sFBInfoInstance = new FrameBufferInfo; - } - return sFBInfoInstance; - } - int getWidth() const { return mFBWidth; } - int getHeight() const { return mFBHeight; } - bool canSupportTrueMirroring() const { - return mBorderFillSupported; } - }; - -enum { - OV_UI_MIRROR_TV = 0, - OV_2D_VIDEO_ON_PANEL, - OV_2D_VIDEO_ON_TV, - OV_3D_VIDEO_2D_PANEL, - OV_3D_VIDEO_2D_TV, - OV_3D_VIDEO_3D_PANEL, - OV_3D_VIDEO_3D_TV -}; -bool isHDMIConnected(); -bool is3DTV(); -bool isPanel3D(); -bool usePanel3D(); -bool send3DInfoPacket(unsigned int format3D); -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); -int get_mdp_orientation(int value); -void normalize_crop(uint32_t& xy, uint32_t& wh); -//Initializes the overlay - cleans up any existing overlay pipes -int initOverlay(); - -/* Print values being sent to driver in case of ioctl failures - These logs are enabled only if DEBUG_OVERLAY is true */ -void dump(msm_rotator_img_info& mRotInfo); -void dump(mdp_overlay& mOvInfo); -const char* getFormatString(int format); - - //singleton class to decide the z order of new overlay surfaces - class ZOrderManager { - bool mFB0Pipes[NUM_CHANNELS]; - bool mFB1Pipes[NUM_CHANNELS+1]; //FB1 can have 3 pipes - int mPipesInuse; // Holds the number of pipes in use - int mMaxPipes; // Max number of pipes - static ZOrderManager *sInstance; - Mutex *mObjMutex; - ZOrderManager(){ - mPipesInuse = 0; - // for true mirroring support there can be 3 pipes on secondary - mMaxPipes = FrameBufferInfo::getInstance()->canSupportTrueMirroring()? - NUM_CHANNELS+1 : NUM_CHANNELS; - for (int i = 0; i < NUM_CHANNELS; i++) - mFB0Pipes[i] = false; - for (int j = 0; j < mMaxPipes; j++) - mFB1Pipes[j] = false; - mObjMutex = new Mutex(); - } - ~ZOrderManager() { - delete sInstance; - delete mObjMutex; - } - public: - static ZOrderManager* getInstance(){ - if (!sInstance){ - sInstance = new ZOrderManager; - } - return sInstance; - } - int getZ(int fbnum); - void decZ(int fbnum, int zorder); - }; -const int max_num_buffers = 3; -typedef struct mdp_rect overlay_rect; - -class OverlayControlChannel { - -enum { - SET_NONE = 0, - SET_SHARPNESS, -#ifdef USES_POST_PROCESSING - SET_HUE, - SET_BRIGHTNESS, - SET_SATURATION, - SET_CONTRAST, -#endif - RESET_ALL, -}; - bool mNoRot; - int mFBNum; - int mFBWidth; - int mFBHeight; - int mFBbpp; - int mFBystride; - int mFormat; - int mFD; - int mRotFD; - int mSize; - int mOrientation; - unsigned int mFormat3D; - bool mUIChannel; -#ifdef USES_POST_PROCESSING - struct display_pp_conv_cfg hsic_cfg; -#endif - mdp_overlay mOVInfo; - msm_rotator_img_info mRotInfo; - msmfb_overlay_3d m3DOVInfo; - bool mIsChannelUpdated; - bool openDevices(int fbnum = -1); - bool setOverlayInformation(const overlay_buffer_info& info, - int zorder = 0, int flags = 0, - int requestType = NEW_REQUEST); - bool startOVRotatorSessions(const overlay_buffer_info& info, int requestType); - void swapOVRotWidthHeight(); - int commitVisualParam(int8_t paramType, float paramValue); - void setInformationFromFlags(int flags, mdp_overlay& ov); - -public: - OverlayControlChannel(); - ~OverlayControlChannel(); - bool startControlChannel(const overlay_buffer_info& info, - int fbnum, bool norot = false, - bool uichannel = false, - unsigned int format3D = 0, int zorder = 0, - int flags = 0); - bool closeControlChannel(); - bool setPosition(int x, int y, uint32_t w, uint32_t h); - bool setTransform(int value, bool fetch = true); - void setSize (int size) { mSize = size; } - bool getPosition(int& x, int& y, uint32_t& w, uint32_t& h); - bool getOvSessionID(int& sessionID) const; - bool getRotSessionID(int& sessionID) const; - bool getSize(int& size) const; - bool isChannelUP() const { return (mFD > 0); } - int getFBWidth() const { return mFBWidth; } - int getFBHeight() const { return mFBHeight; } - int getFormat3D() const { return mFormat3D; } - bool getOrientation(int& orientation) const; - bool updateOverlayFlags(int flags); - bool getAspectRatioPosition(int w, int h, overlay_rect *rect); - // Calculates the aspect ratio for video on HDMI based on primary - // aspect ratio used in case of true mirroring - bool getAspectRatioPosition(int w, int h, int orientation, - overlay_rect *inRect, overlay_rect *outRect); - bool getPositionS3D(int channel, int format, overlay_rect *rect); - bool updateOverlaySource(const overlay_buffer_info& info, int orientation, int flags); - bool getFormat() const { return mFormat; } - bool setVisualParam(int8_t paramType, float paramValue); - bool useVirtualFB (); - bool doFlagsNeedUpdate(int flags); -}; - -class OverlayDataChannel { - - bool mNoRot; - bool mSecure; - int mFD; - int mRotFD; - int mPmemFD; - void* mPmemAddr; - uint32_t mPmemOffset; - uint32_t mNewPmemOffset; - msmfb_overlay_data mOvData; - msmfb_overlay_data mOvDataRot; - msm_rotator_data_info mRotData; - int mRotOffset[max_num_buffers]; - int mCurrentItem; - int mNumBuffers; - bool mUpdateDataChannel; - android::sp mAlloc; - int mBufferType; - - bool openDevices(int fbnum = -1, bool uichannel = false, int num_buffers = 2); - bool mapRotatorMemory(int num_buffers, bool uiChannel, int requestType); - bool queue(uint32_t offset); - -public: - OverlayDataChannel(); - ~OverlayDataChannel(); - bool startDataChannel(const OverlayControlChannel& objOvCtrlChannel, - int fbnum, bool norot = false, bool secure = false, - bool uichannel = false, int num_buffers = 2); - bool startDataChannel(int ovid, int rotid, int size, - int fbnum, bool norot = false, bool uichannel = false, - int num_buffers = 2); - bool closeDataChannel(); - bool setFd(int fd); - bool queueBuffer(uint32_t offset); - bool waitForHdmiVsync(); - bool setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h); - bool getCropS3D(overlay_rect *inRect, int channel, int format, overlay_rect *rect); - bool isChannelUP() const { return (mFD > 0); } - bool updateDataChannel(int size); -}; - -/* - * Overlay class for single thread application - * A multiple thread/process application need to use Overlay HAL - */ -class Overlay { - - bool mChannelUP; - //stores the connected external display Ex: HDMI(1) WFD(2) - int mExternalDisplay; - unsigned int mS3DFormat; - //Actual cropped source width and height of overlay - int mCroppedSrcWidth; - int mCroppedSrcHeight; - overlay_buffer_info mOVBufferInfo; - int mState; - // Stores the current device orientation - int mDevOrientation; - OverlayControlChannel objOvCtrlChannel[2]; - OverlayDataChannel objOvDataChannel[2]; - -public: - Overlay(); - ~Overlay(); - - static bool sHDMIAsPrimary; - bool startChannel(const overlay_buffer_info& info, int fbnum, bool norot = false, - bool uichannel = false, unsigned int format3D = 0, - int channel = 0, int flags = 0, - int num_buffers = 2); - bool closeChannel(); - bool setDeviceOrientation(int orientation); - bool setPosition(int x, int y, uint32_t w, uint32_t h); - bool setTransform(int value); - bool setOrientation(int value, int channel = 0); - bool setFd(int fd, int channel = 0); - bool queueBuffer(uint32_t offset, int channel = 0); - bool getPosition(int& x, int& y, uint32_t& w, uint32_t& h, int channel = 0); - bool isChannelUP() const { return mChannelUP; } - int getFBWidth(int channel = 0) const; - int getFBHeight(int channel = 0) const; - bool getOrientation(int& orientation, int channel = 0) const; - bool queueBuffer(buffer_handle_t buffer); - bool setSource(const overlay_buffer_info& info, int orientation, int hdmiConnected, - int flags, int numBuffers = 2); - bool getAspectRatioPosition(int w, int h, overlay_rect *rect, int channel = 0); - bool setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h); - bool updateOverlayFlags(int flags); - void setVisualParam(int8_t paramType, float paramValue); - bool waitForHdmiVsync(int channel); - int getChannelStatus() const { return (mChannelUP ? OVERLAY_CHANNEL_UP: OVERLAY_CHANNEL_DOWN); } - void closeExternalChannel(); -private: - bool setChannelPosition(int x, int y, uint32_t w, uint32_t h, int channel = 0); - bool setChannelCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h, int channel); - bool queueBuffer(int fd, uint32_t offset, int channel); - bool updateOverlaySource(const overlay_buffer_info& info, int orientation, int flags); - int getS3DFormat(int format); -}; - -struct overlay_shared_data { - volatile bool isControlSetup; - unsigned int state; - int rotid[2]; - int ovid[2]; -}; -}; -#endif diff --git a/liboverlay/overlayLibUI.cpp b/liboverlay/overlayLibUI.cpp deleted file mode 100755 index d3fd80a..0000000 --- a/liboverlay/overlayLibUI.cpp +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. - * - * 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. - */ - -#include "overlayLibUI.h" -#include "gralloc_priv.h" -#define LOG_TAG "OverlayUI" - -using android::sp; -using gralloc::IMemAlloc; -using gralloc::alloc_data; - -namespace { -/* helper functions */ -void swapOVRotWidthHeight(msm_rotator_img_info& rotInfo, - mdp_overlay& ovInfo) { - int srcWidth = ovInfo.src.width; - ovInfo.src.width = ovInfo.src.height; - ovInfo.src.height = srcWidth; - - int srcRectWidth = ovInfo.src_rect.w; - ovInfo.src_rect.w = ovInfo.src_rect.h; - ovInfo.src_rect.h = srcRectWidth; - - int dstWidth = rotInfo.dst.width; - rotInfo.dst.width = rotInfo.dst.height; - rotInfo.dst.height = dstWidth; -} - -bool isRGBType(int format) { - bool ret = false; - switch(format) { - case MDP_RGBA_8888: - case MDP_BGRA_8888: - case MDP_RGBX_8888: - case MDP_RGB_565: - ret = true; - break; - default: - ret = false; - break; - } - return ret; -} - -int getRGBBpp(int format) { - int ret = -1; - switch(format) { - case MDP_RGBA_8888: - case MDP_BGRA_8888: - case MDP_RGBX_8888: - ret = 4; - break; - case MDP_RGB_565: - ret = 2; - break; - default: - ret = -1; - break; - } - - return ret; -} - -bool turnOFFVSync() { - static int swapIntervalPropVal = -1; - if (swapIntervalPropVal == -1) { - char pval[PROPERTY_VALUE_MAX]; - property_get("debug.gr.swapinterval", pval, "1"); - swapIntervalPropVal = atoi(pval); - } - return (swapIntervalPropVal == 0); -} - -}; - -namespace overlay { - -status_t Display::openDisplay(int fbnum) { - if (mFD != NO_INIT) - return NO_ERROR; - - status_t ret = NO_INIT; - char dev_name[64]; - snprintf(dev_name, 64, FB_DEVICE_TEMPLATE, fbnum); - - mFD = open(dev_name, O_RDWR, 0); - if (mFD < 0) { - LOGE("Failed to open FB %d", fbnum); - return ret; - } - - fb_var_screeninfo vinfo; - if (ioctl(mFD, FBIOGET_VSCREENINFO, &vinfo)) { - LOGE("FBIOGET_VSCREENINFO on failed on FB %d", fbnum); - close(mFD); - mFD = NO_INIT; - return ret; - } - - mFBWidth = vinfo.xres; - mFBHeight = vinfo.yres; - mFBBpp = vinfo.bits_per_pixel; - ret = NO_ERROR; - - return ret; -} - -void Display::closeDisplay() { - close(mFD); - mFD = NO_INIT; -} - -Rotator::Rotator() : mFD(NO_INIT), mSessionID(NO_INIT), mPmemFD(NO_INIT) -{ - mAlloc = gralloc::IAllocController::getInstance(false); -} - -Rotator::~Rotator() -{ - closeRotSession(); -} - -status_t Rotator::startRotSession(msm_rotator_img_info& rotInfo, - int size, int numBuffers) { - status_t ret = NO_ERROR; - if (mSessionID == NO_INIT && mFD == NO_INIT) { - mNumBuffers = numBuffers; - mFD = open("/dev/msm_rotator", O_RDWR, 0); - if (mFD < 0) { - LOGE("Couldnt open rotator device"); - return NO_INIT; - } - - if (ioctl(mFD, MSM_ROTATOR_IOCTL_START, &rotInfo)) { - close(mFD); - mFD = NO_INIT; - return NO_INIT; - } - - mSessionID = rotInfo.session_id; - alloc_data data; - data.base = 0; - data.fd = -1; - data.offset = 0; - data.size = mSize * mNumBuffers; - data.align = getpagesize(); - data.uncached = true; - - int allocFlags = GRALLOC_USAGE_PRIVATE_MM_HEAP | - GRALLOC_USAGE_PRIVATE_WRITEBACK_HEAP | - GRALLOC_USAGE_PRIVATE_ADSP_HEAP | - GRALLOC_USAGE_PRIVATE_IOMMU_HEAP | - GRALLOC_USAGE_PRIVATE_SMI_HEAP | - GRALLOC_USAGE_PRIVATE_DO_NOT_MAP; - - int err = mAlloc->allocate(data, allocFlags, 0); - - if(err) { - LOGE("%s: Can't allocate rotator memory", __func__); - closeRotSession(); - return NO_INIT; - } - mPmemFD = data.fd; - mPmemAddr = data.base; - mBufferType = data.allocType; - - mCurrentItem = 0; - for (int i = 0; i < mNumBuffers; i++) - mRotOffset[i] = i * mSize; - ret = NO_ERROR; - } - return ret; -} - -status_t Rotator::closeRotSession() { - if (mSessionID != NO_INIT && mFD != NO_INIT) { - ioctl(mFD, MSM_ROTATOR_IOCTL_FINISH, &mSessionID); - close(mFD); - if (NO_INIT != mPmemFD) { - sp memalloc = mAlloc->getAllocator(mBufferType); - memalloc->free_buffer(mPmemAddr, mSize * mNumBuffers, 0, mPmemFD); - close(mPmemFD); - } - } - - mFD = NO_INIT; - mSessionID = NO_INIT; - mPmemFD = NO_INIT; - mPmemAddr = MAP_FAILED; - - return NO_ERROR; -} - -status_t Rotator::rotateBuffer(msm_rotator_data_info& rotData) { - status_t ret = NO_INIT; - if (mSessionID != NO_INIT) { - rotData.dst.memory_id = mPmemFD; - rotData.dst.offset = mRotOffset[mCurrentItem]; - rotData.session_id = mSessionID; - mCurrentItem = (mCurrentItem + 1) % mNumBuffers; - if (ioctl(mFD, MSM_ROTATOR_IOCTL_ROTATE, &rotData)) { - LOGE("Rotator failed to rotate"); - return BAD_VALUE; - } - return NO_ERROR; - } - - return ret; -} - -//===================== OverlayUI =================// - -OverlayUI::OverlayUI() : mChannelState(CLOSED), mOrientation(NO_INIT), - mFBNum(NO_INIT), mZorder(NO_INIT), mWaitForVsync(false), mIsFg(false), - mSessionID(NO_INIT), mParamsChanged(false) { - memset(&mOvInfo, 0, sizeof(mOvInfo)); - memset(&mRotInfo, 0, sizeof(mRotInfo)); -} - -OverlayUI::~OverlayUI() { - closeChannel(); -} - -void OverlayUI::setSource(const overlay_buffer_info& info, int orientation) { - status_t ret = NO_INIT; - int format3D = FORMAT_3D(info.format); - int colorFormat = COLOR_FORMAT(info.format); - int format = get_mdp_format(colorFormat); - - if (format3D || !isRGBType(format)) { - LOGE("%s: Unsupported format", __func__); - return; - } - - mParamsChanged |= (mSource.width ^ info.width) || - (mSource.height ^ info.height) || - (mSource.format ^ format) || - (mSource.size ^ info.size) || - (mOrientation ^ orientation); - - mSource.width = info.width; - mSource.height = info.height; - mSource.format = format; - mSource.size = info.size; - mOrientation = orientation; - setupOvRotInfo(); -} - -void OverlayUI::setDisplayParams(int fbNum, bool waitForVsync, bool isFg, int - zorder, bool isVGPipe) { - int flags = 0; - - if(false == waitForVsync) - flags |= MDP_OV_PLAY_NOWAIT; - else - flags &= ~MDP_OV_PLAY_NOWAIT; - - if(isVGPipe) - flags |= MDP_OV_PIPE_SHARE; - else - flags &= ~MDP_OV_PIPE_SHARE; - - if (turnOFFVSync()) - flags |= MDP_OV_PLAY_NOWAIT; - - mParamsChanged |= (mFBNum ^ fbNum) || - (mOvInfo.is_fg ^ isFg) || - (mOvInfo.flags ^ flags) || - (mOvInfo.z_order ^ zorder); - - mFBNum = fbNum; - mOvInfo.is_fg = isFg; - mOvInfo.flags = flags; - mOvInfo.z_order = zorder; - - mobjDisplay.openDisplay(mFBNum); -} - -void OverlayUI::setPosition(int x, int y, int w, int h) { - mParamsChanged |= (mOvInfo.dst_rect.x ^ x) || - (mOvInfo.dst_rect.y ^ y) || - (mOvInfo.dst_rect.w ^ w) || - (mOvInfo.dst_rect.h ^ h); - - mOvInfo.dst_rect.x = x; - mOvInfo.dst_rect.y = y; - mOvInfo.dst_rect.w = w; - mOvInfo.dst_rect.h = h; -} - -void OverlayUI::setCrop(int x, int y, int w, int h) { - mParamsChanged |= (mOvInfo.src_rect.x ^ x) || - (mOvInfo.src_rect.y ^ y) || - (mOvInfo.src_rect.w ^ w) || - (mOvInfo.src_rect.h ^ h); - - mOvInfo.src_rect.x = x; - mOvInfo.src_rect.y = y; - mOvInfo.src_rect.w = w; - mOvInfo.src_rect.h = h; -} - -void OverlayUI::setupOvRotInfo() { - int w = mSource.width; - int h = mSource.height; - int format = mSource.format; - int srcw = (w + 31) & ~31; - int srch = (h + 31) & ~31; - mOvInfo.src.width = srcw; - mOvInfo.src.height = srch; - mOvInfo.src.format = format; - mOvInfo.src_rect.w = w; - mOvInfo.src_rect.h = h; - mOvInfo.alpha = 0xff; - mOvInfo.transp_mask = 0xffffffff; - mRotInfo.src.format = format; - mRotInfo.dst.format = format; - mRotInfo.src.width = srcw; - mRotInfo.src.height = srch; - mRotInfo.src_rect.w = srcw; - mRotInfo.src_rect.h = srch; - mRotInfo.dst.width = srcw; - mRotInfo.dst.height = srch; - - int rot = mOrientation; - switch(rot) { - case 0: - case HAL_TRANSFORM_FLIP_H: - case HAL_TRANSFORM_FLIP_V: - rot = 0; - break; - case HAL_TRANSFORM_ROT_90: - case (HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_H): - case (HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_V): { - int tmp = mOvInfo.src_rect.x; - mOvInfo.src_rect.x = mOvInfo.src.height - - (mOvInfo.src_rect.y + mOvInfo.src_rect.h); - mOvInfo.src_rect.y = tmp; - swapOVRotWidthHeight(mRotInfo, mOvInfo); - rot = HAL_TRANSFORM_ROT_90; - break; - } - case HAL_TRANSFORM_ROT_180: - break; - case HAL_TRANSFORM_ROT_270: { - int tmp = mOvInfo.src_rect.y; - mOvInfo.src_rect.y = mOvInfo.src.width - - (mOvInfo.src_rect.x + mOvInfo.src_rect.w); - mOvInfo.src_rect.x = tmp; - swapOVRotWidthHeight(mRotInfo, mOvInfo); - break; - } - default: - break; - } - int mdp_rotation = overlay::get_mdp_orientation(rot); - if (mdp_rotation < 0) - mdp_rotation = 0; - mOvInfo.user_data[0] = mdp_rotation; - mRotInfo.rotations = mOvInfo.user_data[0]; - if (mdp_rotation) - mRotInfo.enable = 1; -} - -status_t OverlayUI::commit() { - status_t ret = BAD_VALUE; - if(mChannelState != UP) - mOvInfo.id = MSMFB_NEW_REQUEST; - ret = startOVSession(); - if (ret == NO_ERROR && mOrientation) { - ret = mobjRotator.startRotSession(mRotInfo, mSource.size); - } - if (ret == NO_ERROR) { - mChannelState = UP; - } else { - LOGE("start channel failed."); - } - return ret; -} - -status_t OverlayUI::closeChannel() { - if( mChannelState != UP ) { - return NO_ERROR; - } - if(NO_ERROR != closeOVSession()) { - LOGE("%s: closeOVSession() failed.", __FUNCTION__); - return BAD_VALUE; - } - if(NO_ERROR != mobjRotator.closeRotSession()) { - LOGE("%s: closeRotSession() failed.", __FUNCTION__); - return BAD_VALUE; - } - mChannelState = CLOSED; - mParamsChanged = false; - memset(&mOvInfo, 0, sizeof(mOvInfo)); - memset(&mRotInfo, 0, sizeof(mRotInfo)); - return NO_ERROR; -} - -status_t OverlayUI::startOVSession() { - status_t ret = NO_INIT; - ret = mobjDisplay.openDisplay(mFBNum); - - if (ret != NO_ERROR) - return ret; - - if(mParamsChanged) { - mParamsChanged = false; - mdp_overlay ovInfo = mOvInfo; - if (ioctl(mobjDisplay.getFD(), MSMFB_OVERLAY_SET, &ovInfo)) { - LOGE("Overlay set failed.."); - ret = BAD_VALUE; - } else { - mSessionID = ovInfo.id; - mOvInfo = ovInfo; - ret = NO_ERROR; - } - } - return ret; -} - -status_t OverlayUI::closeOVSession() { - status_t ret = NO_ERROR; - int err = 0; - if(err = ioctl(mobjDisplay.getFD(), MSMFB_OVERLAY_UNSET, &mSessionID)) { - LOGE("%s: MSMFB_OVERLAY_UNSET failed. (%d)", __FUNCTION__, err); - ret = BAD_VALUE; - } else { - mobjDisplay.closeDisplay(); - mSessionID = NO_INIT; - } - return ret; -} - -status_t OverlayUI::queueBuffer(buffer_handle_t buffer) { - status_t ret = NO_INIT; - - if (mChannelState != UP) - return ret; - - msmfb_overlay_data ovData; - memset(&ovData, 0, sizeof(ovData)); - - private_handle_t const* hnd = reinterpret_cast - (buffer); - ovData.data.memory_id = hnd->fd; - ovData.data.offset = hnd->offset; - if (mOrientation) { - msm_rotator_data_info rotData; - memset(&rotData, 0, sizeof(rotData)); - rotData.src.memory_id = hnd->fd; - rotData.src.offset = hnd->offset; - if (mobjRotator.rotateBuffer(rotData) != NO_ERROR) { - LOGE("Rotator failed.. "); - return BAD_VALUE; - } - ovData.data.memory_id = rotData.dst.memory_id; - ovData.data.offset = rotData.dst.offset; - } - ovData.id = mSessionID; - if (ioctl(mobjDisplay.getFD(), MSMFB_OVERLAY_PLAY, &ovData)) { - LOGE("Queuebuffer failed "); - return BAD_VALUE; - } - return NO_ERROR; -} - -}; diff --git a/liboverlay/overlayLibUI.h b/liboverlay/overlayLibUI.h deleted file mode 100644 index d16a968..0000000 --- a/liboverlay/overlayLibUI.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. - * - * 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. - */ - -#ifndef INCLUDE_OVERLAY_LIB_UI -#define INCLUDE_OVERLAY_LIB_UI - -#include - -#include "overlayLib.h" - -namespace overlay { - -enum channel_state_t { UP, CLOSED, PENDING_CLOSE }; -enum status_t { - NO_ERROR, - INVALID_OPERATION = -ENOSYS, - BAD_VALUE = -EINVAL, - NO_INIT = -ENODEV, - ALREADY_EXISTS = -EEXIST - }; - -/* - * Display class provides following services - * Open FB - * FB information (Width, Height and Bpp) - */ - -class Display { - int mFD; - int mFBWidth; - int mFBHeight; - int mFBBpp; - Display(const Display& objDisplay); - Display& operator=(const Display& objDisplay); - -public: - explicit Display() : mFD(NO_INIT) { }; - ~Display() { close(mFD); }; - int getFD() const { return mFD; }; - int getFBWidth() const { return mFBWidth; }; - int getFBHeight() const { return mFBHeight; }; - int getFBBpp() const { return mFBBpp; }; - status_t openDisplay(int fbnum); - void closeDisplay(); -}; - -/* - * Rotator class, manages rotation of the buffers - * It communicates with Rotator driver, provides following services - * Start rotator session - * Rotate buffer - */ - -class Rotator { - int mFD; - int mSessionID; - int mPmemFD; - void* mPmemAddr; - int mRotOffset[max_num_buffers]; - int mCurrentItem; - int mNumBuffers; - int mSize; - android::sp mAlloc; - int mBufferType; - Rotator(const Rotator& objROtator); - Rotator& operator=(const Rotator& objRotator); - -public: - explicit Rotator(); - ~Rotator(); - status_t startRotSession(msm_rotator_img_info& rotInfo, int size, - int numBuffers = max_num_buffers); - status_t closeRotSession(); - status_t rotateBuffer(msm_rotator_data_info& rotData); -}; - -/* - * Overlay class for Comp. Bypass - * We merge control and data channel classes. - */ - -class OverlayUI { - channel_state_t mChannelState; - overlay_buffer_info mSource; - int mZorder; - int mOrientation; - int mFBNum; - bool mWaitForVsync; - bool mIsFg; - int mSessionID; - Display mobjDisplay; - Rotator mobjRotator; - - mdp_overlay mOvInfo; - msm_rotator_img_info mRotInfo; - - bool mParamsChanged; - - OverlayUI(const OverlayUI& objOverlay); - OverlayUI& operator=(const OverlayUI& objOverlay); - - status_t startOVSession(); - status_t closeOVSession(); - void setupOvRotInfo(); - -public: - - enum fbnum_t { FB0, FB1 }; - - OverlayUI(); - ~OverlayUI(); - void setSource(const overlay_buffer_info& info, int orientation); - void setPosition(int x, int y, int w, int h); - void setCrop(int x, int y, int w, int h); - void setDisplayParams(int fbNum, bool waitForVsync, bool isFg, int zorder, - bool isVGPipe); - status_t commit(); - status_t closeChannel(); - channel_state_t isChannelUP() const { return mChannelState; }; - int getFBWidth() const { return mobjDisplay.getFBWidth(); }; - int getFBHeight() const { return mobjDisplay.getFBHeight(); }; - status_t queueBuffer(buffer_handle_t buffer); -}; - -}; -#endif diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp new file mode 100644 index 0000000..09499c0 --- /dev/null +++ b/liboverlay/overlayMdp.cpp @@ -0,0 +1,289 @@ +/* +* Copyright (C) 2008 The Android Open Source Project +* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. +* +* 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. +*/ + +#include "overlayUtils.h" +#include "overlayMdp.h" + +#undef ALOG_TAG +#define ALOG_TAG "overlay" + +namespace ovutils = overlay::utils; +namespace overlay { +bool MdpCtrl::open(uint32_t fbnum) { + // FD open + if(!utils::openDev(mFd, fbnum, + Res::devTemplate, O_RDWR)){ + ALOGE("Ctrl failed to open fbnum=%d", fbnum); + return false; + } + return true; +} + +void MdpCtrl::reset() { + utils::memset0(mOVInfo); + utils::memset0(mLkgo); + mOVInfo.id = -1; + mLkgo.id = -1; +} + +bool MdpCtrl::close() { + if(-1 == static_cast(mOVInfo.id)) return true; + if(!mdp_wrapper::unsetOverlay(mFd.getFD(), mOVInfo.id)) { + ALOGE("MdpCtrl close error in unset"); + return false; + } + reset(); + if(!mFd.close()) { + return false; + } + return true; +} + +bool MdpCtrl::getScreenInfo(overlay::utils::ScreenInfo& info) { + fb_fix_screeninfo finfo; + if (!mdp_wrapper::getFScreenInfo(mFd.getFD(), finfo)) { + return false; + } + + fb_var_screeninfo vinfo; + if (!mdp_wrapper::getVScreenInfo(mFd.getFD(), vinfo)) { + return false; + } + info.mFBWidth = vinfo.xres; + info.mFBHeight = vinfo.yres; + info.mFBbpp = vinfo.bits_per_pixel; + info.mFBystride = finfo.line_length; + return true; +} + +bool MdpCtrl::get() { + mdp_overlay ov; + ov.id = mOVInfo.id; + if (!mdp_wrapper::getOverlay(mFd.getFD(), ov)) { + ALOGE("MdpCtrl get failed"); + return false; + } + mOVInfo = ov; + return true; +} + +// that is the second part of original setParameter function +void MdpCtrl::setSrcFormat(const utils::Whf& whf) { + + //By default mdp src format is the same as buffer's + mOVInfo.src.format = whf.format; + + //If rotation is used and input formats are tiled then output of rotator is + //non-tiled. + // FIXME mRotInfo.enable = 1; for enable + if (getUserData()) { // if rotations enabled in MdpCtrl + if (whf.format == MDP_Y_CRCB_H2V2_TILE) + mOVInfo.src.format = MDP_Y_CRCB_H2V2; + else if (whf.format == MDP_Y_CBCR_H2V2_TILE) + mOVInfo.src.format = MDP_Y_CBCR_H2V2; + return; + } + +} + +bool MdpCtrl::set() { + if(!this->ovChanged()) { + return true; // nothing todo here. + } + + if(!mdp_wrapper::setOverlay(mFd.getFD(), mOVInfo)) { + ALOGE("MdpCtrl failed to setOverlay, restoring last known " + "good ov info"); + mdp_wrapper::dump("== Bad OVInfo is: ", mOVInfo); + mdp_wrapper::dump("== Last good known OVInfo is: ", mLkgo); + this->restore(); + // FIXME, do we need to set the old one? + return false; + } + this->save(); + return true; +} + +bool MdpCtrl::setPosition(const overlay::utils::Dim& d, + int fbw, int fbh) +{ + // Validatee against FB size + if(!d.check(fbw, fbh)) { + ALOGE("MdpCtrl setPosition failed dest dim violate screen limits"); + return false; + } + + ovutils::Dim dim(d); + ovutils::Dim ovsrcdim = getSrcRectDim(); + // Scaling of upto a max of 8 times supported + if(dim.w >(ovsrcdim.w * ovutils::HW_OV_MAGNIFICATION_LIMIT)){ + dim.w = ovutils::HW_OV_MAGNIFICATION_LIMIT * ovsrcdim.w; + dim.x = (fbw - dim.w) / 2; + } + if(dim.h >(ovsrcdim.h * ovutils::HW_OV_MAGNIFICATION_LIMIT)) { + dim.h = ovutils::HW_OV_MAGNIFICATION_LIMIT * ovsrcdim.h; + dim.y = (fbh - dim.h) / 2; + } + + //dim.even_out(); + setDstRectDim(dim); + return true; +} + +void MdpCtrl::updateSource(RotatorBase* r, + const utils::PipeArgs& args, + const utils::ScreenInfo& info) { + utils::Whf whf(args.whf); + mOVInfo.src.width = whf.w; + mOVInfo.src.height = whf.h; + mOVInfo.src_rect.x = 0; + mOVInfo.src_rect.y = 0; + mOVInfo.dst_rect.x = 0; + mOVInfo.dst_rect.y = 0; + mOVInfo.dst_rect.w = whf.w; + mOVInfo.dst_rect.h = whf.h; + mOVInfo.src.format = whf.format; + + if(whf.format == MDP_Y_CRCB_H2V2_TILE || + (whf.format == MDP_Y_CBCR_H2V2_TILE)) { + // passing by value, setInfo fills it and return by val + mOVInfo = r->setInfo(args, mOVInfo); + } else { + mOVInfo.src_rect.w = whf.w; + mOVInfo.src_rect.h = whf.h; + } + + if (whf.w > info.mFBWidth) + mOVInfo.dst_rect.w = info.mFBWidth; + if (whf.h > info.mFBHeight) + mOVInfo.dst_rect.h = info.mFBHeight; + mSize = whf.size; +} + + +bool MdpCtrl::setInfo(RotatorBase* r, + const utils::PipeArgs& args, + const utils::ScreenInfo& info) +{ + // new request + utils::Whf whf(args.whf); + mOVInfo.id = MSMFB_NEW_REQUEST; + + updateSource(r, args, info); + + setUserData(0); + mOVInfo.alpha = 0xff; + mOVInfo.transp_mask = 0xffffffff; + setZ(args.zorder); + setFlags(args.mdpFlags); + setWait(args.wait); + setIsFg(args.isFg); + mSize = whf.size; + return true; +} + +bool MdpCtrl::setCrop(const utils::Dim& cdim) { + utils::Dim d(cdim); + const utils::Whf ovwhf = getSrcWhf(); + int udata = getUserData(); + switch(udata) { + case MDP_ROT_NOP: + break; // nothing to do here + case MDP_ROT_90: + case MDP_ROT_90 | MDP_FLIP_UD: + case MDP_ROT_90 | MDP_FLIP_LR: + { + if (ovwhf.w < (d.y + d.h)) { + ALOGE("MdpCtrl setCrop failed ROT 90 udata=%d", + udata); + d.dump(); + this->dump(); + return false; + } + uint32_t tmp = d.x; + d.x = ovwhf.w - (d.y + d.h); + d.y = tmp; + utils::swap(d.w, d.h); + }break; + case MDP_ROT_270: + { + if (ovwhf.h < (d.x + d.w)) { + ALOGE("MdpCtrl setCrop failed ROT 270 udata=%d", + udata); + d.dump(); + this->dump(); + return false; + } + uint32_t tmp = d.y; + d.y = ovwhf.h - (d.x + d.w); + d.x = tmp; + utils::swap(d.w, d.h); + }break; + case MDP_ROT_180: + { + if ((ovwhf.h < (d.y + d.h)) || + (ovwhf.w < ( d.x + d.w))) { + ALOGE("MdpCtrl setCrop failed ROT 180 udata=%d", + udata); + d.dump(); + this->dump(); + return false; + } + d.x = ovwhf.w - (d.x + d.w); + d.y = ovwhf.h - (d.y + d.h); + }break; + default: + if(!(udata & (MDP_FLIP_UD | MDP_FLIP_LR))) { + ALOGE("MdpCtrl setCrop unknown rot %d", udata); + return false; + } + } + + if(getSrcRectDim() == d) { + return true; // Nothing to do here + } + + utils::normalizeCrop(d.x, d.w); + utils::normalizeCrop(d.y, d.h); + + setSrcRectDim(d); + + return true; +} + +void MdpCtrl::dump() const { + ALOGE("== Dump MdpCtrl start =="); + ALOGE("size=%d", mSize); + mFd.dump(); + mdp_wrapper::dump("mOVInfo", mOVInfo); + ALOGE("== Dump MdpCtrl end =="); +} + +void MdpData::dump() const { + ALOGE("== Dump MdpData start =="); + mFd.dump(); + mdp_wrapper::dump("mOvData", mOvData); + ALOGE("== Dump MdpData end =="); +} + +void MdpCtrl3D::dump() const { + ALOGE("== Dump MdpCtrl start =="); + mFd.dump(); + ALOGE("== Dump MdpCtrl end =="); +} + +} // overlay diff --git a/liboverlay/overlayMdp.h b/liboverlay/overlayMdp.h new file mode 100644 index 0000000..29f8fd5 --- /dev/null +++ b/liboverlay/overlayMdp.h @@ -0,0 +1,489 @@ +/* +* Copyright (C) 2008 The Android Open Source Project +* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. +* +* 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. +*/ + +#ifndef OVERLAY_MDP_H +#define OVERLAY_MDP_H + +#include + +#include "overlayUtils.h" +#include "mdpWrapper.h" +#include "overlayRotator.h" + +namespace overlay{ + +class RotatorBase; + +/* +* Mdp Ctrl holds corresponding fd and MDP related struct. +* It is simple wrapper to MDP services +* */ +class MdpCtrl { +public: + /* ctor reset */ + explicit MdpCtrl(); + + /* dtor close */ + ~MdpCtrl(); + + /* Open underlying device using fbnum */ + bool open(uint32_t fbnum); + + /* unset overlay, reset and close fd */ + bool close(); + + /* reset and set ov id to -1*/ + void reset(); + + /* get orient / user_data[0] */ + int getOrient() const; + + /* returns session id */ + int getId() const; + + /* returns the fd associated to ctrl*/ + int getFd() const; + + /* Get screen info. out: info*/ + bool getScreenInfo(utils::ScreenInfo& info); + + /* overlay get */ + bool get(); + + /* returns flags from mdp structure. + * Flags are WAIT/NOWAIT/PIPE SHARED*/ + int getFlags() const; + + /* set flags to mdp structure */ + void setFlags(int f); + + /* code taken from OverlayControlChannel::setOverlayInformation */ + bool setInfo(RotatorBase* r, + const utils::PipeArgs& args, + const utils::ScreenInfo& info); + + /* given whf, update src */ + void updateSource(RotatorBase* r, + const utils::PipeArgs& args, + const utils::ScreenInfo& info); + + /* set z order */ + void setZ(utils::eZorder z); + + /* set Wait/nowait */ + void setWait(utils::eWait wait); + + /* set isFg flag */ + void setIsFg(utils::eIsFg isFg); + + /* calls overlay set + * Set would always consult last good known ov instance. + * Only if it is different, set would actually exectue ioctl. + * On a sucess ioctl. last good known ov instance is updated */ + bool set(); + + /* return a copy of src whf*/ + utils::Whf getSrcWhf() const; + + /* set src whf */ + void setSrcWhf(const utils::Whf& whf); + + /* set source format based on rot info */ + void setSrcFormat(const utils::Whf& whf); + + /* swap src w/h*/ + void swapSrcWH(); + + /* swap src rect w/h */ + void swapSrcRectWH(); + + /* returns a copy to src rect dim */ + utils::Dim getSrcRectDim() const; + + /* set src/dst rect dim */ + void setSrcRectDim(const utils::Dim d); + void setDstRectDim(const utils::Dim d); + + /* returns a copy ro dst rect dim */ + utils::Dim getDstRectDim() const; + + /* returns user_data[0]*/ + int getUserData() const; + + /* sets user_data[0] */ + void setUserData(int v); + + /* return true if current overlay is different + * than lask known good overlay */ + bool ovChanged() const; + + /* save mOVInfo to be last known good ov*/ + void save(); + + /* restore last known good ov to be the current */ + void restore(); + + /* + * Sets ROI, the unpadded region, for source buffer. + * Should be called before a setPosition, for small clips. + * Dim - ROI dimensions. + */ + bool setCrop(const utils::Dim& d); + + /* given a dim and w/h, set overlay dim */ + bool setPosition(const utils::Dim& dim, int w, int h); + + /* using user_data, sets/unsets roationvalue in mdp flags */ + void setRotationFlags(); + + /* dump state of the object */ + void dump() const; +private: + + /* last good known ov info */ + mdp_overlay mLkgo; + + /* Actual overlay mdp structure */ + mdp_overlay mOVInfo; + + /* FD for the mdp fbnum */ + OvFD mFd; + + /* cached size FIXME do we need it? */ + uint32_t mSize; +}; + + +/* MDP 3D related ctrl */ +class MdpCtrl3D { +public: + /* ctor reset data */ + MdpCtrl3D(); + /* calls MSMFB_OVERLAY_3D */ + bool close(); + /* set w/h. format is ignored*/ + void setWh(const utils::Whf& whf); + /* set is_3d calls MSMFB_OVERLAY_3D */ + bool useVirtualFB(); + /* set fd to be used in ioctl */ + void setFd(int fd); + /* dump */ + void dump() const; +private: + /* reset */ + void reset(); + /* actual MSM 3D info */ + msmfb_overlay_3d m3DOVInfo; + /* FD for the mdp 3D */ + OvFD mFd; +}; + +/* MDP data */ +class MdpData { +public: + /* ctor reset data */ + explicit MdpData(); + + /* dtor close*/ + ~MdpData(); + + /* open FD */ + bool open(uint32_t fbnum); + + /* memset0 the underlying mdp object */ + void reset(); + + /* close fd, and reset */ + bool close(); + + /* Set FD / memid */ + void setMemoryId(int id); + + /* set id of mdp data */ + void setId(int id); + + /* return ses id of data */ + int getId() const; + + /* get underlying fd*/ + int getFd() const; + + /* get memory_id */ + int getMemoryId() const; + + /* set offset in underlying mdp obj */ + void setOffset(uint32_t o); + + /* calls wrapper play */ + bool play(); + + /* calls wrapper playWait */ + bool playWait(); + + /* dump state of the object */ + void dump() const; +private: + + /* actual overlay mdp data */ + msmfb_overlay_data mOvData; + + /* fd to mdp fbnum */ + OvFD mFd; +}; + +//--------------Inlines--------------------------------- +namespace utils { + inline bool openDev(OvFD& fd, int fb, + const char* const s, + int flags) { + return overlay::open(fd, fb, Res::devTemplate, O_RDWR); + } +} + +template + inline void init(T& t) { + memset(&t, 0, sizeof(T)); + } + +///// MdpCtrl ////// + +inline MdpCtrl::MdpCtrl() : mSize(0) { + reset(); +} + +inline MdpCtrl::~MdpCtrl() { + close(); +} + +inline int MdpCtrl::getOrient() const { + return getUserData(); +} + +inline int MdpCtrl::getId() const { + return mOVInfo.id; +} + +inline int MdpCtrl::getFd() const { + return mFd.getFD(); +} + +inline int MdpCtrl::getFlags() const { + return mOVInfo.flags; +} + +inline void MdpCtrl::setFlags(int f) { + mOVInfo.flags = f; +} + +inline void MdpCtrl::setZ(overlay::utils::eZorder z) { + mOVInfo.z_order = z; +} + +inline void MdpCtrl::setWait(overlay::utils::eWait wait) { + mOVInfo.flags = utils::setWait(wait, mOVInfo.flags); +} + +inline void MdpCtrl::setIsFg(overlay::utils::eIsFg isFg) { + mOVInfo.is_fg = isFg; +} + +inline bool MdpCtrl::ovChanged() const { + // 0 means same + if(0 == ::memcmp(&mOVInfo, &mLkgo, sizeof (mdp_overlay))) { + return false; + } + return true; +} + +inline void MdpCtrl::save() { + if(static_cast(mOVInfo.id) == -1) { + ALOGE("MdpCtrl current ov has id -1, will not save"); + // FIXME dump both? + return; + } + mLkgo = mOVInfo; +} + +inline void MdpCtrl::restore() { + if(static_cast(mLkgo.id) == -1) { + ALOGE("MdpCtrl Lkgo ov has id -1, will not restore"); + // FIXME dump both? + return; + } + mOVInfo = mLkgo; +} + +inline overlay::utils::Whf MdpCtrl::getSrcWhf() const { + return utils::Whf(mOVInfo.src.width, + mOVInfo.src.height, + mOVInfo.src.format); +} + +inline void MdpCtrl::setSrcWhf(const overlay::utils::Whf& whf) { + mOVInfo.src.width = whf.w; + mOVInfo.src.height = whf.h; + mOVInfo.src.format = whf.format; +} + +inline overlay::utils::Dim MdpCtrl::getSrcRectDim() const { + return utils::Dim(mOVInfo.src_rect.x, + mOVInfo.src_rect.y, + mOVInfo.src_rect.w, + mOVInfo.src_rect.h); +} + +inline void MdpCtrl::setSrcRectDim(const overlay::utils::Dim d) { + mOVInfo.src_rect.x = d.x; + mOVInfo.src_rect.y = d.y; + mOVInfo.src_rect.w = d.w; + mOVInfo.src_rect.h = d.h; +} + +inline overlay::utils::Dim MdpCtrl::getDstRectDim() const { + return utils::Dim(mOVInfo.dst_rect.x, + mOVInfo.dst_rect.y, + mOVInfo.dst_rect.w, + mOVInfo.dst_rect.h); +} + +inline void MdpCtrl::setDstRectDim(const overlay::utils::Dim d) { + mOVInfo.dst_rect.x = d.x; + mOVInfo.dst_rect.y = d.y; + mOVInfo.dst_rect.w = d.w; + mOVInfo.dst_rect.h = d.h; +} + +inline int MdpCtrl::getUserData() const { return mOVInfo.user_data[0]; } + +inline void MdpCtrl::setUserData(int v) { mOVInfo.user_data[0] = v; } + +inline void MdpCtrl::setRotationFlags() { + const int u = getUserData(); + if (u == MDP_ROT_90 || u == MDP_ROT_270) + mOVInfo.flags |= MDP_SOURCE_ROTATED_90; + else + mOVInfo.flags &= ~MDP_SOURCE_ROTATED_90; +} + + +inline void MdpCtrl::swapSrcWH() { + utils::swap(mOVInfo.src.width, + mOVInfo.src.height); } + +inline void MdpCtrl::swapSrcRectWH() { + utils::swap(mOVInfo.src_rect.h, + mOVInfo.src_rect.w); } + +/////// MdpCtrl3D ////// + +inline MdpCtrl3D::MdpCtrl3D() { reset(); } +inline bool MdpCtrl3D::close() { + if (m3DOVInfo.is_3d) { + m3DOVInfo.is_3d = 0; + if(!mdp_wrapper::set3D(mFd.getFD(), m3DOVInfo)) { + ALOGE("MdpCtrl3D close failed set3D with 0"); + return false; + } + } + reset(); + return true; +} +inline void MdpCtrl3D::reset() { + utils::memset0(m3DOVInfo); +} + +inline void MdpCtrl3D::setFd(int fd) { + mFd.copy(fd); + OVASSERT(mFd.valid(), "MdpCtrl3D setFd, FD should be valid"); +} + +inline void MdpCtrl3D::setWh(const utils::Whf& whf) { + // ignore fmt. Needed for useVirtualFB callflow + m3DOVInfo.width = whf.w; + m3DOVInfo.height = whf.h; +} + +inline bool MdpCtrl3D::useVirtualFB() { + if(!m3DOVInfo.is_3d) { + m3DOVInfo.is_3d = 1; + if(!mdp_wrapper::set3D(mFd.getFD(), m3DOVInfo)) { + ALOGE("MdpCtrl3D close failed set3D with 0"); + return false; + } + } + return true; +} + +/////// MdpData ////// + +inline MdpData::MdpData() { reset(); } + +inline MdpData::~MdpData() { close(); } + +inline bool MdpData::open(uint32_t fbnum) { + // FD open + if(!utils::openDev(mFd, fbnum, Res::devTemplate, O_RDWR)){ + ALOGE("Ctrl failed to open fbnum=%d", fbnum); + return false; + } + return true; +} + +inline void MdpData::reset() { + overlay::utils::memset0(mOvData); + mOvData.data.memory_id = -1; +} + +inline bool MdpData::close() { + if(-1 == mOvData.data.memory_id) return true; + reset(); + if(!mFd.close()) { + return false; + } + return true; +} + +inline void MdpData::setMemoryId(int id) { mOvData.data.memory_id = id; } +inline int MdpData::getMemoryId() const { return mOvData.data.memory_id; } + +inline void MdpData::setId(int id) { mOvData.id = id; } + +inline int MdpData::getId() const { return mOvData.id; } + +inline int MdpData::getFd() const { return mFd.getFD(); } + +inline void MdpData::setOffset(uint32_t o) { mOvData.data.offset = o; } + +inline bool MdpData::play() { + if(!mdp_wrapper::play(mFd.getFD(), mOvData)){ + ALOGE("MdpData failed to play"); + return false; + } + return true; +} + +inline bool MdpData::playWait() { + if(!mdp_wrapper::playWait(mFd.getFD(), mOvData)){ + ALOGE("MdpData failed to playWait"); + return false; + } + return true; +} + +} // overlay + +#endif // OVERLAY_MDP_H diff --git a/liboverlay/overlayMem.h b/liboverlay/overlayMem.h new file mode 100644 index 0000000..7c04890 --- /dev/null +++ b/liboverlay/overlayMem.h @@ -0,0 +1,205 @@ +/* +* Copyright (c) 2011-2012, 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 OVERLAY_MEM_H +#define OVERLAY_MEM_H + +#include +#include +#include +#include + +#include "gralloc_priv.h" +#include "overlayUtils.h" + +namespace overlay { + +/* +* Holds base address, offset and the fd +* */ +class OvMem { +public: + /* ctor init*/ + explicit OvMem(); + + /* dtor DO NOT call close so it can be copied */ + ~OvMem(); + + /* Use libgralloc to retrieve fd, base addr, alloc type */ + bool open(uint32_t numbufs, + uint32_t bufSz, int flags = O_RDWR); + + /* close fd. assign base address to invalid*/ + bool close(); + + /* return underlying fd */ + int getFD() const; + + /* return true if fd is valid and base address is valid */ + bool valid() const; + + /* dump the state of the object */ + void dump() const; + + /* return underlying address */ + void* addr() const; + + /* return underlying offset */ + uint32_t bufSz() const; + + /* return number of bufs */ + uint32_t numBufs() const ; + +private: + /* actual os fd */ + int mFd; + + /* points to base addr (mmap)*/ + void* mBaseAddr; + + /* allocated buffer type determined by gralloc (ashmem, ion, etc) */ + int mAllocType; + + /* holds buf size */ + uint32_t mBufSz; + + /* num of bufs */ + uint32_t mNumBuffers; + + /* gralloc alloc controller */ + android::sp mAlloc; +}; + +//-------------------Inlines----------------------------------- + +using android::sp; +using gralloc::IMemAlloc; +using gralloc::alloc_data; + +inline OvMem::OvMem() { + mFd = -1; + mBaseAddr = MAP_FAILED; + mAllocType = 0; + mBufSz = 0; + mNumBuffers = 0; + mAlloc = gralloc::IAllocController::getInstance(false); +} + +inline OvMem::~OvMem() { } + +inline bool OvMem::open(uint32_t numbufs, + uint32_t bufSz, int flags) +{ + alloc_data data; + //XXX: secure buffers and IOMMU heap + int allocFlags = GRALLOC_USAGE_PRIVATE_MM_HEAP | + GRALLOC_USAGE_PRIVATE_DO_NOT_MAP; + int err = 0; + + OVASSERT(numbufs && bufSz, "numbufs=%d bufSz=%d", numbufs, bufSz); + + mBufSz = bufSz; + mNumBuffers = numbufs; + + data.base = 0; + data.fd = -1; + data.offset = 0; + data.size = mBufSz * mNumBuffers; + data.align = getpagesize(); + data.uncached = true; + + err = mAlloc->allocate(data, allocFlags, 0); + if (err != 0) { + ALOGE("OvMem: error allocating memory"); + } + + mFd = data.fd; + mBaseAddr = data.base; + mAllocType = data.allocType; + + return true; +} + +inline bool OvMem::close() +{ + int ret = 0; + + if(!valid()) { + return true; + } + + sp memalloc = mAlloc->getAllocator(mAllocType); + ret = memalloc->free_buffer(mBaseAddr, mBufSz * mNumBuffers, 0, mFd); + if (ret != 0) { + ALOGE("OvMem: error freeing buffer"); + } + + mFd = -1; + mBaseAddr = MAP_FAILED; + mAllocType = 0; + mBufSz = 0; + mNumBuffers = 0; + return ret; +} + +inline bool OvMem::valid() const +{ + return (mFd != -1) && (mBaseAddr != MAP_FAILED); +} + +inline int OvMem::getFD() const +{ + return mFd; +} + +inline void* OvMem::addr() const +{ + return mBaseAddr; +} + +inline uint32_t OvMem::bufSz() const +{ + return mBufSz; +} + +inline uint32_t OvMem::numBufs() const +{ + return mNumBuffers; +} + +inline void OvMem::dump() const +{ + ALOGE("%s: fd=%d addr=%p type=%d bufsz=%u", + __FUNCTION__, mFd, mBaseAddr, mAllocType, mBufSz); +} + +} // overlay + +#endif // OVERLAY_MEM_H diff --git a/liboverlay/overlayRotator.cpp b/liboverlay/overlayRotator.cpp new file mode 100644 index 0000000..30c5ea5 --- /dev/null +++ b/liboverlay/overlayRotator.cpp @@ -0,0 +1,430 @@ +/* +* Copyright (C) 2008 The Android Open Source Project +* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved. +* +* 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. +*/ + +#include "overlayRotator.h" +#include "overlayUtils.h" +#include "overlayMdp.h" + +namespace ovutils = overlay::utils; + +namespace overlay { + +namespace utils { +inline mdp_overlay setInfoNullRot(const utils::PipeArgs& args, + const mdp_overlay& o) +{ + mdp_overlay ov = o; + utils::Whf whf(args.whf); + utils::Dim d(utils::getSrcRectDim(ov)); + + d.w = whf.w - (utils::alignup(whf.w, 64) - whf.w); + d.h = whf.h - (utils::alignup(whf.h, 32) - whf.h); + utils::setSrcRectDim(ov, d); + return ov; +} + +inline mdp_overlay setInfoRot(const utils::PipeArgs& args, + const mdp_overlay& o) +{ + /* If there are no orientation, then we use setInfoRot + * That is even if we are a real rotator object (not null) + * Note, that if args.rotFlags are ENABLED + * it means we would still like to have rot + * even though it is ROT_0 */ + if(OVERLAY_TRANSFORM_0 == args.orientation && + utils::ROT_FLAG_ENABLED != args.rotFlags) { + return setInfoNullRot(args, o); + } + + mdp_overlay ov = o; + utils::Whf whf(args.whf); + utils::Dim d(utils::getSrcRectDim(ov)); + d.w = whf.w; + d.h = whf.h; + utils::Whf localwhf (utils::getSrcWhf(ov)); + localwhf.w = utils::alignup(whf.w, 64); + localwhf.h = utils::alignup(whf.h, 32); + d.x = localwhf.w - whf.w; + d.y = localwhf.h - whf.h; + utils::setSrcRectDim(ov, d); + utils::setSrcWhf(ov, localwhf); + return ov; +} + +} // utils + +bool MdpRot::open() +{ + if(!mFd.open(Res::rotPath, O_RDWR)){ + ALOGE("MdpRot failed to open %s", Res::rotPath); + return false; + } + return true; +} + +bool MdpRot::open_i(uint32_t numbufs, uint32_t bufsz) +{ + OvMem mem; + + OVASSERT(MAP_FAILED == mem.addr(), "MAP failed in open_i"); + + if(!mem.open(numbufs, bufsz)){ + ALOGE("%s: Failed to open", __func__); + mem.close(); + return false; + } + + OVASSERT(MAP_FAILED != mem.addr(), "MAP failed"); + OVASSERT(mem.getFD() != -1, "getFd is -1"); + + mData.data.memory_id = mem.getFD(); + mRotDataInfo.dst.memory_id = mem.getFD(); + mRotDataInfo.dst.offset = 0; + mMem.curr().m = mem; + return true; +} + +bool MdpRot::RotMem::close() { + bool ret = true; + for(uint32_t i=0; i < RotMem::MAX_ROT_MEM; ++i) { + // skip current, and if valid, close + if(m[i].valid() && (m[i].close() != 0)) { + ALOGE("%s error in closing prev rot mem %d", __FUNCTION__, i); + ret = false; + } + } + return ret; +} + +bool MdpRot::close() { + bool success = true; + if(mFd.valid() && (getSessId() > 0)) { + if(!mdp_wrapper::endRotator(mFd.getFD(), getSessId())) { + ALOGE("Mdp Rot error endRotator, fd=%d sessId=%d", + mFd.getFD(), getSessId()); + success = false; + } + } + if (!mFd.close()) { + ALOGE("Mdp Rot error closing fd"); + success = false; + } + if (!mMem.close()) { + ALOGE("Mdp Rot error closing mem"); + success = false; + } + reset(); + return success; +} + +bool MdpRot::unmapNonCurrent() { + bool ret = true; + for(uint32_t i=0; i < RotMem::MAX_ROT_MEM; ++i) { + // skip current, and if valid, close + if(i != mMem._curr % RotMem::MAX_ROT_MEM && + mMem.m[i].valid() && + !mMem.m[i].close()) { + ALOGE("%s error in closing prev rot mem %d", __FUNCTION__, i); + ret = false; + } + } + return ret; +} + +bool MdpRot::remap(uint32_t numbufs, + const utils::PipeArgs& args) { + // if current size changed, remap + if(args.whf.size == mMem.curr().size()) { + ALOGE_IF(DEBUG_OVERLAY, "%s: same size %d", __FUNCTION__, args.whf.size); + return true; + } + + // remap only if we have orientation. + // If rotFlags are ENABLED, it means we need rotation bufs + // even when orientation is 0 + if(utils::OVERLAY_TRANSFORM_0 == args.orientation && + utils::ROT_FLAG_ENABLED != args.rotFlags) { + ALOGE_IF(DEBUG_OVERLAY, "%s: orientation=%d, rotFlags=%d", + __FUNCTION__, args.orientation, args.rotFlags); + return true; + } + + ALOGE_IF(DEBUG_OVERLAY, "%s: size changed - remapping", __FUNCTION__); + OVASSERT(!mMem.prev().valid(), "Prev should not be valid"); + + // remap and have the current to be the new one. + // ++mMem will make curr to be prev, and prev will be curr + ++mMem; + if(!open_i(numbufs, args.whf.size)) { + ALOGE("%s Error could not open", __FUNCTION__); + return false; + } + OVASSERT(numbufs <= ROT_MAX_BUF_OFFSET, + "Numbufs %d > ROT_MAX_BUF_OFFSET", numbufs); + for (uint32_t i = 0; i < numbufs; ++i) { + mMem.curr().mRotOffset[i] = i * args.whf.size; + } + return true; +} + +bool MdpRot::start() { + if(!overlay::mdp_wrapper::startRotator(mFd.getFD(), mRotImgInfo)) { + ALOGE("MdpRot start failed"); + this->dump(); + return false; + } + mRotDataInfo.session_id = mRotImgInfo.session_id; + return true; +} + +void MdpRot::reset() { + ovutils::memset0(mRotImgInfo); + ovutils::memset0(mRotDataInfo); + ovutils::memset0(mData); + ovutils::memset0(mMem.curr().mRotOffset); + ovutils::memset0(mMem.prev().mRotOffset); + mMem.curr().mCurrOffset = 0; + mMem.prev().mCurrOffset = 0; + isSrcFB = false; +} + +bool MdpRot::prepareQueueBuf(uint32_t offset) { + // FIXME if it fails, what happens to the above current item? + if(enabled()) { + OVASSERT(mMem.curr().m.numBufs(), + "prepareQueueBuf numbufs is 0"); + + // If the rotator source is FB + if(isSrcFB) { + mRotDataInfo.src.flags |= MDP_MEMORY_ID_TYPE_FB; + } + + mRotDataInfo.src.offset = offset; + mRotDataInfo.dst.offset = + mMem.curr().mRotOffset[mMem.curr().mCurrOffset]; + mMem.curr().mCurrOffset = + (mMem.curr().mCurrOffset + 1) % mMem.curr().m.numBufs(); + if(!overlay::mdp_wrapper::rotate(mFd.getFD(), mRotDataInfo)) { + ALOGE("MdpRot failed rotate"); + return false; + } + mData.data.offset = mRotDataInfo.dst.offset; + } + return true; +} + + +bool MdpRot::play(int fd) { + if(!overlay::mdp_wrapper::play(fd, mData)) { + ALOGE("MdpRot failed to play with fd=%d", fd); + return false; + } + + // if the prev mem is valid, we need to close + if(mMem.prev().valid()) { + // FIXME FIXME FIXME if no wait for vsync the above + // play will return immediatly and might cause + // tearing when prev.close is called. + if(!mMem.prev().close()) { + ALOGE("%s error in closing prev rot mem", __FUNCTION__); + } + } + return true; +} + +///// Null Rot //// + +mdp_overlay NullRotator::setInfo( + const utils::PipeArgs& args, + const mdp_overlay& o) { + return utils::setInfoNullRot(args, o); +} + +///// Rotator //// + +mdp_overlay Rotator::setInfo( + const utils::PipeArgs& args, + const mdp_overlay& o) +{ + return utils::setInfoRot(args, o); +} + +bool Rotator::overlayTransform(MdpCtrl& mdp, + utils::eTransform& rot) +{ + ALOGE_IF(DEBUG_OVERLAY, "%s: rot=%d", __FUNCTION__, rot); + switch(int(rot)) { + case 0: + case HAL_TRANSFORM_FLIP_H: + case HAL_TRANSFORM_FLIP_V: + overlayTransFlipHV(mdp, rot); + break; + case HAL_TRANSFORM_ROT_90: + case (HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_H): + case (HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_V): + overlayTransFlipRot90(mdp, rot); + break; + case HAL_TRANSFORM_ROT_180: + overlayTransFlipRot180(mdp); + break; + case HAL_TRANSFORM_ROT_270: + overlayTransFlipRot270(mdp); + break; + default: + ALOGE("%s: Error due to unknown rot value %d", __FUNCTION__, rot); + return false; + } + + /* everything below is rotation related */ + int r = utils::getMdpOrient(rot); + ALOGE_IF(DEBUG_OVERLAY, "%s: r=%d", __FUNCTION__, r); + if (r == -1) { + ALOGE("Ctrl setParameter rot it -1"); + return false; + } + + // Need to have both in sync + mdp.setUserData(r); + this->setRotations(r); + this->setDisable(); + if(r) { + this->setEnable(); + } + + /* set src format using rotation info + * e.g. (12-->5 in case of rotation) */ + mdp.setSrcFormat(this->getSrcWhf()); + + // based on 90/270 set flags + mdp.setRotationFlags(); + return true; +} + +void Rotator::overlayTransFlipHV(MdpCtrl& mdp, + utils::eTransform& rot) +{ + int val = mdp.getUserData(); + ALOGE_IF(DEBUG_OVERLAY, "%s: prev=%d", __FUNCTION__, val); + utils::Dim d = mdp.getSrcRectDim(); + utils::Whf whf = mdp.getSrcWhf(); + if (val == MDP_ROT_90) { + int tmp = d.y; + d.y = compute(whf.w, + d.x, + d.w); + d.x = tmp; + mdp.setSrcRectDim(d); + utils::swapOVRotWidthHeight(mRot, mdp); + } + else if (val == MDP_ROT_270) { + int tmp = d.x; + d.x = compute(whf.h, + d.y, + d.h); + d.y = tmp; + mdp.setSrcRectDim(d); + utils::swapOVRotWidthHeight(mRot, mdp); + } +} + +void Rotator::overlayTransFlipRot90(MdpCtrl& mdp, + utils::eTransform& rot) +{ + int val = mdp.getUserData(); + ALOGE_IF(DEBUG_OVERLAY, "%s: prev=%d", __FUNCTION__, val); + utils::Dim d = mdp.getSrcRectDim(); + utils::Whf whf = mdp.getSrcWhf(); + if (val == MDP_ROT_270) { + d.x = compute(whf.w, + d.x, + d.w); + d.y = compute(whf.h, + d.y, + d.h); + } + else if (val == MDP_ROT_NOP || val == MDP_ROT_180) { + int tmp = d.x; + d.x = compute(whf.h, + d.y, + d.h); + d.y = tmp; + mdp.setSrcRectDim(d); + utils::swapOVRotWidthHeight(mRot, mdp); + } +} + +void Rotator::overlayTransFlipRot180(MdpCtrl& mdp) +{ + int val = mdp.getUserData(); + ALOGE_IF(DEBUG_OVERLAY, "%s: prev=%d", __FUNCTION__, val); + utils::Dim d = mdp.getSrcRectDim(); + utils::Whf whf = mdp.getSrcWhf(); + if (val == MDP_ROT_270) { + int tmp = d.y; + d.y = compute(whf.w, + d.x, + d.w); + d.x = tmp; + mdp.setSrcRectDim(d); + utils::swapOVRotWidthHeight(mRot, mdp); + } + else if (val == MDP_ROT_90) { + int tmp = d.x; + d.x = compute(whf.h, + d.y, + d.h); + d.y = tmp; + mdp.setSrcRectDim(d); + utils::swapOVRotWidthHeight(mRot, mdp); + } +} + +void Rotator::overlayTransFlipRot270(MdpCtrl& mdp) +{ + int val = mdp.getUserData(); + ALOGE_IF(DEBUG_OVERLAY, "%s: prev=%d", __FUNCTION__, val); + utils::Dim d = mdp.getSrcRectDim(); + utils::Whf whf = mdp.getSrcWhf(); + if (val == MDP_ROT_90) { + d.y = compute(whf.h, + d.y, + d.h); + d.x = compute(whf.w, + d.x, + d.w); + } + else if (val == MDP_ROT_NOP || val == MDP_ROT_180) { + int tmp = d.y; + d.y = compute(whf.w, + d.x, + d.w); + d.x = tmp; + mdp.setSrcRectDim(d); + utils::swapOVRotWidthHeight(mRot, mdp); + } +} + +void MdpRot::dump() const { + ALOGE("== Dump MdpRot start =="); + mFd.dump(); + mMem.curr().m.dump(); + mdp_wrapper::dump("mRotImgInfo", mRotImgInfo); + mdp_wrapper::dump("mRotDataInfo", mRotDataInfo); + mdp_wrapper::dump("mData", mData); + ALOGE("== Dump MdpRot end =="); +} +} diff --git a/liboverlay/overlayRotator.h b/liboverlay/overlayRotator.h new file mode 100644 index 0000000..39c4f0c --- /dev/null +++ b/liboverlay/overlayRotator.h @@ -0,0 +1,554 @@ +/* +* Copyright (c) 2011-2012, 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 OVERLAY_ROTATOR_H +#define OVERLAY_ROTATOR_H + +#include + +#include "mdpWrapper.h" +#include "overlayUtils.h" +#include "overlayMem.h" + +namespace overlay { + class MdpCtrl; +/* +* MDP rot holds MDP's rotation related structures. +* +* */ +class MdpRot { +public: + /* ctor */ + explicit MdpRot(); + + /* open fd for rotator. map bufs is defered */ + bool open(); + + /* remap rot buffers */ + bool remap(uint32_t numbufs, const utils::PipeArgs& args); + + /* Unmap everything that is not current */ + bool unmapNonCurrent(); + + /* close fd, mem */ + bool close(); + + /* reset underlying data, basically memset 0 */ + void reset(); + + /* calls underlying wrappers to start rotator */ + bool start(); + + /* start underlying but use given whf and flags */ + bool start(const utils::PipeArgs& args); + + /* start underlying but use given whf and flags. + * Has the ability to parameterize the dst fmt */ + template + bool start(const utils::PipeArgs& args); + + /* assign memory id to mdp structure */ + void setDataMemId(int fd); + void setRotDataSrcMemId(int fd); + + /* Mark src as FB (non-ION) */ + void setSrcFB(bool); + + /* get dst (for offset and memory id) non-virt */ + int getDstMemId() const; + uint32_t getDstOffset() const; + + /* set enable/disable flag */ + void setEnable(); + void setDisable(); + bool enabled() const; + + /* set rotator flag*/ + void setRotations(uint32_t r); + + /* set the req data id in mData */ + void setDataReqId(int id); + + /* swap rot info dst w/h */ + void swapDstWH(); + + /* returns a copy of src whf */ + utils::Whf getSrcWhf() const; + + /* setup rotator data before queue buf calls + * call play if rotate call succeed. return false if failed */ + bool prepareQueueBuf(uint32_t offset); + + /* call play on mdp*/ + bool play(int fd); + + /* set src whf */ + void setSrcWhf(const utils::Whf& whf); + + /* returns rotator session id */ + int getSessId() const; + + /* dump the state of the object */ + void dump() const; + +private: + bool open_i(uint32_t numbufs, uint32_t bufsz); + + /* max buf no for offset */ + enum { ROT_MAX_BUF_OFFSET = 2 }; + /* rot info*/ + msm_rotator_img_info mRotImgInfo; + /* rot data */ + msm_rotator_data_info mRotDataInfo; + /* data needed for rotator */ + msmfb_overlay_data mData; + /* rotator fd */ + OvFD mFd; + /* Array of memory map for rotator + * The array enable us to change rot buffers/mapping + * on the fly*/ + struct RotMem { + enum {MAX_ROT_MEM = 2}; + struct Mem { + Mem() : mCurrOffset(0) {utils::memset0(mRotOffset); } + bool valid() { return m.valid(); } + bool close() { return m.close(); } + uint32_t size() const { return m.bufSz(); } + /* rotator data info dst offset */ + uint32_t mRotOffset[ROT_MAX_BUF_OFFSET]; + /* current offset slot from mRotOffset */ + uint32_t mCurrOffset; + OvMem m; + }; + RotMem() : _curr(0) {} + Mem& curr() { return m[_curr % MAX_ROT_MEM]; } + const Mem& curr() const { return m[_curr % MAX_ROT_MEM]; } + Mem& prev() { return m[(_curr+1) % MAX_ROT_MEM]; } + RotMem& operator++() { ++_curr; return *this; } + bool close(); + uint32_t _curr; + Mem m[MAX_ROT_MEM]; + } mMem; + bool isSrcFB; +}; + +/* +* RotatorBase. No memebers, just interface. +* ~ can also be =0 with empty impl in cpp. +* */ +class RotatorBase { +public: + /* Most of the below are No op funcs for RotatorBase */ + virtual ~RotatorBase() {} + virtual bool open() = 0; + virtual bool remap(uint32_t numbufs, const utils::PipeArgs& args) = 0; + virtual bool close() = 0; + virtual bool start(const utils::PipeArgs& args) = 0; + virtual bool start() = 0; + virtual mdp_overlay setInfo(const utils::PipeArgs& args, + const mdp_overlay& o) = 0; + virtual bool overlayTransform(MdpCtrl& mdp, + utils::eTransform& rot) = 0; + virtual void setSrcWhf(const utils::Whf& wfh) = 0; + virtual utils::Whf getSrcWhf() const = 0; + virtual void setRotations(uint32_t r) = 0; + virtual void setDataReqId(int id) = 0; + virtual bool prepareQueueBuf(uint32_t offset) = 0; + virtual bool play(int fd) = 0; + virtual void setEnable() = 0; + virtual void setDisable() = 0; + virtual bool enabled() const = 0; + virtual void setDataMemId(int fd) = 0; + virtual void setRotDataSrcMemId(int fd) = 0; + virtual void setSrcFB(bool) = 0; + virtual int getSessId() const = 0; + virtual void dump() const = 0; +}; + +/* +* Null/Empty impl of RotatorBase +* */ +class NullRotator : public RotatorBase { +public: + /* Most of the below are No op funcs for RotatorBase */ + virtual ~NullRotator(); + virtual bool open(); + virtual bool remap(uint32_t numbufs, const utils::PipeArgs& args); + virtual bool close(); + virtual bool start(const utils::PipeArgs& args); + virtual bool start(); + /* null rotator behavior should set info in a specific way */ + virtual mdp_overlay setInfo(const utils::PipeArgs& args, + const mdp_overlay& o); + virtual bool overlayTransform(MdpCtrl& o, + utils::eTransform& rot); + virtual void setSrcWhf(const utils::Whf& wfh); + virtual utils::Whf getSrcWhf() const; + virtual void setRotations(uint32_t r); + virtual void setDataReqId(int id); + virtual bool prepareQueueBuf(uint32_t offset); + virtual bool play(int fd); + virtual void setEnable(); + virtual void setDisable(); + virtual bool enabled () const; + virtual void setDataMemId(int fd); + virtual void setRotDataSrcMemId(int fd); + virtual void setSrcFB(bool); + virtual int getSessId() const; + virtual void dump() const; +}; + + +/* +* Rotator impl. +* */ +class Rotator : public RotatorBase +{ +public: + /* construct underlying object */ + explicit Rotator(); + + /* close underlying rot */ + virtual ~Rotator(); + + /* calls underlying open */ + virtual bool open(); + + /* remap rot buffers */ + virtual bool remap(uint32_t numbufs, const utils::PipeArgs& args); + + /* calls underlying close */ + virtual bool close(); + + /* calls underlying start */ + virtual bool start(); + + /* calls underlying start with whf and flags */ + virtual bool start(const utils::PipeArgs& args); + + /* non virtual - calls underlying start with whf and flags. + * Has the ability to parameterize the dst */ + template + bool start(const utils::PipeArgs& args); + + /* Unmap everything that is not current */ + bool unmapNonCurrent(); + + /* set info using whf and given mdp */ + virtual mdp_overlay setInfo(const utils::PipeArgs& args, + const mdp_overlay& o); + + /* transform function for the MDP */ + virtual bool overlayTransform(MdpCtrl& mdp, + utils::eTransform& rot); + + /* set src whf */ + virtual void setSrcWhf(const utils::Whf& wfh); + + /* set Rotations */ + virtual void setRotations(uint32_t r); + + /* set the req data id in mData */ + virtual void setDataReqId(int id); + + /* set memory_id */ + virtual void setDataMemId(int fd); + virtual void setRotDataSrcMemId(int fd); + + /* Mark the src for rotator as FB. usually set by UI mirroing cases */ + virtual void setSrcFB(bool); + + /* get dst (for offset and memory id) non-virt */ + int getDstMemId() const; + uint32_t getDstOffset() const; + + /* set enable/disable flag */ + virtual void setEnable(); + virtual void setDisable(); + virtual bool enabled () const; + + /* return rotator sess id */ + virtual int getSessId() const; + + /* return a copy of src whf*/ + virtual utils::Whf getSrcWhf() const; + + /* prepare rot for queue buf*/ + virtual bool prepareQueueBuf(uint32_t offset); + + /* call play on mdp*/ + virtual bool play(int fd); + + /* dump the state of the object */ + virtual void dump() const; +private: + /* helper functions for overlayTransform */ + void overlayTransFlipHV(MdpCtrl& mdp, + utils::eTransform& rot); + void overlayTransFlipRot90(MdpCtrl& mdp, + utils::eTransform& rot); + void overlayTransFlipRot180(MdpCtrl& mdp); + void overlayTransFlipRot270(MdpCtrl& mdp); + + /* underlying rotator MDP object */ + MdpRot mRot; +}; + + +//--------------inlines------------------------------------ +//// MdpRot //// +inline MdpRot::MdpRot() { reset(); } +inline bool MdpRot::start(const utils::PipeArgs& args) { + return this->start(args); +} + +inline void MdpRot::setDataMemId(int fd) { mData.data.memory_id = fd; } +inline void MdpRot::setRotDataSrcMemId(int fd) { + mRotDataInfo.src.memory_id = fd; } + +inline void MdpRot::setEnable() { mRotImgInfo.enable = 1; } +inline void MdpRot::setDisable() { mRotImgInfo.enable = 0; } +inline bool MdpRot::enabled() const { return mRotImgInfo.enable; } + +inline void MdpRot::setRotations(uint32_t r) { mRotImgInfo.rotations = r; } +inline void MdpRot::setDataReqId(int id) { mData.id = id; } +inline void MdpRot::swapDstWH() { + overlay::utils::swap(mRotImgInfo.dst.width, + mRotImgInfo.dst.height); } + +inline overlay::utils::Whf MdpRot::getSrcWhf() const { + return overlay::utils::Whf(mRotImgInfo.src.width, + mRotImgInfo.src.height, + mRotImgInfo.src.format); +} + +inline int MdpRot::getDstMemId() const { + return mRotDataInfo.dst.memory_id; +} +inline uint32_t MdpRot::getDstOffset() const { + return mRotDataInfo.dst.offset; +} + +inline void MdpRot::setSrcWhf(const overlay::utils::Whf& whf) { + mRotImgInfo.src.width = whf.w; + mRotImgInfo.src.height = whf.h; + mRotImgInfo.src.format = whf.format; +} + +inline int MdpRot::getSessId() const { return mRotImgInfo.session_id; } + +inline void MdpRot::setSrcFB(bool mark) { isSrcFB = mark; } + +///// Null Rotator ///// +inline NullRotator::~NullRotator() {} +inline bool NullRotator::open() { + return true; } +inline bool NullRotator::remap(uint32_t numbufs, + const utils::PipeArgs& args){ + return true; } +inline bool NullRotator::close() { return true; } +inline bool NullRotator::start(const utils::PipeArgs& args) +{ return true; } + +inline bool NullRotator::start() { return true; } +inline bool NullRotator::overlayTransform(MdpCtrl& o, + utils::eTransform& rot) +{ return true; } +inline void NullRotator::setSrcWhf(const overlay::utils::Whf& wfh) {} +inline void NullRotator::setRotations(uint32_t) {} +inline void NullRotator::setDataReqId(int id) {} +inline void NullRotator::setEnable() {} +inline void NullRotator::setDisable() {} +inline bool NullRotator::enabled() const { return false; } +inline int NullRotator::getSessId() const { return -1; } +inline overlay::utils::Whf NullRotator::getSrcWhf() const { + return overlay::utils::Whf(); } +inline bool NullRotator::prepareQueueBuf(uint32_t offset) +{ return true; } +inline bool NullRotator::play(int fd) +{ return true; } +inline void NullRotator::setDataMemId(int fd) {} +inline void NullRotator::setRotDataSrcMemId(int fd) {} +inline void NullRotator::setSrcFB(bool) {} +inline void NullRotator::dump() const { + ALOGE("== Dump NullRotator dump (null) start/end =="); +} + +///// Rotator ///// +inline Rotator::Rotator() { } + +inline Rotator::~Rotator() { + mRot.close(); // also will do reset +} + +inline bool Rotator::open() { + if(!mRot.open()) { + ALOGE("Rotator::open failed"); + return false; + } + return true; +} + +template +inline bool Rotator::start(const utils::PipeArgs& args) { + return mRot.start(args); +} + +inline bool Rotator::remap(uint32_t numbufs, + const utils::PipeArgs& args){ + if(!mRot.remap(numbufs, args)) { + ALOGE("%s failed", __FUNCTION__); + return false; + } + return true; +} + +inline bool Rotator::close() { + return mRot.close(); +} + +inline bool Rotator::start() { + return mRot.start(); +} + +inline bool Rotator::start(const utils::PipeArgs& args) { + return mRot.start(args); +} + +inline bool Rotator::unmapNonCurrent() { + return mRot.unmapNonCurrent(); +} + +inline void Rotator::setEnable(){ mRot.setEnable(); } +inline void Rotator::setDisable(){ mRot.setDisable(); } +inline bool Rotator::enabled() const { return mRot.enabled(); } +inline void Rotator::setDataMemId(int fd) { + mRot.setDataMemId(fd); } + +inline void Rotator::setRotDataSrcMemId(int fd) { + mRot.setRotDataSrcMemId(fd); +} + +inline void Rotator::setSrcFB(bool mark) { mRot.setSrcFB(mark); } + +inline int Rotator::getDstMemId() const { + return mRot.getDstMemId(); +} +inline uint32_t Rotator::getDstOffset() const { + return mRot.getDstOffset(); +} + +inline void Rotator::setDataReqId(int id) { + mRot.setDataReqId(id); +} + +inline void Rotator::setSrcWhf( + const overlay::utils::Whf& whf) { + mRot.setSrcWhf(whf); +} + +inline void Rotator::setRotations(uint32_t rot) { + mRot.setRotations (rot); +} + +inline int Rotator::getSessId() const { + return mRot.getSessId(); } + +inline void Rotator::dump() const { + ALOGE("== Dump Rotator start =="); + mRot.dump(); + ALOGE("== Dump Rotator end =="); +} + +inline overlay::utils::Whf Rotator::getSrcWhf() const { + return mRot.getSrcWhf(); } + +inline bool Rotator::prepareQueueBuf(uint32_t offset) +{ + return mRot.prepareQueueBuf(offset); +} + +inline bool Rotator::play(int fd) +{ + return mRot.play(fd); +} + +template +bool MdpRot::start(const utils::PipeArgs& args) { + // Do nothing when no orientation + if(utils::OVERLAY_TRANSFORM_0 == args.orientation && + utils::ROT_FLAG_ENABLED != args.rotFlags) { + return true; + } + utils::Whf whf(args.whf); + mRotImgInfo.src.format = whf.format; + mRotImgInfo.src.width = whf.w; + mRotImgInfo.src.height = whf.h; + mRotImgInfo.src_rect.w = whf.w; + mRotImgInfo.src_rect.h = whf.h; + mRotImgInfo.dst.width = whf.w; + mRotImgInfo.dst.height = whf.h; + if(whf.format == MDP_Y_CRCB_H2V2_TILE || + whf.format == MDP_Y_CBCR_H2V2_TILE) { + mRotImgInfo.src.width = utils::alignup(whf.w, 64); + mRotImgInfo.src.height = utils::alignup(whf.h, 32); + mRotImgInfo.src_rect.w = utils::alignup(whf.w, 64); + mRotImgInfo.src_rect.h = utils::alignup(whf.h, 32); + mRotImgInfo.dst.width = utils::alignup(whf.w, 64); + mRotImgInfo.dst.height = utils::alignup(whf.h, 32); + mRotImgInfo.dst.format = MDP_Y_CRCB_H2V2; + } + // either utils::getRotOutFmt(whf.format); or supplied fmt + // utils::RotOutFmt::fmt; + mRotImgInfo.dst.format = utils::RotOutFmt::fmt(whf.format); + mRotImgInfo.dst_x = 0; + mRotImgInfo.dst_y = 0; + mRotImgInfo.src_rect.x = 0; + mRotImgInfo.src_rect.y = 0; + mRotImgInfo.rotations = 0; + // ROT_FLAG_DISABLED / ENABLED + // Refer to overlayUtils.h eRotFlags + // for more info + mRotImgInfo.enable = args.rotFlags; + mRotImgInfo.session_id = mRotImgInfo.session_id ? + mRotImgInfo.session_id : 0; + + return start(); +} + +} // overlay + +namespace { +// just a helper func for Rotator common operations x-(y+z) +int compute(uint32_t x, uint32_t y, uint32_t z) { + return x-(y+z); +} +} + +#endif // OVERLAY_ROTATOR_H diff --git a/liboverlay/overlayState.h b/liboverlay/overlayState.h new file mode 100644 index 0000000..1d13a2e --- /dev/null +++ b/liboverlay/overlayState.h @@ -0,0 +1,907 @@ +/* +* Copyright (c) 2011-2012, 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 OVERLAY_STATE_H +#define OVERLAY_STATE_H + +#include "overlayUtils.h" +#include "overlayImpl.h" +#include "overlayRotator.h" +#include "pipes/overlayGenPipe.h" +#include "pipes/overlayBypassPipe.h" +#include "pipes/overlayHdmiPipe.h" +#include "pipes/overlayUIMirrorPipe.h" +#include "pipes/overlay3DPipe.h" + +// FIXME make int to be uint32 whenever possible + +namespace overlay { + +/* +* Used by Overlay class. Invokes each event +* */ + +/* TODO case of RGBx will call mOv open with diff +* params customized for RGBx pipes */ + +class OverlayState : utils::NoCopy { +public: + /**/ + explicit OverlayState(); + + /**/ + ~OverlayState(); + + /* return current state */ + utils::eOverlayState state() const; + + /* Overlay Event */ + + /* Hard reset to a new state. If the state is the same + * as the current one, it would be a no-op */ + OverlayImplBase* reset(utils::eOverlayState s); + + /* Caller pass the state to the handleEvent function. + * The input is the current OverlayImplBase*, and output is + * a pointer to (possibly new) instance of OverlayImplBase + * The eFormat can be 2D/3D etc. */ + OverlayImplBase* handleEvent(utils::eOverlayState s, + OverlayImplBase* ov); + + /* Transitions from XXX to XXX */ + OverlayImplBase* handle_closed(utils::eOverlayState s); + OverlayImplBase* handle_2D_2DPanel(utils::eOverlayState s, + OverlayImplBase* ov); + OverlayImplBase* handle_2D_2DTV(utils::eOverlayState s, + OverlayImplBase* ov); + OverlayImplBase* handle_3D_2DPanel(utils::eOverlayState s, + OverlayImplBase* ov); + OverlayImplBase* handle_3D_3DPanel(utils::eOverlayState s, + OverlayImplBase* ov); + OverlayImplBase* handle_3D_3DTV(utils::eOverlayState s, + OverlayImplBase* ov); + OverlayImplBase* handle_3D_2DTV(utils::eOverlayState s, + OverlayImplBase* ov); + OverlayImplBase* handle_UI_Mirror(utils::eOverlayState s, + OverlayImplBase* ov); + OverlayImplBase* handle_2D_trueUI_Mirror(utils::eOverlayState s, + OverlayImplBase* ov); + OverlayImplBase* handle_bypass(utils::eOverlayState s, + OverlayImplBase* ov); + + /* Transition from any state to 2D video on 2D panel */ + OverlayImplBase* handle_xxx_to_2D_2DPanel(OverlayImplBase* ov); + + /* Transition from any state to 2D video on 2D panel and 2D TV */ + OverlayImplBase* handle_xxx_to_2D_2DTV(OverlayImplBase* ov); + + /* Transition from any state to 3D video on 2D panel */ + OverlayImplBase* handle_xxx_to_3D_2DPanel(OverlayImplBase* ov); + + /* Transition from any state to 3D video on 2D panel and 2D TV */ + OverlayImplBase* handle_xxx_to_3D_2DTV(OverlayImplBase* ov); + + /* Transition from any state to 2D video true UI mirroring (2D video + UI) */ + OverlayImplBase* handle_xxx_to_2D_trueUI_Mirror(OverlayImplBase* ov); + + /* Transitions from any state to 1 layer composition bypass */ + OverlayImplBase* handle_xxx_to_bypass1(OverlayImplBase* ov); + + /* Transitions from any state to 2 layers composition bypass */ + OverlayImplBase* handle_xxx_to_bypass2(OverlayImplBase* ov); + + /* Transitions from any state to 3 layers composition bypass */ + OverlayImplBase* handle_xxx_to_bypass3(OverlayImplBase* ov); + + /* Dump */ + void dump() const; +private: + /* States here */ + utils::eOverlayState mState; +}; + +//------------------------State Traits -------------------------- + +// primary has nothing +template struct StateTraits {}; + +/* + * For 3D_xxx we need channel ID besides the FBx since + * get crop/position 3D need that to determine pos/crop + * info. + * */ + +template <> struct StateTraits +{ + typedef overlay::GenericPipe pipe0; + typedef overlay::NullPipe pipe1; // place holder + typedef overlay::NullPipe pipe2; // place holder + + typedef Rotator rot0; + typedef NullRotator rot1; + typedef NullRotator rot2; + + typedef overlay::OverlayImpl ovimpl; +}; + +template <> struct StateTraits +{ + typedef overlay::GenericPipe pipe0; + typedef overlay::HdmiPipe pipe1; + typedef overlay::NullPipe pipe2; // place holder + + typedef Rotator rot0; + typedef NullRotator rot1; + typedef NullRotator rot2; + + typedef overlay::OverlayImpl ovimpl; +}; + +template <> struct StateTraits +{ + typedef overlay::M3DPrimaryPipe pipe0; + typedef overlay::NullPipe pipe1; // place holder + typedef overlay::NullPipe pipe2; // place holder + + typedef Rotator rot0; + typedef NullRotator rot1; + typedef NullRotator rot2; + + typedef overlay::OverlayImpl ovimpl; +}; + +template <> struct StateTraits +{ + typedef overlay::S3DPrimaryPipe pipe0; + typedef overlay::S3DPrimaryPipe pipe1; + typedef overlay::NullPipe pipe2; // place holder + + typedef Rotator rot0; + typedef Rotator rot1; + typedef NullRotator rot2; + + typedef overlay::OverlayImpl ovimpl; +}; + +template <> struct StateTraits +{ + typedef overlay::S3DExtPipe pipe0; + typedef overlay::S3DExtPipe pipe1; + typedef overlay::NullPipe pipe2; // place holder + + typedef NullRotator rot0; + typedef NullRotator rot1; + typedef NullRotator rot2; + + typedef overlay::OverlayImpl ovimpl; +}; + +template <> struct StateTraits +{ + typedef overlay::M3DPrimaryPipe pipe0; + typedef overlay::M3DExtPipe pipe1; + typedef overlay::NullPipe pipe2; // place holder + + typedef Rotator rot0; + typedef NullRotator rot1; + typedef NullRotator rot2; + + typedef overlay::OverlayImpl ovimpl; +}; + +template <> struct StateTraits +{ + typedef overlay::UIMirrorPipe pipe0; + typedef overlay::NullPipe pipe1; // place holder + typedef overlay::NullPipe pipe2; // place holder + + typedef Rotator rot0; + typedef NullRotator rot1; + typedef NullRotator rot2; + + typedef overlay::OverlayImpl ovimpl; +}; + +template <> struct StateTraits +{ + typedef overlay::GenericPipe pipe0; + typedef overlay::HdmiPipe pipe1; + typedef overlay::UIMirrorPipe pipe2; + + typedef Rotator rot0; + typedef NullRotator rot1; + typedef Rotator rot2; + + typedef overlay::OverlayImpl ovimpl; +}; + +template <> struct StateTraits +{ + typedef overlay::BypassPipe pipe0; + typedef overlay::NullPipe pipe1; // place holder + typedef overlay::NullPipe pipe2; // place holder + + typedef NullRotator rot0; + typedef NullRotator rot1; + typedef NullRotator rot2; + + typedef overlay::OverlayImpl ovimpl; +}; + +template <> struct StateTraits +{ + typedef overlay::BypassPipe pipe0; + typedef overlay::BypassPipe pipe1; + typedef overlay::NullPipe pipe2; // place holder + + typedef NullRotator rot0; + typedef NullRotator rot1; + typedef NullRotator rot2; + + typedef overlay::OverlayImpl ovimpl; +}; + +template <> struct StateTraits +{ + typedef overlay::BypassPipe pipe0; + typedef overlay::BypassPipe pipe1; + typedef overlay::BypassPipe pipe2; + + typedef NullRotator rot0; + typedef NullRotator rot1; + typedef NullRotator rot2; + + typedef overlay::OverlayImpl ovimpl; +}; + + +//------------------------Inlines -------------------------------- + +inline OverlayState::OverlayState() : mState(utils::OV_CLOSED) +{} + +inline OverlayState::~OverlayState() {} + +inline utils::eOverlayState OverlayState::state() const +{ + return mState; +} + +inline OverlayImplBase* OverlayState::reset(utils::eOverlayState s) +{ + return handleEvent(s, 0); +} + +inline void OverlayState::dump() const +{ + ALOGE("== Dump state %d start/end ==", mState); +} + +template +inline OverlayImplBase* handle_closed_to_xxx() +{ + OverlayImplBase* ov = new typename StateTraits::ovimpl; + RotatorBase* rot0 = new typename StateTraits::rot0; + RotatorBase* rot1 = new typename StateTraits::rot1; + RotatorBase* rot2 = new typename StateTraits::rot2; + if(!ov->open(rot0, rot1, rot2)) { + ALOGE("Overlay failed to open in state %d", STATE); + return 0; + } + return ov; +} + +inline OverlayImplBase* handle_xxx_to_closed(OverlayImplBase* ov) +{ + OVASSERT(ov, "%s: ov is null", __FUNCTION__); + + if(!ov->close()) { + ALOGE("%s: Failed to ov close", __FUNCTION__); + } + delete ov; + ov = 0; + return 0; +} + +/* Hard transitions from any state to any state will close and then open */ +template +inline OverlayImplBase* handle_xxx_to_xxx(OverlayImplBase* ov) +{ + OVASSERT(ov, "%s: ov is null", __FUNCTION__); + + handle_xxx_to_closed(ov); + return handle_closed_to_xxx(); +} + +inline OverlayImplBase* OverlayState::handleEvent(utils::eOverlayState newState, + OverlayImplBase* ov) +{ + OverlayImplBase* newov = ov; // at least, we return the same + if (mState != newState) { + ALOGE_IF(DEBUG_OVERLAY, "%s: state changed %s-->%s", + __FUNCTION__, getStateString(mState), getStateString(newState)); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: no state change, state=%s", + __FUNCTION__, getStateString(newState)); + return newov; + } + + switch(mState) + { + case utils::OV_CLOSED: + newov = handle_closed(newState); + break; + case utils::OV_2D_VIDEO_ON_PANEL: + newov = handle_2D_2DPanel(newState, ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL_TV: + newov = handle_2D_2DTV(newState, ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL: + newov = handle_3D_2DPanel(newState, ov); + break; + case utils::OV_3D_VIDEO_ON_3D_PANEL: + newov = handle_3D_3DPanel(newState, ov); + break; + case utils::OV_3D_VIDEO_ON_3D_TV: + newov = handle_3D_3DTV(newState, ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + newov = handle_3D_2DTV(newState, ov); + break; + case utils::OV_UI_MIRROR: + newov = handle_UI_Mirror(newState, ov); + break; + case utils::OV_2D_TRUE_UI_MIRROR: + newov = handle_2D_trueUI_Mirror(newState, ov); + break; + case utils::OV_BYPASS_1_LAYER: + case utils::OV_BYPASS_2_LAYER: + case utils::OV_BYPASS_3_LAYER: + newov = handle_bypass(newState, ov); + break; + default: + ALOGE("%s: unknown state=%d", __FUNCTION__, mState); + } + + // FIXME, how to communicate bad transition? + // Should we have bool returned from transition func? + + return newov; +} + +// Transitions from closed to XXX +inline OverlayImplBase* OverlayState::handle_closed(utils::eOverlayState s) +{ + OverlayImplBase* ov = 0; + switch(s) + { + case utils::OV_CLOSED: + // no state change + break; + case utils::OV_2D_VIDEO_ON_PANEL: + ov = handle_closed_to_xxx(); + break; + case utils::OV_2D_VIDEO_ON_PANEL_TV: + ov = handle_closed_to_xxx(); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL: + ov = handle_closed_to_xxx(); + break; + case utils::OV_3D_VIDEO_ON_3D_PANEL: + ov = handle_closed_to_xxx(); + break; + case utils::OV_3D_VIDEO_ON_3D_TV: + ov = handle_closed_to_xxx(); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + ov = handle_closed_to_xxx(); + break; + case utils::OV_UI_MIRROR: + ov = handle_closed_to_xxx(); + break; + case utils::OV_2D_TRUE_UI_MIRROR: + ov = handle_closed_to_xxx(); + break; + case utils::OV_BYPASS_1_LAYER: + ov = handle_closed_to_xxx(); + break; + case utils::OV_BYPASS_2_LAYER: + ov = handle_closed_to_xxx(); + break; + case utils::OV_BYPASS_3_LAYER: + ov = handle_closed_to_xxx(); + break; + default: + ALOGE("%s: unknown state=%d", __FUNCTION__, s); + } + mState = s; + return ov; +} + +// Transitions from 2D video on 2D panel to XXX +inline OverlayImplBase* OverlayState::handle_2D_2DPanel( + utils::eOverlayState s, + OverlayImplBase* ov) +{ + OverlayImplBase* newov = ov; + switch(s) + { + case utils::OV_CLOSED: + newov = handle_xxx_to_closed(ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL: + // no state change + break; + case utils::OV_2D_VIDEO_ON_PANEL_TV: + newov = handle_xxx_to_2D_2DTV(ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_3D_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_3D_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_UI_MIRROR: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_2D_TRUE_UI_MIRROR: + newov = handle_xxx_to_2D_trueUI_Mirror(ov); + break; + case utils::OV_BYPASS_1_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_2_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_3_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + default: + ALOGE("%s: unknown state=%d", __FUNCTION__, s); + } + mState = s; + return newov; +} + +// Transitions from 2D video on 2D panel and 2D TV to XXX +inline OverlayImplBase* OverlayState::handle_2D_2DTV( + utils::eOverlayState s, + OverlayImplBase* ov) +{ + OverlayImplBase* newov = ov; + switch(s) + { + case utils::OV_CLOSED: + newov = handle_xxx_to_closed(ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL: + newov = handle_xxx_to_2D_2DPanel(ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL_TV: + // no state change + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_3D_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_3D_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_UI_MIRROR: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_2D_TRUE_UI_MIRROR: + newov = handle_xxx_to_2D_trueUI_Mirror(ov); + break; + case utils::OV_BYPASS_1_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_2_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_3_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + default: + ALOGE("%s: unknown state=%d", __FUNCTION__, s); + } + mState = s; + return newov; +} + +// Transitions from 3D video on 2D panel to XXX +inline OverlayImplBase* OverlayState::handle_3D_2DPanel( + utils::eOverlayState s, + OverlayImplBase* ov) +{ + OverlayImplBase* newov = ov; + switch(s) + { + case utils::OV_CLOSED: + newov = handle_xxx_to_closed(ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL: + // no state change + break; + case utils::OV_3D_VIDEO_ON_3D_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_3D_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + newov = handle_xxx_to_3D_2DTV(ov); + break; + case utils::OV_UI_MIRROR: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_2D_TRUE_UI_MIRROR: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_1_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_2_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_3_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + default: + ALOGE("%s: unknown state=%d", __FUNCTION__, s); + } + mState = s; + return newov; +} + +// Transitions from 3D video on 3D panel to XXX +inline OverlayImplBase* OverlayState::handle_3D_3DPanel( + utils::eOverlayState s, + OverlayImplBase* ov) +{ + OverlayImplBase* newov = ov; + switch(s) + { + case utils::OV_CLOSED: + newov = handle_xxx_to_closed(ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_3D_PANEL: + // no state change + break; + case utils::OV_3D_VIDEO_ON_3D_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_UI_MIRROR: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_2D_TRUE_UI_MIRROR: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_1_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_2_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_3_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + default: + ALOGE("%s: unknown state=%d", __FUNCTION__, s); + } + mState = s; + return newov; +} + +// Transitions from 3D video on 3D TV to XXX +inline OverlayImplBase* OverlayState::handle_3D_3DTV( + utils::eOverlayState s, + OverlayImplBase* ov) +{ + OverlayImplBase* newov = ov; + switch(s) + { + case utils::OV_CLOSED: + newov = handle_xxx_to_closed(ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_3D_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_3D_TV: + // no state change + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_UI_MIRROR: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_2D_TRUE_UI_MIRROR: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_1_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_2_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_3_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + default: + ALOGE("%s: unknown state=%d", __FUNCTION__, s); + } + mState = s; + return newov; +} + +// Transitions from 3D video on 2D panel and 2D TV to XXX +inline OverlayImplBase* OverlayState::handle_3D_2DTV( + utils::eOverlayState s, + OverlayImplBase* ov) +{ + OverlayImplBase* newov = ov; + switch(s) + { + case utils::OV_CLOSED: + newov = handle_xxx_to_closed(ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL: + newov = handle_xxx_to_3D_2DPanel(ov); + break; + case utils::OV_3D_VIDEO_ON_3D_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_3D_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + // no state change + break; + case utils::OV_UI_MIRROR: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_2D_TRUE_UI_MIRROR: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_1_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_2_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_3_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + default: + ALOGE("%s: unknown state=%d", __FUNCTION__, s); + } + mState = s; + return newov; +} + +// Transitions from UI mirroring to XXX +inline OverlayImplBase* OverlayState::handle_UI_Mirror(utils::eOverlayState s, + OverlayImplBase* ov) +{ + OverlayImplBase* newov = ov; + switch(s) + { + case utils::OV_CLOSED: + newov = handle_xxx_to_closed(ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_3D_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_3D_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_UI_MIRROR: + // no state change + break; + case utils::OV_2D_TRUE_UI_MIRROR: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_1_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_2_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_3_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + default: + ALOGE("%s: unknown state=%d", __FUNCTION__, s); + } + mState = s; + return newov; +} + +// Transitions from 2D video true UI mirroring (2D video + UI) to XXX +inline OverlayImplBase* OverlayState::handle_2D_trueUI_Mirror(utils::eOverlayState s, + OverlayImplBase* ov) +{ + OverlayImplBase* newov = ov; + switch(s) + { + case utils::OV_CLOSED: + newov = handle_xxx_to_closed(ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL: + newov = handle_xxx_to_2D_2DPanel(ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL_TV: + newov = handle_xxx_to_2D_2DTV(ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_3D_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_3D_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_UI_MIRROR: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_2D_TRUE_UI_MIRROR: + // no state change + break; + case utils::OV_BYPASS_1_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_2_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_3_LAYER: + newov = handle_xxx_to_xxx(ov); + break; + default: + ALOGE("%s: unknown state=%d", __FUNCTION__, s); + } + mState = s; + return newov; +} + +// Transitions from composition bypass to XXX +inline OverlayImplBase* OverlayState::handle_bypass(utils::eOverlayState s, + OverlayImplBase* ov) +{ + OverlayImplBase* newov = ov; + switch(s) + { + case utils::OV_CLOSED: + newov = handle_xxx_to_closed(ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_2D_VIDEO_ON_PANEL_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_3D_PANEL: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_3D_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_UI_MIRROR: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_2D_TRUE_UI_MIRROR: + newov = handle_xxx_to_xxx(ov); + break; + case utils::OV_BYPASS_1_LAYER: + newov = handle_xxx_to_bypass1(ov); + break; + case utils::OV_BYPASS_2_LAYER: + newov = handle_xxx_to_bypass2(ov); + break; + case utils::OV_BYPASS_3_LAYER: + newov = handle_xxx_to_bypass3(ov); + break; + default: + ALOGE("%s: unknown state=%d", __FUNCTION__, s); + } + mState = s; + return newov; +} + + +} // overlay + +#endif // OVERLAY_STATE_H diff --git a/liboverlay/overlayTransitions.cpp b/liboverlay/overlayTransitions.cpp new file mode 100644 index 0000000..45d3720 --- /dev/null +++ b/liboverlay/overlayTransitions.cpp @@ -0,0 +1,503 @@ +/* +* Copyright (c) 2012, 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 "overlayState.h" + +namespace overlay { + +/* + * Transition from any state to 2D video on 2D panel + */ +OverlayImplBase* OverlayState::handle_xxx_to_2D_2DPanel( + OverlayImplBase* ov) +{ + OVASSERT(ov, "%s: ov is null", __FUNCTION__); + ALOGE("%s", __FUNCTION__); + + // Create new ovimpl based on new state + typedef StateTraits NewState; + OverlayImplBase* newov = new NewState::ovimpl; + + //=========================================================== + // For each pipe: + // - If pipe matches, copy from previous into new ovimpl + // - Otherwise open for new and delete from previous ovimpl + //=========================================================== + + // pipe0/rot0 (GenericPipe) + if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_GENERIC) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (GenericPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE0); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe0 (GenericPipe)", __FUNCTION__); + RotatorBase* rot0 = new NewState::rot0; + ov->closePipe(utils::OV_PIPE0); + newov->openPipe(rot0, utils::OV_PIPE0); + } + + // pipe1/rot1 (NullPipe) + if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_NULL) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (NullPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE1); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe1 (NullPipe)", __FUNCTION__); + RotatorBase* rot1 = new NewState::rot1; + ov->closePipe(utils::OV_PIPE1); + newov->openPipe(rot1, utils::OV_PIPE1); + } + + // pipe2/rot2 (NullPipe) + if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_NULL) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (NullPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE2); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe2 (NullPipe)", __FUNCTION__); + RotatorBase* rot2 = new NewState::rot2; + ov->closePipe(utils::OV_PIPE2); + newov->openPipe(rot2, utils::OV_PIPE2); + } + + // All pipes are copied or deleted so no more need for previous ovimpl + delete ov; + ov = 0; + + return newov; +} + +/* + * Transition from any state to 2D video on 2D panel and 2D TV + */ +OverlayImplBase* OverlayState::handle_xxx_to_2D_2DTV( + OverlayImplBase* ov) +{ + OVASSERT(ov, "%s: ov is null", __FUNCTION__); + ALOGE("%s", __FUNCTION__); + + // Create new ovimpl based on new state + typedef StateTraits NewState; + OverlayImplBase* newov = new NewState::ovimpl; + + //=========================================================== + // For each pipe: + // - If pipe matches, copy from previous into new ovimpl + // - Otherwise open for new and delete from previous ovimpl + //=========================================================== + + // pipe0/rot0 (GenericPipe) + if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_GENERIC) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (GenericPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE0); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe0 (GenericPipe)", __FUNCTION__); + RotatorBase* rot0 = new NewState::rot0; + ov->closePipe(utils::OV_PIPE0); + newov->openPipe(rot0, utils::OV_PIPE0); + } + + // pipe1/rot1 (HdmiPipe) + if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_HDMI) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (HdmiPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE1); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe1 (HdmiPipe)", __FUNCTION__); + RotatorBase* rot1 = new NewState::rot1; + ov->closePipe(utils::OV_PIPE1); + newov->openPipe(rot1, utils::OV_PIPE1); + } + + // pipe2/rot2 (NullPipe) + if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_NULL) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (NullPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE2); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe2 (NullPipe)", __FUNCTION__); + RotatorBase* rot2 = new NewState::rot2; + ov->closePipe(utils::OV_PIPE2); + newov->openPipe(rot2, utils::OV_PIPE2); + } + + // All pipes are copied or deleted so no more need for previous ovimpl + delete ov; + ov = 0; + + return newov; +} + +/* + * Transition from any state to 3D video on 2D panel + */ +OverlayImplBase* OverlayState::handle_xxx_to_3D_2DPanel( + OverlayImplBase* ov) +{ + OVASSERT(ov, "%s: ov is null", __FUNCTION__); + ALOGE("%s", __FUNCTION__); + + // Create new ovimpl based on new state + typedef StateTraits NewState; + OverlayImplBase* newov = new NewState::ovimpl; + + //=========================================================== + // For each pipe: + // - If pipe matches, copy from previous into new ovimpl + // - Otherwise open for new and delete from previous ovimpl + //=========================================================== + + // pipe0/rot0 (M3DPrimaryPipe) + if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_M3D_PRIMARY) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (M3DPrimaryPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE0); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe0 (M3DPrimaryPipe)", __FUNCTION__); + RotatorBase* rot0 = new NewState::rot0; + ov->closePipe(utils::OV_PIPE0); + newov->openPipe(rot0, utils::OV_PIPE0); + } + + // pipe1/rot1 (NullPipe) + if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_NULL) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (NullPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE1); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe1 (NullPipe)", __FUNCTION__); + RotatorBase* rot1 = new NewState::rot1; + ov->closePipe(utils::OV_PIPE1); + newov->openPipe(rot1, utils::OV_PIPE1); + } + + // pipe2/rot2 (NullPipe) + if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_NULL) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (NullPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE2); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe2 (NullPipe)", __FUNCTION__); + RotatorBase* rot2 = new NewState::rot2; + ov->closePipe(utils::OV_PIPE2); + newov->openPipe(rot2, utils::OV_PIPE2); + } + + // All pipes are copied or deleted so no more need for previous ovimpl + delete ov; + ov = 0; + + return newov; +} + +/* + * Transition from any state to 3D video on 2D panel and 2D TV + */ +OverlayImplBase* OverlayState::handle_xxx_to_3D_2DTV( + OverlayImplBase* ov) +{ + OVASSERT(ov, "%s: ov is null", __FUNCTION__); + ALOGE("%s", __FUNCTION__); + + // Create new ovimpl based on new state + typedef StateTraits NewState; + OverlayImplBase* newov = new NewState::ovimpl; + + //=========================================================== + // For each pipe: + // - If pipe matches, copy from previous into new ovimpl + // - Otherwise open for new and delete from previous ovimpl + //=========================================================== + + // pipe0/rot0 (M3DPrimaryPipe) + if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_M3D_PRIMARY) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (M3DPrimaryPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE0); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe0 (M3DPrimaryPipe)", __FUNCTION__); + RotatorBase* rot0 = new NewState::rot0; + ov->closePipe(utils::OV_PIPE0); + newov->openPipe(rot0, utils::OV_PIPE0); + } + + // pipe1/rot1 (M3DExtPipe) + if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_M3D_EXTERNAL) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (M3DExtPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE1); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe1 (M3DExtPipe)", __FUNCTION__); + RotatorBase* rot1 = new NewState::rot1; + ov->closePipe(utils::OV_PIPE1); + newov->openPipe(rot1, utils::OV_PIPE1); + } + + // pipe2/rot2 (NullPipe) + if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_NULL) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (NullPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE2); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe2 (NullPipe)", __FUNCTION__); + RotatorBase* rot2 = new NewState::rot2; + ov->closePipe(utils::OV_PIPE2); + newov->openPipe(rot2, utils::OV_PIPE2); + } + + // All pipes are copied or deleted so no more need for previous ovimpl + delete ov; + ov = 0; + + return newov; +} + +/* + * Transition from any state to 2D true UI mirroring (2D video + UI) + */ +OverlayImplBase* OverlayState::handle_xxx_to_2D_trueUI_Mirror( + OverlayImplBase* ov) +{ + OVASSERT(ov, "%s: ov is null", __FUNCTION__); + ALOGE("%s", __FUNCTION__); + + // Create new ovimpl based on new state + typedef StateTraits NewState; + OverlayImplBase* newov = new NewState::ovimpl; + + //=========================================================== + // For each pipe: + // - If pipe matches, copy from previous into new ovimpl + // - Otherwise open for new and delete from previous ovimpl + //=========================================================== + + // pipe0/rot0 (GenericPipe) + if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_GENERIC) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (GenericPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE0); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe0 (GenericPipe)", __FUNCTION__); + RotatorBase* rot0 = new NewState::rot0; + ov->closePipe(utils::OV_PIPE0); + newov->openPipe(rot0, utils::OV_PIPE0); + } + + // pipe1/rot1 (HdmiPipe) + if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_HDMI) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (HdmiPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE1); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe1 (HdmiPipe)", __FUNCTION__); + RotatorBase* rot1 = new NewState::rot1; + ov->closePipe(utils::OV_PIPE1); + newov->openPipe(rot1, utils::OV_PIPE1); + } + + // pipe2/rot2 (UIMirrorPipe) + if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_UI_MIRROR) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (UIMirrorPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE2); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe2 (UIMirrorPipe)", __FUNCTION__); + RotatorBase* rot2 = new NewState::rot2; + ov->closePipe(utils::OV_PIPE2); + newov->openPipe(rot2, utils::OV_PIPE2); + } + + // All pipes are copied or deleted so no more need for previous ovimpl + delete ov; + ov = 0; + + return newov; +} + +/* + * Transitions from any state to 1 layer composition bypass + */ +OverlayImplBase* OverlayState::handle_xxx_to_bypass1(OverlayImplBase* ov) +{ + OVASSERT(ov, "%s: ov is null", __FUNCTION__); + ALOGE("%s", __FUNCTION__); + + // Create new ovimpl based on new state + typedef StateTraits NewState; + OverlayImplBase* newov = new NewState::ovimpl; + + //=========================================================== + // For each pipe: + // - If pipe matches, copy from previous into new ovimpl + // - Otherwise open for new and delete from previous ovimpl + //=========================================================== + + // pipe0/rot0 (BypassPipe) + if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_BYPASS) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (BypassPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE0); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe0 (BypassPipe)", __FUNCTION__); + RotatorBase* rot0 = new NewState::rot0; + ov->closePipe(utils::OV_PIPE0); + newov->openPipe(rot0, utils::OV_PIPE0); + } + + // pipe1/rot1 (NullPipe) + if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_NULL) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (NullPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE1); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe1 (NullPipe)", __FUNCTION__); + RotatorBase* rot1 = new NewState::rot1; + ov->closePipe(utils::OV_PIPE1); + newov->openPipe(rot1, utils::OV_PIPE1); + } + + // pipe2/rot2 (NullPipe) + if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_NULL) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (NullPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE2); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe2 (NullPipe)", __FUNCTION__); + RotatorBase* rot2 = new NewState::rot2; + ov->closePipe(utils::OV_PIPE2); + newov->openPipe(rot2, utils::OV_PIPE2); + } + + // All pipes are copied or deleted so no more need for previous ovimpl + delete ov; + ov = 0; + + return newov; +} + +/* + * Transitions from any state to 2 layers composition bypass + */ +OverlayImplBase* OverlayState::handle_xxx_to_bypass2(OverlayImplBase* ov) +{ + OVASSERT(ov, "%s: ov is null", __FUNCTION__); + ALOGE("%s", __FUNCTION__); + + // Create new ovimpl based on new state + typedef StateTraits NewState; + OverlayImplBase* newov = new NewState::ovimpl; + + //=========================================================== + // For each pipe: + // - If pipe matches, copy from previous into new ovimpl + // - Otherwise open for new and delete from previous ovimpl + //=========================================================== + + // pipe0/rot0 (BypassPipe) + if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_BYPASS) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (BypassPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE0); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe0 (BypassPipe)", __FUNCTION__); + RotatorBase* rot0 = new NewState::rot0; + ov->closePipe(utils::OV_PIPE0); + newov->openPipe(rot0, utils::OV_PIPE0); + } + + // pipe1/rot1 (BypassPipe) + if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_BYPASS) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (BypassPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE1); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe1 (BypassPipe)", __FUNCTION__); + RotatorBase* rot1 = new NewState::rot1; + ov->closePipe(utils::OV_PIPE1); + newov->openPipe(rot1, utils::OV_PIPE1); + } + + // pipe2/rot2 (NullPipe) + if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_NULL) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (NullPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE2); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe2 (NullPipe)", __FUNCTION__); + RotatorBase* rot2 = new NewState::rot2; + ov->closePipe(utils::OV_PIPE2); + newov->openPipe(rot2, utils::OV_PIPE2); + } + + // All pipes are copied or deleted so no more need for previous ovimpl + delete ov; + ov = 0; + + return newov; +} + +/* + * Transitions from any state to 3 layers composition bypass + */ +OverlayImplBase* OverlayState::handle_xxx_to_bypass3(OverlayImplBase* ov) +{ + OVASSERT(ov, "%s: ov is null", __FUNCTION__); + ALOGE("%s", __FUNCTION__); + + // Create new ovimpl based on new state + typedef StateTraits NewState; + OverlayImplBase* newov = new NewState::ovimpl; + + //=========================================================== + // For each pipe: + // - If pipe matches, copy from previous into new ovimpl + // - Otherwise open for new and delete from previous ovimpl + //=========================================================== + + // pipe0/rot0 (BypassPipe) + if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_BYPASS) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (BypassPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE0); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe0 (BypassPipe)", __FUNCTION__); + RotatorBase* rot0 = new NewState::rot0; + ov->closePipe(utils::OV_PIPE0); + newov->openPipe(rot0, utils::OV_PIPE0); + } + + // pipe1/rot1 (BypassPipe) + if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_BYPASS) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (BypassPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE1); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe1 (BypassPipe)", __FUNCTION__); + RotatorBase* rot1 = new NewState::rot1; + ov->closePipe(utils::OV_PIPE1); + newov->openPipe(rot1, utils::OV_PIPE1); + } + + // pipe2/rot2 (BypassPipe) + if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_BYPASS) { + ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (BypassPipe)", __FUNCTION__); + newov->copyOvPipe(ov, utils::OV_PIPE2); + } else { + ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe2 (BypassPipe)", __FUNCTION__); + RotatorBase* rot2 = new NewState::rot2; + ov->closePipe(utils::OV_PIPE2); + newov->openPipe(rot2, utils::OV_PIPE2); + } + + // All pipes are copied or deleted so no more need for previous ovimpl + delete ov; + ov = 0; + + return newov; +} + +} // overlay diff --git a/liboverlay/overlayUtils.cpp b/liboverlay/overlayUtils.cpp new file mode 100644 index 0000000..38e3ab2 --- /dev/null +++ b/liboverlay/overlayUtils.cpp @@ -0,0 +1,337 @@ +/* +* Copyright (c) 2011-2012, 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 "gralloc_priv.h" +#include "fb_priv.h" +#include "overlayUtils.h" +#include "mdpWrapper.h" + +// just a helper static thingy +namespace { +struct IOFile { + IOFile(const char* s, const char* mode) : fp(0) { + fp = ::fopen(s, mode); + if(!fp) { + ALOGE("Failed open %s", s); + } + } + template + size_t read(T& r, size_t elem) { + if(fp) { + return ::fread(&r, sizeof(T), elem, fp); + } + return 0; + } + size_t write(const char* s, uint32_t val) { + if(fp) { + return ::fprintf(fp, s, val); + } + return 0; + } + bool valid() const { return fp != 0; } + ~IOFile() { + if(fp) ::fclose(fp); + fp=0; + } + FILE* fp; +}; +} + +namespace overlay { + +//----------From class Res ------------------------------ +const char* const Res::devTemplate = "/dev/graphics/fb%u"; +const char* const Res::rotPath = "/dev/msm_rotator"; +const char* const Res::format3DFile = + "/sys/class/graphics/fb1/format_3d"; +const char* const Res::edid3dInfoFile = + "/sys/class/graphics/fb1/3d_present"; +const char* const Res::barrierFile = + "/sys/devices/platform/mipi_novatek.0/enable_3d_barrier"; +//-------------------------------------------------------- + + + +namespace utils { +//-------------------------------------------------------- +FrameBufferInfo::FrameBufferInfo() { + mFBWidth = 0; + mFBHeight = 0; + mBorderFillSupported = false; + + OvFD mFd; + + // Use open defined in overlayFD file to open fd for fb0 + if(!overlay::open(mFd, 0, Res::devTemplate)) { + ALOGE("FrameBufferInfo: failed to open fd"); + return; + } + + if (!mFd.valid()) { + ALOGE("FrameBufferInfo: FD not valid"); + return; + } + + fb_var_screeninfo vinfo; + if (!mdp_wrapper::getVScreenInfo(mFd.getFD(), vinfo)) { + ALOGE("FrameBufferInfo: failed getVScreenInfo on fb0"); + mFd.close(); + return; + } + + mdp_overlay ov; + memset(&ov, 0, sizeof(ov)); + ov.id = 1; + if (!mdp_wrapper::getOverlay(mFd.getFD(), ov)) { + ALOGE("FrameBufferInfo: failed getOverlay on fb0"); + mFd.close(); + return; + } + + mFd.close(); + + mFBWidth = vinfo.xres; + mFBHeight = vinfo.yres; + mBorderFillSupported = (ov.flags & MDP_BORDERFILL_SUPPORTED) ? + true : false; +} + +FrameBufferInfo* FrameBufferInfo::getInstance() { + if (!sFBInfoInstance) { + sFBInfoInstance = new FrameBufferInfo; + } + return sFBInfoInstance; +} + +int FrameBufferInfo::getWidth() const { + return mFBWidth; +} + +int FrameBufferInfo::getHeight() const { + return mFBHeight; +} + +bool FrameBufferInfo::supportTrueMirroring() const { + return mBorderFillSupported; +} + +//-------------------------------------------------------- +uint32_t getSize(const Whf& whf) { + int aligned_height=0, pitch=0; + + uint32_t size = whf.w * whf.h; + switch (whf.format) { + case MDP_RGBA_8888: + case MDP_BGRA_8888: + case MDP_RGBX_8888: + size *= 4; + break; + case MDP_RGB_565: + case MDP_Y_CBCR_H2V1: + size *= 2; + break; + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + size = (size * 3) / 2; + break; + case MDP_Y_CRCB_H2V2_TILE: + case MDP_Y_CBCR_H2V2_TILE: + aligned_height = align(whf.h , 32); + pitch = align(whf.w, 128); + size = pitch * aligned_height; + size = align(size, 8192); + + aligned_height = align(whf.h >> 1, 32); + size += pitch * aligned_height; + size = align(size, 8192); + break; + default: + ALOGE("getSize unknown format %d", whf.format); + return 0; + } + return size; +} + +int getMdpFormat(int format) { + switch (format) { + case HAL_PIXEL_FORMAT_RGBA_8888 : + return MDP_RGBA_8888; + case HAL_PIXEL_FORMAT_BGRA_8888: + return MDP_BGRA_8888; + case HAL_PIXEL_FORMAT_RGB_565: + return MDP_RGB_565; + case HAL_PIXEL_FORMAT_RGBX_8888: + return MDP_RGBX_8888; + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + return MDP_Y_CBCR_H2V1; + case HAL_PIXEL_FORMAT_YCrCb_422_SP: + return MDP_Y_CRCB_H2V1; + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + return MDP_Y_CBCR_H2V2; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + return MDP_Y_CRCB_H2V2; + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: + return MDP_Y_CBCR_H2V2_TILE; + case HAL_PIXEL_FORMAT_YV12: + return MDP_Y_CR_CB_H2V2; + default: + ALOGE("Error getMdpFormat format=%d", format); + return -1; + } + // not reached + return -1; +} + +bool isHDMIConnected () { + char value[PROPERTY_VALUE_MAX] = {0}; + property_get("hw.hdmiON", value, "0"); + int isHDMI = atoi(value); + return isHDMI ? true : false; +} + +bool is3DTV() { + char is3DTV = '0'; + IOFile fp(Res::edid3dInfoFile, "r"); + (void)fp.read(is3DTV, 1); + ALOGI("3DTV EDID flag: %d", is3DTV); + return (is3DTV == '0') ? false : true; +} + +bool isPanel3D() { + OvFD fd; + if(!overlay::open(fd, 0 /*fb*/, Res::devTemplate)){ + ALOGE("isPanel3D Can't open framebuffer 0"); + return false; + } + fb_fix_screeninfo finfo; + if(!mdp_wrapper::getFScreenInfo(fd.getFD(), finfo)) { + ALOGE("isPanel3D read fb0 failed"); + } + fd.close(); + return (FB_TYPE_3D_PANEL == finfo.type) ? true : false; +} + +bool usePanel3D() { + if(!isPanel3D()) + return false; + char value[PROPERTY_VALUE_MAX]; + property_get("persist.user.panel3D", value, "0"); + int usePanel3D = atoi(value); + return usePanel3D ? true : false; +} + +bool send3DInfoPacket (uint32_t format3D) { + IOFile fp(Res::format3DFile, "wb"); + (void)fp.write("%d", format3D); + if(!fp.valid()) { + ALOGE("send3DInfoPacket: no sysfs entry for setting 3d mode"); + return false; + } + return true; +} + +bool enableBarrier (uint32_t orientation) { + IOFile fp(Res::barrierFile, "wb"); + (void)fp.write("%d", orientation); + if(!fp.valid()) { + ALOGE("enableBarrier no sysfs entry for " + "enabling barriers on 3D panel"); + return false; + } + return true; +} + +uint32_t getS3DFormat(uint32_t fmt) { + // The S3D is part of the HAL_PIXEL_FORMAT_YV12 value. Add + // an explicit check for the format + if (fmt == HAL_PIXEL_FORMAT_YV12) { + return 0; + } + uint32_t fmt3D = format3D(fmt); + uint32_t fIn3D = format3DInput(fmt3D); // MSB 2 bytes - inp + uint32_t fOut3D = format3DOutput(fmt3D); // LSB 2 bytes - out + fmt3D = fIn3D | fOut3D; + if (!fIn3D) { + fmt3D |= fOut3D << SHIFT_TOT_3D; //Set the input format + } + if (!fOut3D) { + switch (fIn3D) { + case HAL_3D_IN_SIDE_BY_SIDE_L_R: + case HAL_3D_IN_SIDE_BY_SIDE_R_L: + // For all side by side formats, set the output + // format as Side-by-Side i.e 0x1 + fmt3D |= HAL_3D_IN_SIDE_BY_SIDE_L_R >> SHIFT_TOT_3D; + break; + default: + fmt3D |= fIn3D >> SHIFT_TOT_3D; //Set the output format + } + } + return fmt3D; +} + +void normalizeCrop(uint32_t& xy, uint32_t& wh) { + if (xy & 0x0001) { + // x or y is odd, increment it's value + xy += 1; + // Since we've incremented x(y), we need to decrement + // w(h) accordingly + if (wh & 0x0001) { + // w or h is odd, decrement it by 1, to make it even + even_out(wh); + } else { + // w(h) is already even, hence we decrement by 2 + wh -=2; + } + } else { + even_out(wh); + } +} + +void scale(mdp_overlay& ov) +{ + /* Scaling of upto a max of 8 times supported */ + overlay::utils::Dim dst(overlay::utils::getDstRectDim(ov)); + overlay::utils::Dim src(overlay::utils::getSrcRectDim(ov)); + if(dst.w >(src.w * overlay::utils::HW_OV_MAGNIFICATION_LIMIT)) { + dst.w = overlay::utils::HW_OV_MAGNIFICATION_LIMIT * src.w; + } + if(dst.h >(src.h * overlay::utils::HW_OV_MAGNIFICATION_LIMIT)) { + dst.h = overlay::utils::HW_OV_MAGNIFICATION_LIMIT * src.h; + } + + setDstRectDim(dst, ov); +} + +} // utils + +} // overlay diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h new file mode 100644 index 0000000..089d3fb --- /dev/null +++ b/liboverlay/overlayUtils.h @@ -0,0 +1,1112 @@ +/* +* Copyright (c) 2011-2012, 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 OVERLAY_UTILS_H +#define OVERLAY_UTILS_H + +#include // ALOGE, etc +#include +#include // open, O_RDWR, etc +#include +#include // buffer_handle_t +#include // MDP_OV_PLAY_NOWAIT etc ... +#include +#include +#include +#include +#include +#include + +/* +* +* Collection of utilities functions/structs/enums etc... +* +* */ + +// comment that out if you want to remove asserts +// or put it as -D in Android.mk. your choice. +#define OVERLAY_HAS_ASSERT + +#ifdef OVERLAY_HAS_ASSERT +# define OVASSERT(x, ...) if(!(x)) { ALOGE(__VA_ARGS__); abort(); } +#else +# define OVASSERT(x, ...) ALOGE_IF(!(x), __VA_ARGS__) +#endif // OVERLAY_HAS_ASSERT + +#define DEBUG_OVERLAY 0 +#define PROFILE_OVERLAY 0 + +namespace overlay { + +// fwd +class Overlay; + +namespace utils { +struct Whf; +struct Dim; +template + inline void even_out(T& x) { if (x & 0x0001) --x; } + +inline uint32_t getBit(uint32_t x, uint32_t mask) { + return (x & mask); +} + +inline uint32_t setBit(uint32_t x, uint32_t mask) { + return (x | mask); +} + +inline uint32_t clrBit(uint32_t x, uint32_t mask) { + return (x & ~mask); +} + +/* Utility class to help avoid copying instances by making the copy ctor +* and assignment operator private +* +* Usage: +* * class SomeClass : utils::NoCopy {...}; +*/ +class NoCopy { +protected: + NoCopy(){} + ~NoCopy() {} +private: + NoCopy(const NoCopy&); + const NoCopy& operator=(const NoCopy&); +}; + +/* +* Utility class to query the framebuffer info for primary display +* +* Usage: +* Outside of functions: +* utils::FrameBufferInfo* utils::FrameBufferInfo::sFBInfoInstance = 0; +* Inside functions: +* utils::FrameBufferInfo::getInstance()->supportTrueMirroring() +*/ +class FrameBufferInfo { + +public: + /* ctor init */ + explicit FrameBufferInfo(); + + /* Gets an instance if one does not already exist */ + static FrameBufferInfo* getInstance(); + + /* Gets width of primary framebuffer */ + int getWidth() const; + + /* Gets height of primary framebuffer */ + int getHeight() const; + + /* Indicates whether true mirroring is supported */ + bool supportTrueMirroring() const; + +private: + int mFBWidth; + int mFBHeight; + bool mBorderFillSupported; + static FrameBufferInfo *sFBInfoInstance; +}; + +/* 3D related utils, defines etc... + * The compound format passed to the overlay is + * ABCCC where A is the input 3D format + * B is the output 3D format + * CCC is the color format e.g YCbCr420SP YCrCb420SP etc */ +enum { SHIFT_OUT_3D = 12, + SHIFT_TOT_3D = 16 }; +enum { INPUT_3D_MASK = 0xFFFF0000, + OUTPUT_3D_MASK = 0x0000FFFF }; +enum { BARRIER_LAND = 1, + BARRIER_PORT = 2 }; + +inline uint32_t format3D(uint32_t x) { return x & 0xFF000; } +inline uint32_t colorFormat(uint32_t x) { return x & 0xFFF; } +inline uint32_t format3DOutput(uint32_t x) { + return (x & 0xF000) >> SHIFT_OUT_3D; } +inline uint32_t format3DInput(uint32_t x) { return x & 0xF0000; } +uint32_t getColorFormat(uint32_t format); + +bool isHDMIConnected (); +bool is3DTV(); +bool isPanel3D(); +bool usePanel3D(); +bool send3DInfoPacket (uint32_t fmt); +bool enableBarrier (uint32_t orientation); +uint32_t getS3DFormat(uint32_t fmt); +template + bool getPositionS3D(const Whf& whf, Dim& out); +template + bool getCropS3D(const Dim& in, Dim& out, uint32_t fmt); +template + void swapWidthHeight(Type& width, Type& height); + +struct Dim { + Dim () : x(0), y(0), + w(0), h(0), + o(0) {} + Dim(uint32_t _x, uint32_t _y, uint32_t _w, uint32_t _h) : + x(_x), y(_y), + w(_w), h(_h) {} + Dim(uint32_t _x, uint32_t _y, uint32_t _w, uint32_t _h, uint32_t _o) : + x(_x), y(_y), + w(_w), h(_h), + o(_o) {} + bool check(uint32_t _w, uint32_t _h) const { + return (x+w <= _w && y+h <= _h); + + } + + bool operator==(const Dim& d) const { + return d.x == x && d.y == y && + d.w == w && d.h == h && + d.o == o; + } + + bool operator!=(const Dim& d) const { + return !operator==(d); + } + + void even_out() { + utils::even_out(x); + utils::even_out(y); + utils::even_out(w); + utils::even_out(h); + } + + void dump() const; + uint32_t x; + uint32_t y; + uint32_t w; + uint32_t h; + uint32_t o; +}; + +// TODO have Whfz + +struct Whf { + Whf() : w(0), h(0), format(0), size(0) {} + Whf(uint32_t wi, uint32_t he, uint32_t f) : + w(wi), h(he), format(f), size(0) {} + Whf(uint32_t wi, uint32_t he, uint32_t f, uint32_t s) : + w(wi), h(he), format(f), size(s) {} + // FIXME not comparing size at the moment + bool operator==(const Whf& whf) const { + return whf.w == w && whf.h == h && + whf.format == format; + } + bool operator!=(const Whf& whf) const { + return !operator==(whf); + } + void dump() const; + uint32_t w; + uint32_t h; + // FIXME need to be int32_t ? + uint32_t format; + uint32_t size; +}; + +enum { MAX_PATH_LEN = 256 }; + +enum eParams { + OVERLAY_DITHER, + OVERLAY_TRANSFORM, + OVERLAY_TRANSFORM_UI +}; + +struct Params{ + Params(eParams p, int v) : param(p), value(v) {} + eParams param; + int value; +}; + + +/** + * Rotator flags: not to be confused with orientation flags. + * Ususally, you want to open the rotator to make sure it is + * ready for business. + * ROT_FLAG_DISABLED: Rotator would not kick in. (ioctl will emit errors). + * ROT_FLAG_ENABLED: and when rotation is needed. + * (prim video playback) + * (UI mirroring on HDMI w/ 0 degree rotator. - just memcpy) + * In HDMI UI mirroring, rotator is always used. + * Even when w/o orienation change on primary, + * we do 0 rotation on HDMI and using rotator buffers. + * That is because we might see tearing otherwise. so + * we use another buffer (rotator). + * When a simple video playback on HDMI, no rotator is being used.(null r). + * */ +enum eRotFlags { + ROT_FLAG_DISABLED = 0, + ROT_FLAG_ENABLED = 1 // needed in rot +}; + +/* Used for rotator open. + * FIXME that is default, might be configs */ +enum { ROT_NUM_BUFS = 2 }; + +/* Wait/No wait for waiting for vsync + * WAIT - wait for vsync, ignore fb (no need to compose w/ fb) + * NO_WAIT - do not wait for vsync and return immediatly since + * we need to run composition code */ +enum eWait { + WAIT, + NO_WAIT +}; + +/* The values for is_fg flag for control alpha and transp + * IS_FG_OFF means is_fg = 0 + * IS_FG_SET means is_fg = 1 + */ +enum eIsFg { + IS_FG_OFF = 0, + IS_FG_SET = 1 +}; + +/* + * Various mdp flags like PIPE SHARE, DEINTERLACE etc... + * kernel/common/linux/msm_mdp.h + * INTERLACE_MASK: hardware/qcom/display/libgralloc/badger/fb_priv.h + * */ +enum eMdpFlags { + OV_MDP_FLAGS_NONE = 0, + OV_MDP_PIPE_SHARE = MDP_OV_PIPE_SHARE, + OV_MDP_DEINTERLACE = MDP_DEINTERLACE, + OV_MDP_PLAY_NOWAIT = MDP_OV_PLAY_NOWAIT, + OV_MDP_SECURE_OVERLAY_SESSION = MDP_SECURE_OVERLAY_SESSION +}; + +enum eOverlayPipeType { + OV_PIPE_TYPE_NULL, + OV_PIPE_TYPE_BYPASS, + OV_PIPE_TYPE_GENERIC, + OV_PIPE_TYPE_HDMI, + OV_PIPE_TYPE_M3D_EXTERNAL, + OV_PIPE_TYPE_M3D_PRIMARY, + OV_PIPE_TYPE_RGB, + OV_PIPE_TYPE_S3D_EXTERNAL, + OV_PIPE_TYPE_S3D_PRIMARY, + OV_PIPE_TYPE_UI_MIRROR +}; + +enum eZorder { + ZORDER_0, + ZORDER_1, + ZORDER_2, + Z_SYSTEM_ALLOC = 0xFFFF +}; + +enum eMdpPipeType { + OV_MDP_PIPE_RGB, + OV_MDP_PIPE_VG +}; + +/* Corresponds to pipes in eDest */ +enum eChannel { + CHANNEL_0, + CHANNEL_1, + CHANNEL_2 +}; + +// Max pipes via overlay (VG0, VG1, RGB1) +enum { MAX_PIPES = 3 }; + +/* Used to identify destination channels and + * also 3D channels e.g. when in 3D mode with 2 + * pipes opened and it is used in get crop/pos 3D + * + * PLEASE NOTE : DO NOT USE eDest FOR ARRAYS + * i.e. args[OV_PIPE1] since it is a BIT MASK + * use CHANNELS enum instead. Each OV_PIPEX is + * not specific to a display (primary/external). + * */ +enum eDest { + OV_PIPE0 = 1 << 0, + OV_PIPE1 = 1 << 1, + OV_PIPE2 = 1 << 2, + OV_PIPE_ALL = (OV_PIPE0 | OV_PIPE1 | OV_PIPE2) +}; + +/* values for copybit_set_parameter(OVERLAY_TRANSFORM) */ +enum eTransform { + /* No rot */ + OVERLAY_TRANSFORM_0 = 0x0, + /* flip source image horizontally */ + OVERLAY_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H, + /* flip source image vertically */ + OVERLAY_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V, + /* rotate source image 90 degrees */ + OVERLAY_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90, + /* rotate source image 180 degrees + * It is basically bit-or-ed H | V == 0x3 */ + OVERLAY_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180, + /* rotate source image 270 degrees + * Basically 180 | 90 == 0x7 */ + OVERLAY_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270, + /* rotate invalid like in Transform.h */ + OVERLAY_TRANSFORM_INV = 0x80 +}; + +/* offset and fd are play info */ +struct PlayInfo { + PlayInfo() : fd(-1), offset(0) {} + PlayInfo(int _fd, uint32_t _offset) : + fd(_fd), offset(_offset) {} + bool operator==(const PlayInfo& p) { + return (fd == p.fd && offset == p.offset); + } + int fd; + uint32_t offset; +}; + +// Used to consolidate pipe params +struct PipeArgs { + PipeArgs() : mdpFlags(OV_MDP_FLAGS_NONE), + orientation(OVERLAY_TRANSFORM_0), + wait(NO_WAIT), + zorder(Z_SYSTEM_ALLOC), + isFg(IS_FG_OFF), + rotFlags(ROT_FLAG_DISABLED){ + } + + PipeArgs(eMdpFlags f, eTransform o, + Whf _whf, eWait w, + eZorder z, eIsFg fg, eRotFlags r) : + mdpFlags(f), + orientation(o), + whf(_whf), + wait(w), + zorder(z), + isFg(fg), + rotFlags(r) { + } + + eMdpFlags mdpFlags; // for mdp_overlay flags PIPE_SHARE, NO_WAIT, etc + eTransform orientation; // FIXME docs + Whf whf; + eWait wait; // flags WAIT/NO_WAIT + eZorder zorder; // stage number + eIsFg isFg; // control alpha & transp + eRotFlags rotFlags; + PlayInfo play; +}; + +enum eOverlayState{ + /* No pipes from overlay open */ + OV_CLOSED = 0, + + /* 2D Video */ + OV_2D_VIDEO_ON_PANEL, + OV_2D_VIDEO_ON_PANEL_TV, + + /* 3D Video on one display (panel or TV) */ + OV_3D_VIDEO_ON_2D_PANEL, + OV_3D_VIDEO_ON_3D_PANEL, + OV_3D_VIDEO_ON_3D_TV, + + /* 3D Video on two displays (panel and TV) */ + OV_3D_VIDEO_ON_2D_PANEL_2D_TV, + + /* UI Mirroring */ + OV_UI_MIRROR, + OV_2D_TRUE_UI_MIRROR, + OV_M3D_TRUE_UI_MIRROR, // Not yet supported + + /* Composition Bypass */ + OV_BYPASS_1_LAYER, + OV_BYPASS_2_LAYER, + OV_BYPASS_3_LAYER, +}; + +inline void setMdpFlags(eMdpFlags& f, eMdpFlags v) { + f = static_cast(setBit(f, v)); +} + +inline void clearMdpFlags(eMdpFlags& f, eMdpFlags v) { + f = static_cast(clrBit(f, v)); +} + +// fb 0/1/2 +enum { FB0, FB1, FB2 }; + +//Panels could be categorized as primary and external +enum { PRIMARY, EXTERNAL }; + +//External Panels could use HDMI or WFD +enum { + HDMI = 1, + WFD = 2 +}; + +static int sExtType = HDMI; //HDMI or WFD + +//Set by client as HDMI/WFD +static inline void setExtType(const int& type) { + if(type != HDMI || type != WFD) { + ALOGE("%s: Unrecognized type %d", __func__, type); + return; + } + sExtType = type; +} + +//Return External panel type set by client. +static inline int getExtType() { + return sExtType; +} + +//Gets the FB number for the external type. +//As of now, HDMI always has fb1, WFD could use fb1 or fb2 +//Assumes Ext type set by setExtType() from client. +static int getFBForPanel(int panel) { // PRIMARY OR EXTERNAL + switch(panel) { + case PRIMARY: return FB0; + break; + case EXTERNAL: + switch(getExtType()) { + case HDMI: return FB1; + break; + case WFD: return FB2;//Hardcoding fb2 for wfd. Will change. + break; + } + break; + default: + ALOGE("%s: Unrecognized PANEL category %d", __func__, panel); + break; + } + return -1; +} + +// number of rgb pipes bufs (max) +// 2 for rgb0/1 double bufs +enum { RGB_PIPE_NUM_BUFS = 2 }; + +struct ScreenInfo { + ScreenInfo() : mFBWidth(0), + mFBHeight(0), + mFBbpp(0), + mFBystride(0) {} + void dump(const char* const s) const; + uint32_t mFBWidth; + uint32_t mFBHeight; + uint32_t mFBbpp; + uint32_t mFBystride; +}; + +int getMdpFormat(int format); +int getRotOutFmt(uint32_t format); +/* flip is upside down and such. V, H flip + * rotation is 90, 180 etc + * It returns MDP related enum/define that match rot+flip*/ +int getMdpOrient(eTransform rotation); +uint32_t getSize(const Whf& whf); +uint32_t getSizeByMdp(const Whf& whf); +const char* getFormatString(uint32_t format); +const char* getStateString(eOverlayState state); + +inline int setWait(eWait wait, int flags) { + return (wait == WAIT) ? + flags &= ~MDP_OV_PLAY_NOWAIT : + flags |= MDP_OV_PLAY_NOWAIT; +} +/* possible overlay formats libhardware/include/hardware/hardware.h */ +enum eFormat { + OVERLAY_FORMAT_RGBA_8888 = HAL_PIXEL_FORMAT_RGBA_8888, + OVERLAY_FORMAT_RGB_565 = HAL_PIXEL_FORMAT_RGB_565, + OVERLAY_FORMAT_BGRA_8888 = HAL_PIXEL_FORMAT_BGRA_8888, + OVERLAY_FORMAT_YCbYCr_422_I = 0x14, + OVERLAY_FORMAT_CbYCrY_422_I = 0x16, + OVERLAY_FORMAT_DEFAULT = 99 // The actual color format is + // determined by the overlay +}; + +// Cannot use HW_OVERLAY_MAGNIFICATION_LIMIT, since at the time +// of integration, HW_OVERLAY_MAGNIFICATION_LIMIT was a define +enum { HW_OV_MAGNIFICATION_LIMIT = 20, + HW_OV_MINIFICATION_LIMIT = 8 +}; + +inline bool rotated(int orie) { + return (orie == OVERLAY_TRANSFORM_ROT_90 || + orie == OVERLAY_TRANSFORM_ROT_270); +} + +/* used by crop funcs in order to + * normalizes the crop values to be all even */ +void normalizeCrop(uint32_t& xy, uint32_t& wh); + +template + inline void memset0(T& t) { ::memset(&t, 0, sizeof(T)); } + +template + inline void swapOVRotWidthHeight(ROT& rot, MDP& mdp) + { + mdp.swapSrcWH(); + mdp.swapSrcRectWH(); + rot.swapDstWH(); + } + +template inline void swap ( T& a, T& b ) +{ + T c(a); a=b; b=c; +} + +inline int alignup(int value, int a) { + //if align = 0, return the value. Else, do alignment. + return a ? ((((value - 1) / a) + 1) * a) : value; +} + +// FIXME that align should replace the upper one. +inline int align(int value, int a) { + //if align = 0, return the value. Else, do alignment. + return a ? ((value + (a-1)) & ~(a-1)) : value; +} + + +template +inline utils::Dim getSrcRectDim(const MDP& ov) { + return utils::Dim(ov.src_rect.x, + ov.src_rect.y, + ov.src_rect.w, + ov.src_rect.h); +} + +template +inline utils::Whf getSrcWhf(const MDP& ov) { + return utils::Whf(ov.src.width, + ov.src.height, + ov.src.format); +} +template +inline void setSrcRectDim(MDP& ov, const utils::Dim& d) { + ov.src_rect.x = d.x; + ov.src_rect.y = d.y; + ov.src_rect.w = d.w; + ov.src_rect.h = d.h; +} +template +inline void setSrcWhf(MDP& ov, const utils::Whf& whf) { + ov.src.width = whf.w; + ov.src.height = whf.h; + ov.src.format = whf.format; +} + +enum eRotOutFmt { + ROT_OUT_FMT_DEFAULT, + ROT_OUT_FMT_Y_CRCB_H2V2 +}; + +template struct RotOutFmt; + +// FIXME, taken from gralloc_priv.h. Need to +// put it back as soon as overlay takes place of the old one +/* possible formats for 3D content*/ +enum { + HAL_NO_3D = 0x0000, + HAL_3D_IN_SIDE_BY_SIDE_L_R = 0x10000, + HAL_3D_IN_TOP_BOTTOM = 0x20000, + HAL_3D_IN_INTERLEAVE = 0x40000, + HAL_3D_IN_SIDE_BY_SIDE_R_L = 0x80000, + HAL_3D_OUT_SIDE_BY_SIDE = 0x1000, + HAL_3D_OUT_TOP_BOTTOM = 0x2000, + HAL_3D_OUT_INTERLEAVE = 0x4000, + HAL_3D_OUT_MONOSCOPIC = 0x8000 +}; + +enum { HAL_3D_OUT_SBS_MASK = + HAL_3D_OUT_SIDE_BY_SIDE >> overlay::utils::SHIFT_OUT_3D, + HAL_3D_OUT_TOP_BOT_MASK = + HAL_3D_OUT_TOP_BOTTOM >> overlay::utils::SHIFT_OUT_3D, + HAL_3D_OUT_INTERL_MASK = + HAL_3D_OUT_INTERLEAVE >> overlay::utils::SHIFT_OUT_3D, + HAL_3D_OUT_MONOS_MASK = + HAL_3D_OUT_MONOSCOPIC >> overlay::utils::SHIFT_OUT_3D +}; + + +inline bool isYuv(uint32_t format) { + switch(format){ + case MDP_Y_CBCR_H2V1: + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + case MDP_Y_CRCB_H2V2_TILE: + case MDP_Y_CBCR_H2V2_TILE: + return true; + default: + return false; + } + return false; +} + +inline bool isRgb(uint32_t format) { + switch(format) { + case MDP_RGBA_8888: + case MDP_BGRA_8888: + case MDP_RGBX_8888: + case MDP_RGB_565: + return true; + default: + return false; + } + return false; +} + +inline bool isValidDest(eDest dest) +{ + if ((OV_PIPE0 & dest) || + (OV_PIPE1 & dest) || + (OV_PIPE2 & dest)) { + return true; + } + return false; +} + +inline const char* getFormatString(uint32_t format){ + static const char* const formats[] = { + "MDP_RGB_565", + "MDP_XRGB_8888", + "MDP_Y_CBCR_H2V2", + "MDP_ARGB_8888", + "MDP_RGB_888", + "MDP_Y_CRCB_H2V2", + "MDP_YCRYCB_H2V1", + "MDP_Y_CRCB_H2V1", + "MDP_Y_CBCR_H2V1", + "MDP_RGBA_8888", + "MDP_BGRA_8888", + "MDP_RGBX_8888", + "MDP_Y_CRCB_H2V2_TILE", + "MDP_Y_CBCR_H2V2_TILE", + "MDP_Y_CR_CB_H2V2", + "MDP_Y_CB_CR_H2V2", + "MDP_IMGTYPE_LIMIT", + "MDP_BGR_565", + "MDP_FB_FORMAT", + "MDP_IMGTYPE_LIMIT2" + }; + OVASSERT(format < sizeof(formats) / sizeof(formats[0]), + "getFormatString wrong fmt %d", format); + return formats[format]; +} + +inline const char* getStateString(eOverlayState state){ + switch (state) { + case OV_CLOSED: + return "OV_CLOSED"; + case OV_2D_VIDEO_ON_PANEL: + return "OV_2D_VIDEO_ON_PANEL"; + case OV_2D_VIDEO_ON_PANEL_TV: + return "OV_2D_VIDEO_ON_PANEL_TV"; + case OV_3D_VIDEO_ON_2D_PANEL: + return "OV_3D_VIDEO_ON_2D_PANEL"; + case OV_3D_VIDEO_ON_3D_PANEL: + return "OV_3D_VIDEO_ON_3D_PANEL"; + case OV_3D_VIDEO_ON_3D_TV: + return "OV_3D_VIDEO_ON_3D_TV"; + case OV_3D_VIDEO_ON_2D_PANEL_2D_TV: + return "OV_3D_VIDEO_ON_2D_PANEL_2D_TV"; + case OV_UI_MIRROR: + return "OV_UI_MIRROR"; + case OV_2D_TRUE_UI_MIRROR: + return "OV_2D_TRUE_UI_MIRROR"; + case OV_BYPASS_1_LAYER: + return "OV_BYPASS_1_LAYER"; + case OV_BYPASS_2_LAYER: + return "OV_BYPASS_2_LAYER"; + case OV_BYPASS_3_LAYER: + return "OV_BYPASS_3_LAYER"; + default: + return "UNKNOWN_STATE"; + } + return "BAD_STATE"; +} + +inline uint32_t getSizeByMdp(const Whf& whf) { + Whf _whf(whf); + int fmt = getMdpFormat(whf.format); + OVASSERT(-1 != fmt, "getSizeByMdp error in format %d", + whf.format); + _whf.format = fmt; + return getSize(_whf); +} + +inline void Whf::dump() const { + ALOGE("== Dump WHF w=%d h=%d f=%d s=%d start/end ==", + w, h, format, size); +} + +inline void Dim::dump() const { + ALOGE("== Dump Dim x=%d y=%d w=%d h=%d start/end ==", x, y, w, h); +} + +inline int getMdpOrient(eTransform rotation) { + ALOGE_IF(DEBUG_OVERLAY, "%s: rot=%d", __FUNCTION__, rotation); + switch(int(rotation)) + { + case OVERLAY_TRANSFORM_0 : return 0; + case HAL_TRANSFORM_FLIP_V: return MDP_FLIP_UD; + case HAL_TRANSFORM_FLIP_H: return MDP_FLIP_LR; + case HAL_TRANSFORM_ROT_90: return MDP_ROT_90; + case HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_V: + return MDP_ROT_90|MDP_FLIP_LR; + case HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_H: + return MDP_ROT_90|MDP_FLIP_UD; + case HAL_TRANSFORM_ROT_180: return MDP_ROT_180; + case HAL_TRANSFORM_ROT_270: return MDP_ROT_270; + default: + ALOGE("%s: invalid rotation value (value = 0x%x", + __FUNCTION__, rotation); + } + return -1; +} + +inline int getRotOutFmt(uint32_t format) { + switch (format) { + case MDP_Y_CRCB_H2V2_TILE: + return MDP_Y_CRCB_H2V2; + case MDP_Y_CBCR_H2V2_TILE: + return MDP_Y_CBCR_H2V2; + case MDP_Y_CB_CR_H2V2: + return MDP_Y_CBCR_H2V2; + default: + return format; + } + // not reached + OVASSERT(false, "%s not reached", __FUNCTION__); + return -1; +} + +template<> +struct RotOutFmt +{ + static inline int fmt(uint32_t format) { + return getRotOutFmt(format); + } +}; + +template<> +struct RotOutFmt +{ + static inline int fmt(uint32_t) { + return MDP_Y_CRCB_H2V2; + } +}; + +inline uint32_t getColorFormat(uint32_t format) +{ + return (format == HAL_PIXEL_FORMAT_YV12) ? + format : colorFormat(format); +} + +// FB0 +template +inline Dim getPositionS3DImpl(const Whf& whf) +{ + switch (whf.format & OUTPUT_3D_MASK) + { + case HAL_3D_OUT_SBS_MASK: + // x, y, w, h + return Dim(0, 0, whf.w/2, whf.h); + case HAL_3D_OUT_TOP_BOT_MASK: + return Dim(0, 0, whf.w, whf.h/2); + case HAL_3D_OUT_MONOS_MASK: + return Dim(); + case HAL_3D_OUT_INTERL_MASK: + // FIXME error? + ALOGE("%s HAL_3D_OUT_INTERLEAVE_MASK", __FUNCTION__); + return Dim(); + default: + ALOGE("%s Unsupported 3D output format %d", __FUNCTION__, + whf.format); + } + return Dim(); +} + +template <> +inline Dim getPositionS3DImpl(const Whf& whf) +{ + switch (whf.format & OUTPUT_3D_MASK) + { + case HAL_3D_OUT_SBS_MASK: + return Dim(whf.w/2, 0, whf.w/2, whf.h); + case HAL_3D_OUT_TOP_BOT_MASK: + return Dim(0, whf.h/2, whf.w, whf.h/2); + case HAL_3D_OUT_MONOS_MASK: + return Dim(0, 0, whf.w, whf.h); + case HAL_3D_OUT_INTERL_MASK: + // FIXME error? + ALOGE("%s HAL_3D_OUT_INTERLEAVE_MASK", __FUNCTION__); + return Dim(); + default: + ALOGE("%s Unsupported 3D output format %d", __FUNCTION__, + whf.format); + } + return Dim(); +} + +template +inline bool getPositionS3D(const Whf& whf, Dim& out) { + out = getPositionS3DImpl(whf); + return (out != Dim()); +} + +template +inline Dim getCropS3DImpl(const Dim& in, uint32_t fmt) { + switch (fmt & INPUT_3D_MASK) + { + case HAL_3D_IN_SIDE_BY_SIDE_L_R: + return Dim(0, 0, in.w/2, in.h); + case HAL_3D_IN_SIDE_BY_SIDE_R_L: + return Dim(in.w/2, 0, in.w/2, in.h); + case HAL_3D_IN_TOP_BOTTOM: + return Dim(0, 0, in.w, in.h/2); + case HAL_3D_IN_INTERLEAVE: + ALOGE("%s HAL_3D_IN_INTERLEAVE", __FUNCTION__); + break; + default: + ALOGE("%s Unsupported 3D format %d", __FUNCTION__, fmt); + break; + } + return Dim(); +} + +template <> +inline Dim getCropS3DImpl(const Dim& in, uint32_t fmt) { + switch (fmt & INPUT_3D_MASK) + { + case HAL_3D_IN_SIDE_BY_SIDE_L_R: + return Dim(in.w/2, 0, in.w/2, in.h); + case HAL_3D_IN_SIDE_BY_SIDE_R_L: + return Dim(0, 0, in.w/2, in.h); + case HAL_3D_IN_TOP_BOTTOM: + return Dim(0, in.h/2, in.w, in.h/2); + case HAL_3D_IN_INTERLEAVE: + ALOGE("%s HAL_3D_IN_INTERLEAVE", __FUNCTION__); + break; + default: + ALOGE("%s Unsupported 3D format %d", __FUNCTION__, fmt); + break; + } + return Dim(); +} + +template +inline bool getCropS3D(const Dim& in, Dim& out, uint32_t fmt) +{ + out = getCropS3DImpl(in, fmt); + return (out != Dim()); +} + +template +void swapWidthHeight(Type& width, Type& height) { + Type tmp = width; + width = height; + height = tmp; +} + +inline void ScreenInfo::dump(const char* const s) const { + ALOGE("== Dump %s ScreenInfo w=%d h=%d" + " bpp=%d stride=%d start/end ==", + s, mFBWidth, mFBHeight, mFBbpp, mFBystride); +} + +inline void setSrcRectDim(const overlay::utils::Dim d, + mdp_overlay& ov) { + ov.src_rect.x = d.x; + ov.src_rect.y = d.y; + ov.src_rect.w = d.w; + ov.src_rect.h = d.h; +} + +inline void setDstRectDim(const overlay::utils::Dim d, + mdp_overlay& ov) { + ov.dst_rect.x = d.x; + ov.dst_rect.y = d.y; + ov.dst_rect.w = d.w; + ov.dst_rect.h = d.h; +} + +inline overlay::utils::Whf getSrcWhf(const mdp_overlay& ov) { + return overlay::utils::Whf(ov.src.width, + ov.src.height, + ov.src.format); +} + +inline overlay::utils::Dim getSrcRectDim(const mdp_overlay& ov) { + return overlay::utils::Dim(ov.src_rect.x, + ov.src_rect.y, + ov.src_rect.w, + ov.src_rect.h); +} + +inline overlay::utils::Dim getDstRectDim(const mdp_overlay& ov) { + return overlay::utils::Dim(ov.dst_rect.x, + ov.dst_rect.y, + ov.dst_rect.w, + ov.dst_rect.h); +} + + +} // namespace utils ends + +//--------------------Class Res stuff (namespace overlay only) ----------- + +class Res { +public: + // /dev/graphics/fb%u + static const char* const devTemplate; + // /dev/msm_rotator + static const char* const rotPath; + // /sys/class/graphics/fb1/format_3d + static const char* const format3DFile; + // /sys/class/graphics/fb1/3d_present + static const char* const edid3dInfoFile; + // /sys/devices/platform/mipi_novatek.0/enable_3d_barrier + static const char* const barrierFile; +}; + + +//--------------------Class OvFD stuff (namespace overlay only) ----------- + +class OvFD; + +/* helper function to open by using fbnum */ +bool open(OvFD& fd, uint32_t fbnum, const char* const dev, + int flags = O_RDWR); + +/* +* Holds one FD +* Dtor will NOT close the underlying FD. +* That enables us to copy that object around +* */ +class OvFD { +public: + /* Ctor */ + explicit OvFD(); + + /* dtor will NOT close the underlying FD */ + ~OvFD(); + + /* Open fd using the path given by dev. + * return false in failure */ + bool open(const char* const dev, + int flags = O_RDWR); + + /* populate path */ + void setPath(const char* const dev); + + /* Close fd if we have a valid fd. */ + bool close(); + + /* returns underlying fd.*/ + int getFD() const; + + /* returns true if fd is valid */ + bool valid() const; + + /* like operator= */ + void copy(int fd); + + /* dump the state of the instance */ + void dump() const; +private: + /* helper enum for determine valid/invalid fd */ + enum { INVAL = -1 }; + + /* actual os fd */ + int mFD; + + /* path, for debugging */ + char mPath[utils::MAX_PATH_LEN]; +}; + +//-------------------Inlines-------------------------- + +inline bool open(OvFD& fd, uint32_t fbnum, const char* const dev, int flags) +{ + char dev_name[64] = {0}; + snprintf(dev_name, sizeof(dev_name), dev, fbnum); + return fd.open(dev_name, flags); +} + +inline OvFD::OvFD() : mFD (INVAL) { + mPath[0] = 0; +} + +inline OvFD::~OvFD() { /* no op in the meantime */ } + +inline bool OvFD::open(const char* const dev, int flags) +{ + mFD = ::open(dev, flags, 0); + if (mFD < 0) { + // FIXME errno, strerror in bionic? + ALOGE("Cant open device %s err=%d", dev, errno); + return false; + } + setPath(dev); + return true; +} + +inline void OvFD::setPath(const char* const dev) +{ + ::strncpy(mPath, dev, utils::MAX_PATH_LEN); +} + +inline bool OvFD::close() +{ + int ret = 0; + if(valid()) { + ret = ::close(mFD); + mFD = INVAL; + } + return (ret == 0); +} + +inline bool OvFD::valid() const +{ + return (mFD != INVAL); +} + +inline int OvFD::getFD() const { return mFD; } + +inline void OvFD::copy(int fd) { + mFD = fd; +} + +inline void OvFD::dump() const +{ + ALOGE("== Dump OvFD fd=%d path=%s start/end ==", + mFD, mPath); +} + +//--------------- class OvFD stuff ends --------------------- + +} // overlay + + +#endif // OVERLAY_UTILS_H diff --git a/liboverlay/pipes/overlay3DPipe.h b/liboverlay/pipes/overlay3DPipe.h new file mode 100644 index 0000000..dce4bf4 --- /dev/null +++ b/liboverlay/pipes/overlay3DPipe.h @@ -0,0 +1,617 @@ +/* +* Copyright (c) 2011-2012, 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 OVERLAY_M3D_EXT_PIPE_H +#define OVERLAY_M3D_EXT_PIPE_H + +#include "overlayGenPipe.h" +#include "overlayUtils.h" + +namespace overlay { + +///////////// M3DExt Pipe //////////////////////////// +/** +* A specific impl of GenericPipe for 3D. +* Whenever needed to have a pass through - we do it. +* If there is a special need for special/diff behavior +* do it here +* PANEL is always EXTERNAL for this pipe. +* CHAN = 0,1 it's either Channel 1 or channel 2 needed for +* 3D crop and position */ +template +class M3DExtPipe : utils::NoCopy { +public: + /* Please look at overlayGenPipe.h for info */ + explicit M3DExtPipe(); + ~M3DExtPipe(); + bool open(RotatorBase* rot); + bool close(); + bool commit(); + void setId(int id); + void setMemoryId(int id); + bool queueBuffer(uint32_t offset); + bool dequeueBuffer(void*& buf); + bool waitForVsync(); + bool setCrop(const utils::Dim& d); + bool start(const utils::PipeArgs& args); + bool setPosition(const utils::Dim& dim); + bool setParameter(const utils::Params& param); + bool setSource(const utils::PipeArgs& args); + const utils::PipeArgs& getArgs() const; + utils::eOverlayPipeType getOvPipeType() const; + void dump() const; +private: + overlay::GenericPipe mM3d; + // Cache the M3D format + uint32_t mM3Dfmt; +}; + +///////////// M3DPrimary Pipe //////////////////////////// +/** +* A specific impl of GenericPipe for 3D. +* Whenever needed to have a pass through - we do it. +* If there is a special need for special/diff behavior +* do it here +* PANEL is always PRIMARY for this pipe. +* CHAN = 0,1 it's either Channel 1 or channel 2 needed for +* 3D crop and position */ +template +class M3DPrimaryPipe : utils::NoCopy { +public: + /* Please look at overlayGenPipe.h for info */ + explicit M3DPrimaryPipe(); + ~M3DPrimaryPipe(); + bool open(RotatorBase* rot); + bool close(); + bool commit(); + void setId(int id); + void setMemoryId(int id); + bool queueBuffer(uint32_t offset); + bool dequeueBuffer(void*& buf); + bool waitForVsync(); + bool setCrop(const utils::Dim& d); + bool start(const utils::PipeArgs& args); + bool setPosition(const utils::Dim& dim); + bool setParameter(const utils::Params& param); + bool setSource(const utils::PipeArgs& args); + const utils::PipeArgs& getArgs() const; + utils::eOverlayPipeType getOvPipeType() const; + void dump() const; +private: + overlay::GenericPipe mM3d; + // Cache the M3D format + uint32_t mM3Dfmt; +}; + +///////////// S3DExt Pipe //////////////////////////////// +/** +* A specific impl of GenericPipe for 3D. +* Whenever needed to have a pass through - we do it. +* If there is a special need for special/diff behavior +* do it here. +* PANEL is always EXTERNAL for this pipe. +* CHAN = 0,1 it's either Channel 1 or channel 2 needed for +* 3D crop and position */ +template +class S3DExtPipe : utils::NoCopy { +public: + /* Please look at overlayGenPipe.h for info */ + explicit S3DExtPipe(); + ~S3DExtPipe(); + bool open(RotatorBase* rot); + bool close(); + bool commit(); + void setId(int id); + void setMemoryId(int id); + bool queueBuffer(uint32_t offset); + bool dequeueBuffer(void*& buf); + bool waitForVsync(); + bool setCrop(const utils::Dim& d); + bool start(const utils::PipeArgs& args); + bool setPosition(const utils::Dim& dim); + bool setParameter(const utils::Params& param); + bool setSource(const utils::PipeArgs& args); + const utils::PipeArgs& getArgs() const; + utils::eOverlayPipeType getOvPipeType() const; + void dump() const; +private: + overlay::GenericPipe mS3d; + // Cache the 3D format + uint32_t mS3Dfmt; +}; + +///////////// S3DPrimary Pipe //////////////////////////// +/** +* A specific impl of GenericPipe for 3D. +* Whenever needed to have a pass through - we do it. +* If there is a special need for special/diff behavior +* do it here +* PANEL is always PRIMARY for this pipe. +* CHAN = 0,1 it's either Channel 1 or channel 2 needed for +* 3D crop and position */ +template +class S3DPrimaryPipe : utils::NoCopy { +public: + /* Please look at overlayGenPipe.h for info */ + explicit S3DPrimaryPipe(); + ~S3DPrimaryPipe(); + bool open(RotatorBase* rot); + bool close(); + bool commit(); + void setId(int id); + void setMemoryId(int id); + bool queueBuffer(uint32_t offset); + bool dequeueBuffer(void*& buf); + bool waitForVsync(); + bool setCrop(const utils::Dim& d); + bool start(const utils::PipeArgs& args); + bool setPosition(const utils::Dim& dim); + bool setParameter(const utils::Params& param); + bool setSource(const utils::PipeArgs& args); + const utils::PipeArgs& getArgs() const; + utils::eOverlayPipeType getOvPipeType() const; + void dump() const; +private: + /* needed for 3D related IOCTL */ + MdpCtrl3D mCtrl3D; + overlay::GenericPipe mS3d; + // Cache the 3D format + uint32_t mS3Dfmt; +}; + + + + +//------------------------Inlines and Templates-------------------------- + + +///////////// M3DExt Pipe //////////////////////////// +template +inline M3DExtPipe::M3DExtPipe() : mM3Dfmt(0) {} +template +inline M3DExtPipe::~M3DExtPipe() { close(); } +template +inline bool M3DExtPipe::open(RotatorBase* rot) { + ALOGE_IF(DEBUG_OVERLAY, "M3DExtPipe open"); + if(!mM3d.open(rot)) { + ALOGE("3Dpipe failed to open"); + return false; + } + return true; +} +template +inline bool M3DExtPipe::close() { + return mM3d.close(); +} +template +inline bool M3DExtPipe::commit() { return mM3d.commit(); } +template +inline void M3DExtPipe::setId(int id) { mM3d.setId(id); } +template +inline void M3DExtPipe::setMemoryId(int id) { mM3d.setMemoryId(id); } +template +inline bool M3DExtPipe::queueBuffer(uint32_t offset) { + return mM3d.queueBuffer(offset); } +template +inline bool M3DExtPipe::dequeueBuffer(void*& buf) { + return mM3d.dequeueBuffer(buf); } +template +inline bool M3DExtPipe::waitForVsync() { + return mM3d.waitForVsync(); } +template +inline bool M3DExtPipe::setCrop(const utils::Dim& d) { + utils::Dim _dim; + if(!utils::getCropS3D(d, _dim, mM3Dfmt)){ + ALOGE("M3DExtPipe setCrop failed to getCropS3D"); + _dim = d; + } + return mM3d.setCrop(_dim); +} +template +inline bool M3DExtPipe::start(const utils::PipeArgs& args) { + if(!mM3d.start(args)) { + ALOGE("M3DExtPipe start failed"); + return false; + } + return true; +} +template +inline bool M3DExtPipe::setPosition(const utils::Dim& d) { + utils::Dim _dim; + // original setPositionHandleState has getPositionS3D(...,true) + // which means format is HAL_3D_OUT_SBS_MASK + // HAL_3D_OUT_SBS_MASK is 0x1000 >> 12 == 0x1 as the orig + // code suggets + utils::Whf _whf(mM3d.getScreenInfo().mFBWidth, + mM3d.getScreenInfo().mFBHeight, + mM3Dfmt); + if(!utils::getPositionS3D(_whf, _dim)) { + ALOGE("S3DPrimaryPipe setPosition err in getPositionS3D"); + _dim = d; + } + return mM3d.setPosition(_dim); +} +template +inline bool M3DExtPipe::setParameter(const utils::Params& param) { + return mM3d.setParameter(param); +} +template +inline bool M3DExtPipe::setSource(const utils::PipeArgs& args) +{ + // extract 3D fmt + mM3Dfmt = utils::format3DInput(utils::getS3DFormat(args.whf.format)) | + utils::HAL_3D_OUT_MONOS_MASK; + if(mM3d.isClosed()){ + if(!this->start(args)) { + ALOGE("M3DExtPipe setSource failed to start"); + return false; + } + } + return mM3d.setSource(args); +} +template +inline const utils::PipeArgs& M3DExtPipe::getArgs() const { + return mM3d.getArgs(); +} +template +inline utils::eOverlayPipeType M3DExtPipe::getOvPipeType() const { + return utils::OV_PIPE_TYPE_M3D_EXTERNAL; +} +template +inline void M3DExtPipe::dump() const { + ALOGE("M3DExtPipe Pipe fmt=%d", mM3Dfmt); + mM3d.dump(); +} + + +///////////// M3DPrimary Pipe //////////////////////////// +template +inline M3DPrimaryPipe::M3DPrimaryPipe() : mM3Dfmt(0) {} +template +inline M3DPrimaryPipe::~M3DPrimaryPipe() { close(); } +template +inline bool M3DPrimaryPipe::open(RotatorBase* rot) { + ALOGE_IF(DEBUG_OVERLAY, "M3DPrimaryPipe open"); + if(!mM3d.open(rot)) { + ALOGE("3Dpipe failed to open"); + return false; + } + return true; +} +template +inline bool M3DPrimaryPipe::close() { + return mM3d.close(); +} +template +inline bool M3DPrimaryPipe::commit() { return mM3d.commit(); } +template +inline void M3DPrimaryPipe::setId(int id) { mM3d.setId(id); } +template +inline void M3DPrimaryPipe::setMemoryId(int id) { mM3d.setMemoryId(id); } +template +inline bool M3DPrimaryPipe::queueBuffer(uint32_t offset) { + return mM3d.queueBuffer(offset); } +template +inline bool M3DPrimaryPipe::dequeueBuffer(void*& buf) { + return mM3d.dequeueBuffer(buf); } +template +inline bool M3DPrimaryPipe::waitForVsync() { + return mM3d.waitForVsync(); } +template +inline bool M3DPrimaryPipe::setCrop(const utils::Dim& d) { + utils::Dim _dim; + if(!utils::getCropS3D(d, _dim, mM3Dfmt)){ + ALOGE("M3DPrimaryPipe setCrop failed to getCropS3D"); + _dim = d; + } + return mM3d.setCrop(_dim); +} +template +inline bool M3DPrimaryPipe::start(const utils::PipeArgs& args) { + if(!mM3d.start(args)) { + ALOGE("M3DPrimaryPipe start failed"); + return false; + } + return true; +} +template +inline bool M3DPrimaryPipe::setPosition(const utils::Dim& d) { + return mM3d.setPosition(d); +} +template +inline bool M3DPrimaryPipe::setParameter(const utils::Params& param) { + return mM3d.setParameter(param); +} +template +inline bool M3DPrimaryPipe::setSource(const utils::PipeArgs& args) +{ + // extract 3D fmt + mM3Dfmt = utils::format3DInput(utils::getS3DFormat(args.whf.format)) | + utils::HAL_3D_OUT_MONOS_MASK; + if (mM3d.isClosed()) { + if (!this->start(args)) { + ALOGE("M3DPrimaryPipe setSource failed to start"); + return false; + } + } + return mM3d.setSource(args); +} +template +inline const utils::PipeArgs& M3DPrimaryPipe::getArgs() const { + return mM3d.getArgs(); +} +template +inline utils::eOverlayPipeType M3DPrimaryPipe::getOvPipeType() const { + return utils::OV_PIPE_TYPE_M3D_PRIMARY; +} +template +inline void M3DPrimaryPipe::dump() const { + ALOGE("M3DPrimaryPipe Pipe fmt=%d", mM3Dfmt); + mM3d.dump(); +} + +///////////// S3DExt Pipe //////////////////////////////// +template +inline S3DExtPipe::S3DExtPipe() : mS3Dfmt(0) {} +template +inline S3DExtPipe::~S3DExtPipe() { close(); } +template +inline bool S3DExtPipe::open(RotatorBase* rot) { + ALOGE_IF(DEBUG_OVERLAY, "S3DExtPipe open"); + if(!mS3d.open(rot)) { + ALOGE("3Dpipe failed to open"); + return false; + } + return true; +} +template +inline bool S3DExtPipe::close() { + if(!utils::send3DInfoPacket(0)) { + ALOGE("S3DExtPipe close failed send3D info packet"); + } + return mS3d.close(); +} +template +inline bool S3DExtPipe::commit() { return mS3d.commit(); } +template +inline void S3DExtPipe::setId(int id) { mS3d.setId(id); } +template +inline void S3DExtPipe::setMemoryId(int id) { mS3d.setMemoryId(id); } +template +inline bool S3DExtPipe::queueBuffer(uint32_t offset) { + //this->dump(); + return mS3d.queueBuffer(offset); } +template +inline bool S3DExtPipe::dequeueBuffer(void*& buf) { + return mS3d.dequeueBuffer(buf); } +template +inline bool S3DExtPipe::waitForVsync() { + return mS3d.waitForVsync(); } +template +inline bool S3DExtPipe::setCrop(const utils::Dim& d) { + utils::Dim _dim; + if(!utils::getCropS3D(d, _dim, mS3Dfmt)){ + ALOGE("S3DExtPipe setCrop failed to getCropS3D"); + _dim = d; + } + return mS3d.setCrop(_dim); +} +template +inline bool S3DExtPipe::start(const utils::PipeArgs& args) { + OVASSERT(mS3Dfmt, "S3DExtPipe mS3Dfmt should not be 0 here"); + if(!mS3d.start(args)) { + ALOGE("S3DExtPipe start failed"); + return false; + } + uint32_t fmt = mS3Dfmt & utils::OUTPUT_3D_MASK; + if(!utils::send3DInfoPacket(fmt)){ + ALOGE("Error S3DExtPipe start error send3DInfoPacket %d", fmt); + return false; + } + return true; +} +template +inline bool S3DExtPipe::setPosition(const utils::Dim& d) +{ + utils::Dim _dim; + utils::Whf _whf(mS3d.getScreenInfo().mFBWidth, + mS3d.getScreenInfo().mFBHeight, + mS3Dfmt); + if(!utils::getPositionS3D(_whf, _dim)) { + ALOGE("S3DExtPipe setPosition err in getPositionS3D"); + _dim = d; + } + return mS3d.setPosition(_dim); +} +template +inline bool S3DExtPipe::setParameter(const utils::Params& param) { + return mS3d.setParameter(param); +} +template +inline bool S3DExtPipe::setSource(const utils::PipeArgs& args) { + mS3Dfmt = utils::getS3DFormat(args.whf.format); + if(mS3d.isClosed()){ + if(!this->start(args)) { + ALOGE("S3DExtPipe setSource failed to start"); + return false; + } + } + return mS3d.setSource(args); +} +template +inline const utils::PipeArgs& S3DExtPipe::getArgs() const { + return mS3d.getArgs(); +} +template +inline utils::eOverlayPipeType S3DExtPipe::getOvPipeType() const { + return utils::OV_PIPE_TYPE_S3D_EXTERNAL; +} +template +inline void S3DExtPipe::dump() const { + ALOGE("S3DExtPipe Pipe fmt=%d", mS3Dfmt); + mS3d.dump(); +} + +///////////// S3DPrimary Pipe //////////////////////////// +template +inline S3DPrimaryPipe::S3DPrimaryPipe() : mS3Dfmt(0) {} +template +inline S3DPrimaryPipe::~S3DPrimaryPipe() { close(); } +template +inline bool S3DPrimaryPipe::open(RotatorBase* rot) { + ALOGE_IF(DEBUG_OVERLAY, "S3DPrimaryPipe open"); + if(!mS3d.open(rot)) { + ALOGE("3Dpipe failed to open"); + return false; + } + // set the ctrl fd + mCtrl3D.setFd(mS3d.getCtrlFd()); + return true; +} +template +inline bool S3DPrimaryPipe::close() { + if(!utils::enableBarrier(0)) { + ALOGE("S3DExtPipe close failed enable barrier"); + } + mCtrl3D.close(); + return mS3d.close(); +} +template +inline bool S3DPrimaryPipe::commit() { return mS3d.commit(); } +template +inline void S3DPrimaryPipe::setId(int id) { mS3d.setId(id); } +template +inline void S3DPrimaryPipe::setMemoryId(int id) { mS3d.setMemoryId(id); } +template +inline bool S3DPrimaryPipe::queueBuffer(uint32_t offset) { + return mS3d.queueBuffer(offset); } +template +inline bool S3DPrimaryPipe::dequeueBuffer(void*& buf) { + return mS3d.dequeueBuffer(buf); } +template +inline bool S3DPrimaryPipe::waitForVsync() { + return mS3d.waitForVsync(); } +template +inline bool S3DPrimaryPipe::setCrop(const utils::Dim& d) { + utils::Dim _dim; + if(!utils::getCropS3D(d, _dim, mS3Dfmt)){ + ALOGE("S3DPrimaryPipe setCrop failed to getCropS3D"); + _dim = d; + } + return mS3d.setCrop(_dim); +} +template +inline bool S3DPrimaryPipe::start(const utils::PipeArgs& args) { + if(!mS3d.start(args)) { + ALOGE("S3DPrimaryPipe start failed"); + return false; + } + return true; +} +template +inline bool S3DPrimaryPipe::setPosition(const utils::Dim& d) +{ + utils::Whf fbwhf(mS3d.getScreenInfo().mFBWidth, + mS3d.getScreenInfo().mFBHeight, + 0 /* fmt dont care*/); + mCtrl3D.setWh(fbwhf); + if(!mCtrl3D.useVirtualFB()) { + ALOGE("Failed to use VFB on %d (non fatal)", utils::FB0); + return false; + } + utils::Dim _dim; + // original setPositionHandleState has getPositionS3D(...,true) + // which means format is HAL_3D_OUT_SBS_MASK + // HAL_3D_OUT_SBS_MASK is 0x1000 >> 12 == 0x1 as the orig + // code suggets + utils::Whf _whf(d.w, d.h, utils::HAL_3D_OUT_SBS_MASK); + if(!utils::getPositionS3D(_whf, _dim)) { + ALOGE("S3DPrimaryPipe setPosition err in getPositionS3D"); + _dim = d; + } + return mS3d.setPosition(_dim); +} + +/* for S3DPrimaryPipe, we need to have barriers once +* So the easiest way to achieve it, is to make sure FB0 is having it before +* setParam is running */ +template <> +inline bool S3DPrimaryPipe::setParameter( + const utils::Params& param) { + if(utils::OVERLAY_TRANSFORM == param.param){ + uint32_t barrier=0; + switch(param.value) { + case HAL_TRANSFORM_ROT_90: + case HAL_TRANSFORM_ROT_270: + barrier = utils::BARRIER_LAND; + break; + default: + barrier = utils::BARRIER_PORT; + break; + } + if(!utils::enableBarrier(barrier)) { + ALOGE("S3DPrimaryPipe setParameter failed to enable barrier"); + } + } + return mS3d.setParameter(param); +} + +template +inline bool S3DPrimaryPipe::setParameter(const utils::Params& param) { + return mS3d.setParameter(param); +} +template +inline bool S3DPrimaryPipe::setSource(const utils::PipeArgs& args) +{ + mS3Dfmt = utils::getS3DFormat(args.whf.format); + if(mS3d.isClosed()){ + if(!this->start(args)) { + ALOGE("S3DPrimaryPipe setSource failed to start"); + return false; + } + } + return mS3d.setSource(args); +} +template +inline const utils::PipeArgs& S3DPrimaryPipe::getArgs() const { + return mS3d.getArgs(); +} +template +inline utils::eOverlayPipeType S3DPrimaryPipe::getOvPipeType() const { + return utils::OV_PIPE_TYPE_S3D_PRIMARY; +} +template +inline void S3DPrimaryPipe::dump() const { + ALOGE("S3DPrimaryPipe Pipe fmt=%d", mS3Dfmt); + mS3d.dump(); +} + +} // overlay + +#endif // OVERLAY_M3D_EXT_PIPE_H diff --git a/liboverlay/pipes/overlayBypassPipe.h b/liboverlay/pipes/overlayBypassPipe.h new file mode 100644 index 0000000..593a693 --- /dev/null +++ b/liboverlay/pipes/overlayBypassPipe.h @@ -0,0 +1,213 @@ +/* +* Copyright (c) 2012, 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 OVERLAY_BYPASS_PIPE_H +#define OVERLAY_BYPASS_PIPE_H + +#include "overlayGenPipe.h" +#include "overlayUtils.h" +#include "overlayCtrlData.h" +#include "overlayMdp.h" +#include "overlayRotator.h" + +namespace overlay { + +/* A specific impl of GenericPipe +* Whenever needed to have a pass through - we do it. +* If there is a special need for a different behavior - do it here +* PipeType = 0 (RGB), 1 (VG) */ +template +class BypassPipe : utils::NoCopy { +public: + /* Please look at overlayGenPipe.h for info */ + explicit BypassPipe(); + ~BypassPipe(); + bool open(RotatorBase* rot); + bool close(); + bool commit(); + void setId(int id); + void setMemoryId(int id); + bool queueBuffer(uint32_t offset); + bool dequeueBuffer(void*& buf); + bool waitForVsync(); + bool setCrop(const utils::Dim& dim); + bool start(const utils::PipeArgs& args); + bool setPosition(const utils::Dim& dim); + bool setParameter(const utils::Params& param); + bool setSource(const utils::PipeArgs& args); + const utils::PipeArgs& getArgs() const; + utils::eOverlayPipeType getOvPipeType() const; + void dump() const; +private: + overlay::GenericPipe mBypass; +}; + +//------------------Inlines and Templates--------------------- + +template +inline BypassPipe::BypassPipe() {} + +template +inline BypassPipe::~BypassPipe() { + close(); +} + +template +inline bool BypassPipe::open(RotatorBase* rot) { + ALOGE_IF(DEBUG_OVERLAY, "BypassPipe open"); + return mBypass.open(rot); +} + +template +inline bool BypassPipe::close() { + return mBypass.close(); +} + +template +inline bool BypassPipe::commit() { + return mBypass.commit(); +} + +template +inline void BypassPipe::setId(int id) { + mBypass.setId(id); +} + +template +inline void BypassPipe::setMemoryId(int id) { + mBypass.setMemoryId(id); +} + +template +inline bool BypassPipe::queueBuffer( + uint32_t offset) { + return mBypass.queueBuffer(offset); +} + +template +inline bool BypassPipe::dequeueBuffer( + void*& buf) { + return mBypass.dequeueBuffer(buf); +} + +template +inline bool BypassPipe::waitForVsync() { + return mBypass.waitForVsync(); +} + +template +inline bool BypassPipe::setCrop( + const utils::Dim& dim) { + return mBypass.setCrop(dim); +} + +template +inline bool BypassPipe::start( + const utils::PipeArgs& args) { + return mBypass.start(args); +} + +template +inline bool BypassPipe::setPosition( + const utils::Dim& dim) { + return mBypass.setPosition(dim); +} + +template +inline bool BypassPipe::setParameter( + const utils::Params& param) { + return mBypass.setParameter(param); +} + +template +inline bool BypassPipe::setSource( + const utils::PipeArgs& args) { + utils::PipeArgs arg(args); + + // Stride aligned to 32 + arg.whf.w = utils::align(arg.whf.w, 32); + arg.whf.h = utils::align(arg.whf.h, 32); + + // VG or RG pipe + if (PipeType == utils::OV_MDP_PIPE_VG) { + setMdpFlags(arg.mdpFlags, utils::OV_MDP_PIPE_SHARE); + } + + // Set is_fg flag + arg.isFg = IsFg; + + // Wait or no wait + arg.wait = Wait; + + // Z-order + arg.zorder = Zorder; + + return mBypass.setSource(arg); +} + +template +inline const utils::PipeArgs& BypassPipe::getArgs() const { + return mBypass.getArgs(); +} + +template +inline utils::eOverlayPipeType BypassPipe::getOvPipeType() const { + return utils::OV_PIPE_TYPE_BYPASS; +} + +template +inline void BypassPipe::dump() const { + ALOGE("Bypass VG Pipe"); + mBypass.dump(); +} + +} // overlay + +#endif // OVERLAY_BYPASS_PIPE_H diff --git a/liboverlay/pipes/overlayGenPipe.h b/liboverlay/pipes/overlayGenPipe.h new file mode 100644 index 0000000..1fd4a4f --- /dev/null +++ b/liboverlay/pipes/overlayGenPipe.h @@ -0,0 +1,403 @@ +/* +* Copyright (c) 2011-2012, 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 OVERLAY_GENERIC_PIPE_H +#define OVERLAY_GENERIC_PIPE_H + +#include "overlayUtils.h" +#include "overlayRotator.h" +#include "overlayCtrlData.h" + +// FIXME make int to be uint32 whenever possible + +namespace overlay { + +template +class GenericPipe : utils::NoCopy { +public: + /* ctor init */ + explicit GenericPipe(); + + /* dtor close */ + ~GenericPipe(); + + /* CTRL/DATA/ROT open */ + bool open(RotatorBase* rot); + + /* CTRL/DATA close. Not owning rotator, will not close it */ + bool close(); + + /* commit changes to the overlay "set"*/ + bool commit(); + + /* "Data" related interface */ + + /* set ID directly to data channel */ + void setId(int id); + + /* Set FD / memid */ + void setMemoryId(int id); + + /* queue buffer to the overlay */ + bool queueBuffer(uint32_t offset); + + /* dequeue buffer to the overlay NOTSUPPORTED */ + bool dequeueBuffer(void*& buf); + + /* wait for vsync to be done */ + bool waitForVsync(); + + /* set crop data FIXME setROI (Region Of Intrest) */ + bool setCrop(const utils::Dim& d); + + /* "Ctrl" related interface */ + + /* + * Start a session, opens the rotator + * FIXME, we might want to open the rotator separately + */ + bool start(const utils::PipeArgs& args); + + /* set mdp posision using dim */ + bool setPosition(const utils::Dim& dim); + + /* set param using Params (param,value pair) */ + bool setParameter(const utils::Params& param); + + /* set source using whf, orient and wait flag */ + bool setSource(const utils::PipeArgs& args); + + /* return cached startup args */ + const utils::PipeArgs& getArgs() const; + + /* retrieve screen info */ + utils::ScreenInfo getScreenInfo() const; + + /* retrieve cached crop data */ + utils::Dim getCrop() const; + + /* return aspect ratio from ctrl data */ + utils::Dim getAspectRatio(const utils::Whf& whf) const; + + /* return aspect ratio from ctrl data for true UI mirroring */ + utils::Dim getAspectRatio(const utils::Dim& dim) const; + + /* is closed */ + bool isClosed() const; + + /* is open */ + bool isOpen() const; + + /* return Ctrl fd. Used for S3D */ + int getCtrlFd() const; + + /* Get the overlay pipe type */ + utils::eOverlayPipeType getOvPipeType() const; + + /* dump the state of the object */ + void dump() const; +private: + /* set Closed channel */ + bool setClosed(); + // kick off rotator. + bool startRotator(); + + /* Ctrl/Data aggregator */ + CtrlData mCtrlData; + + /* caching startup params. useful when need + * to have the exact copy of that pipe. + * For example when HDMI is connected, and we would + * like to open/start the pipe with the args */ + utils::PipeArgs mArgs; + + /* rotator mdp base + * Can point to NullRotator or to Rotator*/ + RotatorBase* mRot; + + /* my flags */ + enum { CLOSED = 1<<0 }; + uint32_t mFlags; +}; + +//------------------------Inlines and Templates ---------------------- + +template +GenericPipe::GenericPipe() : mRot(0), mFlags(CLOSED) {} + +template +GenericPipe::~GenericPipe() { + close(); +} + +template +bool GenericPipe::open(RotatorBase* rot) +{ + OVASSERT(rot, "rot is null"); + // open ctrl and data + uint32_t fbnum = utils::getFBForPanel(PANEL); + ALOGE_IF(DEBUG_OVERLAY, "GenericPipe open"); + if(!mCtrlData.ctrl.open(fbnum, rot)) { + ALOGE("GenericPipe failed to open ctrl"); + return false; + } + if(!mCtrlData.data.open(fbnum, rot)) { + ALOGE("GenericPipe failed to open data"); + return false; + } + mRot = rot; + + // NOTE: we won't have the flags as non CLOSED since we + // consider the pipe opened for business only when we call + // start() + + return true; +} + +template +bool GenericPipe::close() { + if(isClosed()) return true; + bool ret = true; + if(!mCtrlData.ctrl.close()) { + ALOGE("GenericPipe failed to close ctrl"); + ret = false; + } + if (!mCtrlData.data.close()) { + ALOGE("GenericPipe failed to close data"); + ret = false; + } + setClosed(); + return ret; +} + +template +inline bool GenericPipe::commit(){ + OVASSERT(isOpen(), "State is closed, cannot commit"); + return mCtrlData.ctrl.commit(); +} + +template +inline void GenericPipe::setMemoryId(int id) { + OVASSERT(isOpen(), "State is closed, cannot setMemoryId"); + mCtrlData.data.setMemoryId(id); +} + +template +inline void GenericPipe::setId(int id) { + mCtrlData.data.setId(id); } + +template +inline int GenericPipe::getCtrlFd() const { + return mCtrlData.ctrl.getFd(); +} + +template +inline bool GenericPipe::setCrop( + const overlay::utils::Dim& d) { + OVASSERT(isOpen(), "State is closed, cannot setCrop"); + return mCtrlData.ctrl.setCrop(d); +} + +template +bool GenericPipe::start(const utils::PipeArgs& args) +{ + /* open before your start control rotator */ + uint32_t sz = args.whf.size; //utils::getSizeByMdp(args.whf); + OVASSERT(sz, "GenericPipe sz=%d", sz); + if(!mRot->open()) { + ALOGE("GenericPipe start failed to open rot"); + return false; + } + + if(!mCtrlData.ctrl.start(args)){ + ALOGE("GenericPipe failed to start"); + return false; + } + + int ctrlId = mCtrlData.ctrl.getId(); + OVASSERT(-1 != ctrlId, "Ctrl ID should not be -1"); + // set ID requeset to assoc ctrl to data + setId(ctrlId); + // set ID request to assoc MDP data to ROT MDP data + mRot->setDataReqId(mCtrlData.data.getId()); + + // cache the args for future reference. + mArgs = args; + + // we got here so we are open+start and good to go + mFlags = 0; // clear flags from CLOSED + // TODO make it more robust when more flags + // are added + + return true; +} + +template +inline const utils::PipeArgs& GenericPipe::getArgs() const +{ + return mArgs; +} + +template +bool GenericPipe::startRotator() { + // kick off rotator + if(!mRot->start()) { + ALOGE("GenericPipe failed to start rotator"); + return false; + } + return true; +} + +template +inline bool GenericPipe::queueBuffer(uint32_t offset) { + OVASSERT(isOpen(), "State is closed, cannot queueBuffer"); + return mCtrlData.data.queueBuffer(offset); +} + +template +inline bool GenericPipe::dequeueBuffer(void*&) { + OVASSERT(isOpen(), "State is closed, cannot dequeueBuffer"); + // can also set error to NOTSUPPORTED in the future + return false; +} + +template +inline bool GenericPipe::waitForVsync() { + OVASSERT(isOpen(), "State is closed, cannot waitForVsync"); + + return mCtrlData.data.waitForVsync(); +} + +template +inline bool GenericPipe::setPosition(const utils::Dim& dim) +{ + OVASSERT(isOpen(), "State is closed, cannot setPosition"); + return mCtrlData.ctrl.setPosition(dim); +} + +template +inline bool GenericPipe::setParameter( + const utils::Params& param) +{ + OVASSERT(isOpen(), "State is closed, cannot setParameter"); + // Currently setParameter would start rotator + if(!mCtrlData.ctrl.setParameter(param)) { + ALOGE("GenericPipe failed to setparam"); + return false; + } + // if rot flags are ENABLED it means we would always + // like to have rot. Even with 0 rot. (solves tearing) + if(utils::ROT_FLAG_ENABLED == mArgs.rotFlags) { + mRot->setEnable(); + } + return startRotator(); +} + +template +inline bool GenericPipe::setSource( + const utils::PipeArgs& args) +{ + // cache the recent args. + mArgs = args; + // setSource is the 1st thing that is being called on a pipe. + // If pipe is closed, we should start everything. + // we assume it is being opened with the correct FDs. + if(isClosed()) { + if(!this->start(args)) { + ALOGE("GenericPipe setSource failed to start"); + return false; + } + return true; + } + + return mCtrlData.ctrl.setSource(args); +} + +template +inline utils::Dim GenericPipe::getAspectRatio( + const utils::Whf& whf) const +{ + return mCtrlData.ctrl.getAspectRatio(whf); +} + +template +inline utils::Dim GenericPipe::getAspectRatio( + const utils::Dim& dim) const +{ + return mCtrlData.ctrl.getAspectRatio(dim); +} + +template +inline utils::ScreenInfo GenericPipe::getScreenInfo() const +{ + return mCtrlData.ctrl.getScreenInfo(); +} + +template +inline utils::Dim GenericPipe::getCrop() const +{ + return mCtrlData.ctrl.getCrop(); +} + +template +inline utils::eOverlayPipeType GenericPipe::getOvPipeType() const { + return utils::OV_PIPE_TYPE_GENERIC; +} + +template +void GenericPipe::dump() const +{ + ALOGE("== Dump Generic pipe start =="); + ALOGE("flags=0x%x", mFlags); + OVASSERT(mRot, "GenericPipe should have a valid Rot"); + mCtrlData.ctrl.dump(); + mCtrlData.data.dump(); + mRot->dump(); + ALOGE("== Dump Generic pipe end =="); +} + +template +inline bool GenericPipe::isClosed() const { + return utils::getBit(mFlags, CLOSED); +} + +template +inline bool GenericPipe::isOpen() const { + return !isClosed(); +} + +template +inline bool GenericPipe::setClosed() { + return utils::setBit(mFlags, CLOSED); +} + + +} //namespace overlay + +#endif // OVERLAY_GENERIC_PIPE_H diff --git a/liboverlay/pipes/overlayHdmiPipe.h b/liboverlay/pipes/overlayHdmiPipe.h new file mode 100644 index 0000000..48c3817 --- /dev/null +++ b/liboverlay/pipes/overlayHdmiPipe.h @@ -0,0 +1,128 @@ +/* +* Copyright (c) 2011-2012, 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 OVERLAY_HDMI_PIPE_H +#define OVERLAY_HDMI_PIPE_H + +#include "overlayGenPipe.h" +#include "overlayUtils.h" +#include "overlayCtrlData.h" +#include "overlayMdp.h" +#include "overlayRotator.h" + +namespace overlay { + +/* A specific impl of GenericPipe +* Whenever needed to have a pass through - we do it. +* If there is a special need for a different behavior - do it here */ +class HdmiPipe : utils::NoCopy { +public: + /* Please look at overlayGenPipe.h for info */ + explicit HdmiPipe(); + ~HdmiPipe(); + bool open(RotatorBase* rot); + bool close(); + bool commit(); + void setId(int id); + void setMemoryId(int id); + bool queueBuffer(uint32_t offset); + bool dequeueBuffer(void*& buf); + bool waitForVsync(); + bool setCrop(const utils::Dim& dim); + bool start(const utils::PipeArgs& args); + bool setPosition(const utils::Dim& dim); + bool setParameter(const utils::Params& param); + bool setSource(const utils::PipeArgs& args); + const utils::PipeArgs& getArgs() const; + utils::eOverlayPipeType getOvPipeType() const; + void dump() const; +private: + overlay::GenericPipe mHdmi; +}; + +//------------------Inlines ----------------------------- + +inline HdmiPipe::HdmiPipe() {} +inline HdmiPipe::~HdmiPipe() { close(); } +inline bool HdmiPipe::open(RotatorBase* rot) { + ALOGE_IF(DEBUG_OVERLAY, "HdmiPipe open"); + return mHdmi.open(rot); +} +inline bool HdmiPipe::close() { return mHdmi.close(); } +inline bool HdmiPipe::commit() { return mHdmi.commit(); } +inline void HdmiPipe::setId(int id) { mHdmi.setId(id); } +inline void HdmiPipe::setMemoryId(int id) { mHdmi.setMemoryId(id); } +inline bool HdmiPipe::queueBuffer(uint32_t offset) { + return mHdmi.queueBuffer(offset); } +inline bool HdmiPipe::dequeueBuffer(void*& buf) { + return mHdmi.dequeueBuffer(buf); } +inline bool HdmiPipe::waitForVsync() { + return mHdmi.waitForVsync(); } +inline bool HdmiPipe::setCrop(const utils::Dim& dim) { + return mHdmi.setCrop(dim); } +inline bool HdmiPipe::start(const utils::PipeArgs& args) { + return mHdmi.start(args); } +inline bool HdmiPipe::setPosition(const utils::Dim& dim) +{ + utils::Dim d; + // Need to change dim to aspect ratio + if (utils::FrameBufferInfo::getInstance()->supportTrueMirroring()) { + // Use dim info to calculate aspect ratio for true UI mirroring + d = mHdmi.getAspectRatio(dim); + } else { + // Use cached crop data to get aspect ratio + utils::Dim crop = mHdmi.getCrop(); + utils::Whf whf(crop.w, crop.h, 0); + d = mHdmi.getAspectRatio(whf); + } + ALOGE_IF(DEBUG_OVERLAY, "Calculated aspect ratio for HDMI: x=%d, y=%d, w=%d, h=%d, o=%d", + d.x, d.y, d.w, d.h, d.o); + return mHdmi.setPosition(d); +} +inline bool HdmiPipe::setParameter(const utils::Params& param) { + return mHdmi.setParameter(param); } +inline bool HdmiPipe::setSource(const utils::PipeArgs& args) { + utils::PipeArgs arg(args); + return mHdmi.setSource(arg); +} +inline const utils::PipeArgs& HdmiPipe::getArgs() const { + return mHdmi.getArgs(); +} +inline utils::eOverlayPipeType HdmiPipe::getOvPipeType() const { + return utils::OV_PIPE_TYPE_HDMI; +} +inline void HdmiPipe::dump() const { + ALOGE("HDMI Pipe"); + mHdmi.dump(); +} + + +} // overlay + +#endif // OVERLAY_HDMI_PIPE_H diff --git a/liboverlay/pipes/overlayUIMirrorPipe.h b/liboverlay/pipes/overlayUIMirrorPipe.h new file mode 100644 index 0000000..47fbc37 --- /dev/null +++ b/liboverlay/pipes/overlayUIMirrorPipe.h @@ -0,0 +1,192 @@ +/* +* Copyright (c) 2011-2012, 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 OVERLAY_UI_PIPE_H +#define OVERLAY_UI_PIPE_H + +#include "overlayGenPipe.h" +#include "overlayUtils.h" +#include "overlayCtrlData.h" +#include "overlayMdp.h" +#include "overlayRotator.h" + +namespace overlay { + +/* A specific impl of GenericPipe +* Whenever needed to have a pass through - we do it. +* If there is a special need for a different behavior - do it here */ +class UIMirrorPipe : utils::NoCopy { +public: + /* Please look at overlayGenPipe.h for info */ + explicit UIMirrorPipe(); + ~UIMirrorPipe(); + bool open(RotatorBase* rot); + bool close(); + bool commit(); + void setId(int id); + void setMemoryId(int id); + bool queueBuffer(uint32_t offset); + bool dequeueBuffer(void*& buf); + bool waitForVsync(); + bool setCrop(const utils::Dim& dim); + bool start(const utils::PipeArgs& args); + bool setPosition(const utils::Dim& dim); + bool setParameter(const utils::Params& param); + bool setSource(const utils::PipeArgs& args); + const utils::PipeArgs& getArgs() const; + utils::eOverlayPipeType getOvPipeType() const; + void dump() const; +private: + overlay::GenericPipe mUI; +}; + +//----------------------------Inlines ----------------------------- + +inline UIMirrorPipe::UIMirrorPipe() {} +inline UIMirrorPipe::~UIMirrorPipe() { close(); } +inline bool UIMirrorPipe::open(RotatorBase* rot) { + ALOGE_IF(DEBUG_OVERLAY, "UIMirrorPipe open"); + bool ret = mUI.open(rot); + //If source to rotator is framebuffer, which is the case we UI Mirror pipe, + //we need to inform driver during playback. Since FB does not use ION. + rot->setSrcFB(true); + return ret; +} +inline bool UIMirrorPipe::close() { return mUI.close(); } +inline bool UIMirrorPipe::commit() { return mUI.commit(); } +inline void UIMirrorPipe::setId(int id) { mUI.setId(id); } +inline void UIMirrorPipe::setMemoryId(int id) { mUI.setMemoryId(id); } +inline bool UIMirrorPipe::queueBuffer(uint32_t offset) { + return mUI.queueBuffer(offset); } +inline bool UIMirrorPipe::dequeueBuffer(void*& buf) { + return mUI.dequeueBuffer(buf); } +inline bool UIMirrorPipe::waitForVsync() { + return mUI.waitForVsync(); } +inline bool UIMirrorPipe::setCrop(const utils::Dim& dim) { + return mUI.setCrop(dim); } +inline bool UIMirrorPipe::start(const utils::PipeArgs& args) { + if(!mUI.start(args)) { + ALOGE("%s failed to start", __FUNCTION__); + return false; + } + return true; +} +inline bool UIMirrorPipe::setPosition(const utils::Dim& dim) { + + ovutils::Dim pdim; + switch (dim.o) { + case 0: + case HAL_TRANSFORM_ROT_180: + { + ovutils::Whf whf(dim.x, dim.y, 0); + pdim = mUI.getAspectRatio(whf); + break; + } + case HAL_TRANSFORM_ROT_90: + case HAL_TRANSFORM_ROT_270: + { + // Calculate the Aspectratio for the UI in the landscape mode + // Width and height will be swapped as there is rotation + ovutils::Whf whf(dim.y, dim.x, 0); + pdim = mUI.getAspectRatio(whf); + break; + } + default: + ALOGE("%s: Unknown orientation %d", __FUNCTION__, dim.o); + return false; + } + + ovutils::even_out(pdim.x); + ovutils::even_out(pdim.y); + ovutils::even_out(pdim.w); + ovutils::even_out(pdim.h); + return mUI.setPosition(pdim); +} +inline bool UIMirrorPipe::setParameter(const utils::Params& param) { + + OVASSERT(utils::OVERLAY_TRANSFORM_UI == param.param, + "%p Expecting OVERLAY_TRANSFORM_UI", __FUNCTION__); + + int orientation = param.value; + + // Figure out orientation to transform to + switch (param.value) { + case 0: + orientation = 0; + break; + case HAL_TRANSFORM_ROT_180: + orientation = HAL_TRANSFORM_ROT_180; + break; + case HAL_TRANSFORM_ROT_90: + orientation = HAL_TRANSFORM_ROT_270; + break; + case HAL_TRANSFORM_ROT_270: + orientation = HAL_TRANSFORM_ROT_90; + break; + default: + ALOGE("%s: Unknown orientation %d", __FUNCTION__, param.value); + return false; + } + + ovutils::eTransform transform = + static_cast(orientation); + const ovutils::Params prms (ovutils::OVERLAY_TRANSFORM, transform); + return mUI.setParameter(prms); +} + +inline bool UIMirrorPipe::setSource(const utils::PipeArgs& args) { + utils::PipeArgs arg(args); + + // Rotator flag enabled because buffer comes from fb + arg.rotFlags = utils::ROT_FLAG_ENABLED; + + // For true UI mirroring, want the UI to go through available RGB pipe + // so do not set the PIPE SHARE flag which allocates VG pipe + if (utils::FrameBufferInfo::getInstance()->supportTrueMirroring()) { + arg.mdpFlags = static_cast( + arg.mdpFlags & ~utils::OV_MDP_PIPE_SHARE); + } + + return mUI.setSource(arg); +} +inline const utils::PipeArgs& UIMirrorPipe::getArgs() const { + return mUI.getArgs(); +} +inline utils::eOverlayPipeType UIMirrorPipe::getOvPipeType() const { + return utils::OV_PIPE_TYPE_UI_MIRROR; +} +inline void UIMirrorPipe::dump() const { + ALOGE("UI Mirror Pipe"); + mUI.dump(); +} + + +} // overlay + +#endif // OVERLAY_UI_PIPE_H diff --git a/libqcomui/Android.mk b/libqcomui/Android.mk index deb868c..d79929e 100644 --- a/libqcomui/Android.mk +++ b/libqcomui/Android.mk @@ -1,19 +1,19 @@ LOCAL_PATH := $(call my-dir) + +#Headers to export include $(CLEAR_VARS) -LOCAL_SRC_FILES := \ - qcom_ui.cpp +LOCAL_SRC_FILES := qcomutils/profiler.cpp \ + qcomutils/IdleInvalidator.cpp LOCAL_SHARED_LIBRARIES := \ libutils \ libcutils \ libui \ - libEGL + libEGL \ -LOCAL_C_INCLUDES := $(TOP)/hardware/qcom/display/libgralloc \ - $(TOP)/frameworks/native/services/surfaceflinger \ - $(TOP)/external/skia/include/core \ - $(TOP)/external/skia/include/images +LOCAL_C_INCLUDES := hardware/qcom/display/libgralloc \ + frameworks/base/services/surfaceflinger \ LOCAL_CFLAGS := -DLOG_TAG=\"libQcomUI\" @@ -23,6 +23,10 @@ else LOCAL_SHARED_LIBRARIES += libmemalloc endif +ifeq ($(TARGET_USES_MDP3), true) + LOCAL_CFLAGS += -DUSE_MDP3 +endif + LOCAL_CFLAGS += -DDEBUG_CALC_FPS LOCAL_MODULE := libQcomUI diff --git a/libqcomui/qcom_ui.cpp b/libqcomui/qcom_ui.cpp index 9fdd562..d060439 100644 --- a/libqcomui/qcom_ui.cpp +++ b/libqcomui/qcom_ui.cpp @@ -30,86 +30,78 @@ #include #include #include +#include #include #include #include #include #include #include -#if 0 #include #include -#endif #include -#include -#include -#include - using gralloc::IMemAlloc; using gralloc::IonController; using gralloc::alloc_data; using android::sp; - -static int sCompositionType = -1; - namespace { - static android::sp sAlloc = 0; +static android::sp sAlloc = 0; - int reallocate_memory(native_handle_t *buffer_handle, int mReqSize, int usage) - { - int ret = 0; +int reallocate_memory(native_handle_t *buffer_handle, int mReqSize, int usage) +{ + int ret = 0; #ifndef NON_QCOM_TARGET - if (sAlloc == 0) { - sAlloc = gralloc::IAllocController::getInstance(true); - } - if (sAlloc == 0) { - ALOGE("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) { - ALOGE("%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 { - ALOGE("%s: allocate failed", __FUNCTION__); - return -EINVAL; - } -#endif - return ret; + 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; + } +#endif + return ret; +} }; // ANONYNMOUS NAMESPACE /* @@ -128,8 +120,11 @@ int getNumberOfArgsForOperation(int operation) { case NATIVE_WINDOW_UPDATE_BUFFERS_GEOMETRY: num_args = 3; break; - default: ALOGE("%s: invalid operation(0x%x)", __FUNCTION__, operation); + case NATIVE_WINDOW_SET_PIXEL_ASPECT_RATIO: + num_args = 2; break; + default: LOGE("%s: invalid operation(0x%x)", __FUNCTION__, operation); + break; }; return num_args; } @@ -146,43 +141,20 @@ bool isGPUSupportedFormat(int format) { // We check the YV12 formats, since some Qcom specific formats // could have the bits set. return true; + } else if ((format == HAL_PIXEL_FORMAT_RGB_888) || + (format == HAL_PIXEL_FORMAT_YCrCb_422_SP) || + (format == HAL_PIXEL_FORMAT_YCbCr_422_SP)){ + return false; } else if (format & INTERLACE_MASK) { // Interlaced content return false; } else if (format & S3D_FORMAT_MASK) { // S3D Formats are not supported by the GPU - return false; + return false; } return true; } -/* decide the texture target dynamically, based on the pixel format*/ - -int decideTextureTarget(int pixel_format) -{ - - // Default the return value to GL_TEXTURE_EXTERAL_OES - int retVal = GL_TEXTURE_EXTERNAL_OES; - - // Change texture target to TEXTURE_2D for RGB formats - switch (pixel_format) { - - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_RGBX_8888: - case HAL_PIXEL_FORMAT_RGB_888: - case HAL_PIXEL_FORMAT_RGB_565: - case HAL_PIXEL_FORMAT_BGRA_8888: - case HAL_PIXEL_FORMAT_RGBA_5551: - case HAL_PIXEL_FORMAT_RGBA_4444: - retVal = GL_TEXTURE_2D; - break; - default: - retVal = GL_TEXTURE_EXTERNAL_OES; - break; - } - return retVal; -} - /* * Function to check if the allocated buffer is of the correct size. * Reallocate the buffer with the correct size, if the size doesn't @@ -203,7 +175,7 @@ int checkBuffer(native_handle_t *buffer_handle, int size, int usage) // Validate the handle if (private_handle_t::validate(buffer_handle)) { - ALOGE("%s: handle is invalid", __FUNCTION__); + LOGE("%s: handle is invalid", __FUNCTION__); return -EINVAL; } @@ -255,7 +227,7 @@ bool needNewBuffer(const qBufGeometry currentGeometry, int updateBufferGeometry(sp buffer, const qBufGeometry updatedGeometry) { if (buffer == 0) { - ALOGE("%s: graphic buffer is NULL", __FUNCTION__); + LOGE("%s: graphic buffer is NULL", __FUNCTION__); return -EINVAL; } @@ -273,7 +245,7 @@ int updateBufferGeometry(sp buffer, const qBufGeometry updatedGeo // Validate the handle if (private_handle_t::validate(buffer->handle)) { - ALOGE("%s: handle is invalid", __FUNCTION__); + LOGE("%s: handle is invalid", __FUNCTION__); return -EINVAL; } buffer->width = updatedGeometry.width; @@ -285,7 +257,7 @@ int updateBufferGeometry(sp buffer, const qBufGeometry updatedGeo hnd->height = updatedGeometry.height; hnd->format = updatedGeometry.format; } else { - ALOGE("%s: hnd is NULL", __FUNCTION__); + LOGE("%s: hnd is NULL", __FUNCTION__); return -EINVAL; } @@ -293,14 +265,14 @@ int updateBufferGeometry(sp buffer, const qBufGeometry updatedGeo } /* Update the S3D format of this buffer. -* -* @param: buffer whosei S3D format needs to be updated. -* @param: Updated buffer S3D format -*/ + * + * @param: buffer whosei S3D format needs to be updated. + * @param: Updated buffer S3D format + */ int updateBufferS3DFormat(sp buffer, const int s3dFormat) { if (buffer == 0) { - ALOGE("%s: graphic buffer is NULL", __FUNCTION__); + LOGE("%s: graphic buffer is NULL", __FUNCTION__); return -EINVAL; } @@ -331,7 +303,7 @@ int updateLayerQcomFlags(eLayerAttrib attribute, bool enable, int& currentFlags) else currentFlags &= ~LAYER_ASYNCHRONOUS; } break; - default: ALOGE("%s: invalid attribute(0x%x)", __FUNCTION__, attribute); + default: LOGE("%s: invalid attribute(0x%x)", __FUNCTION__, attribute); break; } return ret; @@ -375,42 +347,11 @@ bool isUpdatingFB(HWCCompositionType compositionType) case HWC_USE_COPYBIT: return true; default: - ALOGE("%s: invalid composition type(%d)", __FUNCTION__, compositionType); + LOGE("%s: invalid composition type(%d)", __FUNCTION__, compositionType); return false; }; } -/* - * Get the current composition Type - * - * @return the compositon Type - */ -int getCompositionType() { - char property[PROPERTY_VALUE_MAX]; - int compositionType = 0; - if (property_get("debug.sf.hw", property, NULL) > 0) { - if(atoi(property) == 0) { - compositionType = COMPOSITION_TYPE_CPU; - } else { //debug.sf.hw = 1 - property_get("debug.composition.type", property, NULL); - if (property == NULL) { - compositionType = COMPOSITION_TYPE_GPU; - } else if ((strncmp(property, "mdp", 3)) == 0) { - compositionType = COMPOSITION_TYPE_MDP; - } else if ((strncmp(property, "c2d", 3)) == 0) { - compositionType = COMPOSITION_TYPE_C2D; - } else if ((strncmp(property, "dyn", 3)) == 0) { - compositionType = COMPOSITION_TYPE_DYN; - } else { - compositionType = COMPOSITION_TYPE_GPU; - } - } - } else { //debug.sf.hw is not set. Use cpu composition - compositionType = COMPOSITION_TYPE_CPU; - } - return compositionType; -} - /* * Clear Region implementation for C2D/MDP versions. * @@ -422,31 +363,27 @@ int getCompositionType() { */ int qcomuiClearRegion(Region region, EGLDisplay dpy, EGLSurface sur) { -#if 0 /* FIXME DIE */ int ret = 0; + int compositionType = QCCompositionType::getInstance().getCompositionType(); - if (-1 == sCompositionType) { - sCompositionType = getCompositionType(); - } - - if ((COMPOSITION_TYPE_MDP != sCompositionType) && - (COMPOSITION_TYPE_C2D != sCompositionType) && - (COMPOSITION_TYPE_CPU != sCompositionType)) { - // For non CPU/C2D/MDP composition, return an error, so that SF can use + if (compositionType & COMPOSITION_TYPE_GPU || + (compositionType == COMPOSITION_TYPE_DYN|COMPOSITION_TYPE_C2D)) + { + // For GPU or DYN comp. with C2D, return an error, so that SF can use // the GPU to draw the wormhole. return -1; } android_native_buffer_t *renderBuffer = (android_native_buffer_t *) - eglGetRenderBufferANDROID(dpy, sur); + eglGetRenderBufferANDROID(dpy, sur); if (!renderBuffer) { - ALOGE("%s: eglGetRenderBufferANDROID returned NULL buffer", - __FUNCTION__); - return -1; + LOGE("%s: eglGetRenderBufferANDROID returned NULL buffer", + __FUNCTION__); + return -1; } private_handle_t *fbHandle = (private_handle_t *)renderBuffer->handle; if(!fbHandle) { - ALOGE("%s: Framebuffer handle is NULL", __FUNCTION__); + LOGE("%s: Framebuffer handle is NULL", __FUNCTION__); return -1; } @@ -461,7 +398,7 @@ int qcomuiClearRegion(Region region, EGLDisplay dpy, EGLSurface sur) while (it != end) { const Rect& r = *it++; uint8_t* dst = (uint8_t*) fbHandle->base + - (r.left + r.top*renderBuffer->stride)*bytesPerPixel; + (r.left + r.top*renderBuffer->stride)*bytesPerPixel; int w = r.width()*bytesPerPixel; int h = r.height(); do { @@ -472,42 +409,45 @@ int qcomuiClearRegion(Region region, EGLDisplay dpy, EGLSurface sur) dst += stride; } while(--h); } -#endif return 0; } /* * Handles the externalDisplay event * HDMI has highest priority compared to WifiDisplay - * Based on the current and the new display event, decides the + * Based on the current and the new display type, decides the * external display to be enabled * - * @param: newEvent - new external event - * @param: currEvent - currently enabled external event - * @return: external display to be enabled + * @param: disp - external display type(wfd/hdmi) + * @param: value - external event(0/1) + * @param: currdispType - Current enabled external display Type + * @return: external display type to be enabled * */ -external_display handleEventHDMI(external_display newState, external_display - currState) +external_display_type handleEventHDMI(external_display_type disp, int value, + external_display_type currDispType) { - external_display retState = currState; - switch(newState) { - case EXT_DISPLAY_HDMI: - retState = EXT_DISPLAY_HDMI; + external_display_type retDispType = currDispType; + switch(disp) { + case EXT_TYPE_HDMI: + if(value) + retDispType = EXT_TYPE_HDMI; + else + retDispType = EXT_TYPE_NONE; break; - case EXT_DISPLAY_WIFI: - if(currState != EXT_DISPLAY_HDMI) { - retState = EXT_DISPLAY_WIFI; + case EXT_TYPE_WIFI: + if(currDispType != EXT_TYPE_HDMI) { + if(value) + retDispType = EXT_TYPE_WIFI; + else + retDispType = EXT_TYPE_NONE; } break; - case EXT_DISPLAY_OFF: - retState = EXT_DISPLAY_OFF; - break; default: - ALOGE("handleEventHDMI: unknown Event"); + LOGE("%s: Unknown External Display Type!!"); break; } - return retState; + return retDispType; } // Using global variables for layer dumping since "property_set("debug.sf.dump", @@ -532,25 +472,25 @@ bool needToDumpLayers() localtime_r(&timenow, &sfdump_time); if ((property_get("debug.sf.dump.png", sfdump_propstr, NULL) > 0) && - (strncmp(sfdump_propstr, sfdump_propstr_persist_png, - PROPERTY_VALUE_MAX - 1))) { + (strncmp(sfdump_propstr, sfdump_propstr_persist_png, + PROPERTY_VALUE_MAX - 1))) { // Strings exist & not equal implies it has changed, so trigger a dump strncpy(sfdump_propstr_persist_png, sfdump_propstr, - PROPERTY_VALUE_MAX - 1); + PROPERTY_VALUE_MAX - 1); sfdump_countlimit_png = atoi(sfdump_propstr); sfdump_countlimit_png = (sfdump_countlimit_png < 0) ? 0: - (sfdump_countlimit_png >= LONG_MAX) ? (LONG_MAX - 1): - sfdump_countlimit_png; + (sfdump_countlimit_png >= LONG_MAX) ? (LONG_MAX - 1): + sfdump_countlimit_png; if (sfdump_countlimit_png) { sprintf(sfdumpdir_png,"/data/sfdump.png%04d%02d%02d.%02d%02d%02d", - sfdump_time.tm_year + 1900, sfdump_time.tm_mon + 1, - sfdump_time.tm_mday, sfdump_time.tm_hour, - sfdump_time.tm_min, sfdump_time.tm_sec); + sfdump_time.tm_year + 1900, sfdump_time.tm_mon + 1, + sfdump_time.tm_mday, sfdump_time.tm_hour, + sfdump_time.tm_min, sfdump_time.tm_sec); if (0 == mkdir(sfdumpdir_png, 0777)) sfdump_counter_png = 0; else - ALOGE("sfdump: Error: %s. Failed to create sfdump directory" - ": %s", strerror(errno), sfdumpdir_png); + LOGE("sfdump: Error: %s. Failed to create sfdump directory" + ": %s", strerror(errno), sfdumpdir_png); } } @@ -558,25 +498,25 @@ bool needToDumpLayers() sfdump_counter_png++; if ((property_get("debug.sf.dump", sfdump_propstr, NULL) > 0) && - (strncmp(sfdump_propstr, sfdump_propstr_persist_raw, - PROPERTY_VALUE_MAX - 1))) { + (strncmp(sfdump_propstr, sfdump_propstr_persist_raw, + PROPERTY_VALUE_MAX - 1))) { // Strings exist & not equal implies it has changed, so trigger a dump strncpy(sfdump_propstr_persist_raw, sfdump_propstr, - PROPERTY_VALUE_MAX - 1); + PROPERTY_VALUE_MAX - 1); sfdump_countlimit_raw = atoi(sfdump_propstr); sfdump_countlimit_raw = (sfdump_countlimit_raw < 0) ? 0: - (sfdump_countlimit_raw >= LONG_MAX) ? (LONG_MAX - 1): - sfdump_countlimit_raw; + (sfdump_countlimit_raw >= LONG_MAX) ? (LONG_MAX - 1): + sfdump_countlimit_raw; if (sfdump_countlimit_raw) { sprintf(sfdumpdir_raw,"/data/sfdump.raw%04d%02d%02d.%02d%02d%02d", - sfdump_time.tm_year + 1900, sfdump_time.tm_mon + 1, - sfdump_time.tm_mday, sfdump_time.tm_hour, - sfdump_time.tm_min, sfdump_time.tm_sec); + sfdump_time.tm_year + 1900, sfdump_time.tm_mon + 1, + sfdump_time.tm_mday, sfdump_time.tm_hour, + sfdump_time.tm_min, sfdump_time.tm_sec); if (0 == mkdir(sfdumpdir_raw, 0777)) sfdump_counter_raw = 0; else - ALOGE("sfdump: Error: %s. Failed to create sfdump directory" - ": %s", strerror(errno), sfdumpdir_raw); + LOGE("sfdump: Error: %s. Failed to create sfdump directory" + ": %s", strerror(errno), sfdumpdir_raw); } } @@ -593,85 +533,85 @@ inline void getHalPixelFormatStr(int format, char pixelformatstr[]) return; switch(format) { - case HAL_PIXEL_FORMAT_RGBA_8888: - strcpy(pixelformatstr, "RGBA_8888"); - break; - case HAL_PIXEL_FORMAT_RGBX_8888: - strcpy(pixelformatstr, "RGBX_8888"); - break; - case HAL_PIXEL_FORMAT_RGB_888: - strcpy(pixelformatstr, "RGB_888"); - break; - case HAL_PIXEL_FORMAT_RGB_565: - strcpy(pixelformatstr, "RGB_565"); - break; - case HAL_PIXEL_FORMAT_BGRA_8888: - strcpy(pixelformatstr, "BGRA_8888"); - break; - case HAL_PIXEL_FORMAT_RGBA_5551: - strcpy(pixelformatstr, "RGBA_5551"); - break; - case HAL_PIXEL_FORMAT_RGBA_4444: - strcpy(pixelformatstr, "RGBA_4444"); - break; - case HAL_PIXEL_FORMAT_YV12: - strcpy(pixelformatstr, "YV12"); - break; - case HAL_PIXEL_FORMAT_YCbCr_422_SP: - strcpy(pixelformatstr, "YCbCr_422_SP_NV16"); - break; - case HAL_PIXEL_FORMAT_YCrCb_420_SP: - strcpy(pixelformatstr, "YCrCb_420_SP_NV21"); - break; - case HAL_PIXEL_FORMAT_YCbCr_422_I: - strcpy(pixelformatstr, "YCbCr_422_I_YUY2"); - break; - case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: - strcpy(pixelformatstr, "NV12_ENCODEABLE"); - break; - case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: - strcpy(pixelformatstr, "YCbCr_420_SP_TILED_TILE_4x2"); - break; - case HAL_PIXEL_FORMAT_YCbCr_420_SP: - strcpy(pixelformatstr, "YCbCr_420_SP"); - break; - case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: - strcpy(pixelformatstr, "YCrCb_420_SP_ADRENO"); - break; - case HAL_PIXEL_FORMAT_YCrCb_422_SP: - strcpy(pixelformatstr, "YCrCb_422_SP"); - break; - case HAL_PIXEL_FORMAT_R_8: - strcpy(pixelformatstr, "R_8"); - break; - case HAL_PIXEL_FORMAT_RG_88: - strcpy(pixelformatstr, "RG_88"); - break; - case HAL_PIXEL_FORMAT_INTERLACE: - strcpy(pixelformatstr, "INTERLACE"); - break; - default: - sprintf(pixelformatstr, "Unknown0x%X", format); - break; + case HAL_PIXEL_FORMAT_RGBA_8888: + strcpy(pixelformatstr, "RGBA_8888"); + break; + case HAL_PIXEL_FORMAT_RGBX_8888: + strcpy(pixelformatstr, "RGBX_8888"); + break; + case HAL_PIXEL_FORMAT_RGB_888: + strcpy(pixelformatstr, "RGB_888"); + break; + case HAL_PIXEL_FORMAT_RGB_565: + strcpy(pixelformatstr, "RGB_565"); + break; + case HAL_PIXEL_FORMAT_BGRA_8888: + strcpy(pixelformatstr, "BGRA_8888"); + break; + case HAL_PIXEL_FORMAT_RGBA_5551: + strcpy(pixelformatstr, "RGBA_5551"); + break; + case HAL_PIXEL_FORMAT_RGBA_4444: + strcpy(pixelformatstr, "RGBA_4444"); + break; + case HAL_PIXEL_FORMAT_YV12: + strcpy(pixelformatstr, "YV12"); + break; + case HAL_PIXEL_FORMAT_YCbCr_422_SP: + strcpy(pixelformatstr, "YCbCr_422_SP_NV16"); + break; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + strcpy(pixelformatstr, "YCrCb_420_SP_NV21"); + break; + case HAL_PIXEL_FORMAT_YCbCr_422_I: + strcpy(pixelformatstr, "YCbCr_422_I_YUY2"); + break; + case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: + strcpy(pixelformatstr, "NV12_ENCODEABLE"); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: + strcpy(pixelformatstr, "YCbCr_420_SP_TILED_TILE_4x2"); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_SP: + strcpy(pixelformatstr, "YCbCr_420_SP"); + break; + case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: + strcpy(pixelformatstr, "YCrCb_420_SP_ADRENO"); + break; + case HAL_PIXEL_FORMAT_YCrCb_422_SP: + strcpy(pixelformatstr, "YCrCb_422_SP"); + break; + case HAL_PIXEL_FORMAT_R_8: + strcpy(pixelformatstr, "R_8"); + break; + case HAL_PIXEL_FORMAT_RG_88: + strcpy(pixelformatstr, "RG_88"); + break; + case HAL_PIXEL_FORMAT_INTERLACE: + strcpy(pixelformatstr, "INTERLACE"); + break; + default: + sprintf(pixelformatstr, "Unknown0x%X", format); + break; } } void dumpLayer(int moduleCompositionType, int listFlags, size_t layerIndex, - hwc_layer_t hwLayers[]) + hwc_layer_t hwLayers[]) { char dumplogstr_png[128] = ""; char dumplogstr_raw[128] = ""; if (sfdump_counter_png <= sfdump_countlimit_png) { sprintf(dumplogstr_png, "[png-dump-frame: %03d of %03d] ", - sfdump_counter_png, sfdump_countlimit_png); + sfdump_counter_png, sfdump_countlimit_png); } if (sfdump_counter_raw <= sfdump_countlimit_raw) { sprintf(dumplogstr_raw, "[raw-dump-frame: %03d of %03d]", - sfdump_counter_raw, sfdump_countlimit_raw); + sfdump_counter_raw, sfdump_countlimit_raw); } if (NULL == hwLayers) { - ALOGE("sfdump: Error.%s%sLayer[%d] No hwLayers to dump.", - dumplogstr_raw, dumplogstr_png, layerIndex); + LOGE("sfdump: Error.%s%sLayer[%d] No hwLayers to dump.", + dumplogstr_raw, dumplogstr_png, layerIndex); return; } hwc_layer *layer = &hwLayers[layerIndex]; @@ -679,263 +619,245 @@ void dumpLayer(int moduleCompositionType, int listFlags, size_t layerIndex, hwc_rect_t displayFrame = layer->displayFrame; private_handle_t *hnd = (private_handle_t *)layer->handle; char pixelformatstr[32] = "None"; + uint32_t transform = layer->transform & FINAL_TRANSFORM_MASK; if (hnd) getHalPixelFormatStr(hnd->format, pixelformatstr); -#if 0 - ALOGE("sfdump: %s%s[%s]-Composition, Layer[%d] SrcBuff[%dx%d] " - "SrcCrop[%dl, %dt, %dr, %db] " - "DispFrame[%dl, %dt, %dr, %db] Composition-type = %s, Format = %s, " - "Orientation = %s, Flags = %s%s%s%s%s%s%s%s%s%s", - dumplogstr_raw, dumplogstr_png, - (moduleCompositionType == COMPOSITION_TYPE_GPU)? "GPU": - (moduleCompositionType == COMPOSITION_TYPE_MDP)? "MDP": - (moduleCompositionType == COMPOSITION_TYPE_C2D)? "C2D": - (moduleCompositionType == COMPOSITION_TYPE_CPU)? "CPU": - (moduleCompositionType == COMPOSITION_TYPE_DYN)? "DYN": "???", - layerIndex, - (hnd)? hnd->width : -1, (hnd)? hnd->height : -1, - sourceCrop.left, sourceCrop.top, - sourceCrop.right, sourceCrop.bottom, - displayFrame.left, displayFrame.top, - displayFrame.right, displayFrame.bottom, - (layer->compositionType == HWC_FRAMEBUFFER)? "Framebuffer (OpenGL ES)": - (layer->compositionType == HWC_OVERLAY)? "Overlay": - (layer->compositionType == HWC_USE_COPYBIT)? "Copybit": "???", - pixelformatstr, - (layer->transform == Transform::ROT_0)? "ROT_0": - (layer->transform == Transform::FLIP_H)? "FLIP_H": - (layer->transform == Transform::FLIP_V)? "FLIP_V": - (layer->transform == Transform::ROT_90)? "ROT_90": - (layer->transform == Transform::ROT_180)? "ROT_180": - (layer->transform == Transform::ROT_270)? "ROT_270": - (layer->transform == Transform::ROT_INVALID)? "ROT_INVALID":"???", - (layer->flags == 0)? "[None]":"", - (layer->flags & HWC_SKIP_LAYER)? "[Skip layer]":"", - (layer->flags & HWC_LAYER_NOT_UPDATING)? "[Layer not updating]":"", - (layer->flags & HWC_USE_ORIGINAL_RESOLUTION)? "[Original Resolution]":"", - (layer->flags & HWC_DO_NOT_USE_OVERLAY)? "[Do not use Overlay]":"", - (layer->flags & HWC_COMP_BYPASS)? "[Bypass]":"", - (layer->flags & HWC_BYPASS_RESERVE_0)? "[Bypass Reserve 0]":"", - (layer->flags & HWC_BYPASS_RESERVE_1)? "[Bypass Reserve 1]":"", - (listFlags & HWC_GEOMETRY_CHANGED)? "[List: Geometry Changed]":"", - (listFlags & HWC_SKIP_COMPOSITION)? "[List: Skip Composition]":""); -#endif - if (NULL == hnd) { - ALOGE("sfdump: %s%sLayer[%d] private-handle is invalid.", - dumplogstr_raw, dumplogstr_png, layerIndex); - return; - } - if ((sfdump_counter_png <= sfdump_countlimit_png) && hnd->base) { -#if 0 - bool bResult = false; - char sfdumpfile_name[256]; - SkBitmap *tempSkBmp = new SkBitmap(); - SkBitmap::Config tempSkBmpConfig = SkBitmap::kNo_Config; - sprintf(sfdumpfile_name, "%s/sfdump%03d_layer%d.png", sfdumpdir_png, - sfdump_counter_png, layerIndex); + LOGE("sfdump: %s%s[%s]-Composition, Layer[%d] SrcBuff[%dx%d] " + "SrcCrop[%dl, %dt, %dr, %db] " + "DispFrame[%dl, %dt, %dr, %db] Composition-type = %s, Format = %s, " + "Orientation = %s, Flags = %s%s%s%s%s%s%s%s%s%s", + dumplogstr_raw, dumplogstr_png, + (moduleCompositionType == COMPOSITION_TYPE_GPU)? "GPU": + (moduleCompositionType == COMPOSITION_TYPE_MDP)? "MDP": + (moduleCompositionType == COMPOSITION_TYPE_C2D)? "C2D": + (moduleCompositionType == COMPOSITION_TYPE_CPU)? "CPU": + (moduleCompositionType == COMPOSITION_TYPE_DYN)? "DYN": "???", + layerIndex, + (hnd)? hnd->width : -1, (hnd)? hnd->height : -1, + sourceCrop.left, sourceCrop.top, + sourceCrop.right, sourceCrop.bottom, + displayFrame.left, displayFrame.top, + displayFrame.right, displayFrame.bottom, + (layer->compositionType == HWC_FRAMEBUFFER)? "Framebuffer (OpenGL ES)": + (layer->compositionType == HWC_OVERLAY)? "Overlay": + (layer->compositionType == HWC_USE_COPYBIT)? "Copybit": "???", + pixelformatstr, + (transform == Transform::ROT_0)? "ROT_0": + (transform == Transform::FLIP_H)? "FLIP_H": + (transform == Transform::FLIP_V)? "FLIP_V": + (transform == Transform::ROT_90)? "ROT_90": + (transform == Transform::ROT_180)? "ROT_180": + (transform == Transform::ROT_270)? "ROT_270": + (transform == Transform::ROT_INVALID)? "ROT_INVALID":"???", + (layer->flags == 0)? "[None]":"", + (layer->flags & HWC_SKIP_LAYER)? "[Skip layer]":"", + (layer->flags & HWC_LAYER_NOT_UPDATING)? "[Layer not updating]":"", + (layer->flags & HWC_COMP_BYPASS)? "[Bypass]":"", + (layer->flags & HWC_BYPASS_RESERVE_0)? "[Bypass Reserve 0]":"", + (layer->flags & HWC_BYPASS_RESERVE_1)? "[Bypass Reserve 1]":"", + (listFlags & HWC_GEOMETRY_CHANGED)? "[List: Geometry Changed]":"", + (listFlags & HWC_SKIP_COMPOSITION)? "[List: Skip Composition]":""); - switch (hnd->format) { - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_RGBX_8888: - case HAL_PIXEL_FORMAT_BGRA_8888: - tempSkBmpConfig = SkBitmap::kARGB_8888_Config; - break; - case HAL_PIXEL_FORMAT_RGB_565: - case HAL_PIXEL_FORMAT_RGBA_5551: - case HAL_PIXEL_FORMAT_RGBA_4444: - tempSkBmpConfig = SkBitmap::kRGB_565_Config; - break; - case HAL_PIXEL_FORMAT_RGB_888: - default: - tempSkBmpConfig = SkBitmap::kNo_Config; - break; - } - if (SkBitmap::kNo_Config != tempSkBmpConfig) { - tempSkBmp->setConfig(tempSkBmpConfig, hnd->width, hnd->height); - tempSkBmp->setPixels((void*)hnd->base); - bResult = SkImageEncoder::EncodeFile(sfdumpfile_name, - *tempSkBmp, SkImageEncoder::kPNG_Type, 100); - ALOGE("sfdump: %sDumped Layer[%d] to %s: %s", dumplogstr_png, - layerIndex, sfdumpfile_name, bResult ? "Success" : "Fail"); - } - else { - ALOGE("sfdump: %sSkipping Layer[%d] dump: Unsupported layer " - "format %s for png encoder.", dumplogstr_png, layerIndex, - pixelformatstr); - } - delete tempSkBmp; // Calls SkBitmap::freePixels() internally. -#endif - } - - if ((sfdump_counter_raw <= sfdump_countlimit_raw) && hnd->base) { - char sfdumpfile_name[256]; - bool bResult = false; - sprintf(sfdumpfile_name, "%s/sfdump%03d_layer%d_%dx%d_%s.raw", - sfdumpdir_raw, - sfdump_counter_raw, layerIndex, hnd->width, hnd->height, - pixelformatstr); - FILE* fp = fopen(sfdumpfile_name, "w+"); - if (fp != NULL) { - bResult = (bool) fwrite((void*)hnd->base, hnd->size, 1, fp); - fclose(fp); - } - ALOGE("sfdump: %s Dumped Layer[%d] to %s: %s", dumplogstr_raw, - layerIndex, sfdumpfile_name, bResult ? "Success" : "Fail"); - } -} - -#ifdef DEBUG_CALC_FPS -ANDROID_SINGLETON_STATIC_INSTANCE(CalcFps) ; - -CalcFps::CalcFps() { - debug_fps_level = 0; - Init(); -} - -CalcFps::~CalcFps() { -} - -void CalcFps::Init() { - char prop[PROPERTY_VALUE_MAX]; - property_get("debug.gr.calcfps", prop, "0"); - debug_fps_level = atoi(prop); - if (debug_fps_level > MAX_DEBUG_FPS_LEVEL) { - ALOGW("out of range value for debug.gr.calcfps, using 0"); - debug_fps_level = 0; - } - - ALOGE("DEBUG_CALC_FPS: %d", debug_fps_level); - populate_debug_fps_metadata(); -} - -void CalcFps::Fps() { - if (debug_fps_level > 0) - calc_fps(ns2us(systemTime())); -} - -void CalcFps::populate_debug_fps_metadata(void) -{ - char prop[PROPERTY_VALUE_MAX]; - - /*defaults calculation of fps to based on number of frames*/ - property_get("debug.gr.calcfps.type", prop, "0"); - debug_fps_metadata.type = (debug_fps_metadata_t::DfmType) atoi(prop); - - /*defaults to 1000ms*/ - property_get("debug.gr.calcfps.timeperiod", prop, "1000"); - debug_fps_metadata.time_period = atoi(prop); - - property_get("debug.gr.calcfps.period", prop, "10"); - debug_fps_metadata.period = atoi(prop); - - if (debug_fps_metadata.period > MAX_FPS_CALC_PERIOD_IN_FRAMES) { - debug_fps_metadata.period = MAX_FPS_CALC_PERIOD_IN_FRAMES; - } - - /* default ignorethresh_us: 500 milli seconds */ - property_get("debug.gr.calcfps.ignorethresh_us", prop, "500000"); - debug_fps_metadata.ignorethresh_us = atoi(prop); - - debug_fps_metadata.framearrival_steps = - (debug_fps_metadata.ignorethresh_us / 16666); - - if (debug_fps_metadata.framearrival_steps > MAX_FRAMEARRIVAL_STEPS) { - debug_fps_metadata.framearrival_steps = MAX_FRAMEARRIVAL_STEPS; - debug_fps_metadata.ignorethresh_us = - debug_fps_metadata.framearrival_steps * 16666; - } - - /* 2ms margin of error for the gettimeofday */ - debug_fps_metadata.margin_us = 2000; - - for (unsigned int i = 0; i < MAX_FRAMEARRIVAL_STEPS; i++) - debug_fps_metadata.accum_framearrivals[i] = 0; - - ALOGE("period: %d", debug_fps_metadata.period); - ALOGE("ignorethresh_us: %lld", debug_fps_metadata.ignorethresh_us); -} - -void CalcFps::print_fps(float fps) -{ - if (debug_fps_metadata_t::DFM_FRAMES == debug_fps_metadata.type) - ALOGE("FPS for last %d frames: %3.2f", debug_fps_metadata.period, fps); - else - ALOGE("FPS for last (%f ms, %d frames): %3.2f", - debug_fps_metadata.time_elapsed, - debug_fps_metadata.curr_frame, fps); - - debug_fps_metadata.curr_frame = 0; - debug_fps_metadata.time_elapsed = 0.0; - - if (debug_fps_level > 1) { - ALOGE("Frame Arrival Distribution:"); - for (unsigned int i = 0; - i < ((debug_fps_metadata.framearrival_steps / 6) + 1); - i++) { - ALOGE("%lld %lld %lld %lld %lld %lld", - debug_fps_metadata.accum_framearrivals[i*6], - debug_fps_metadata.accum_framearrivals[i*6+1], - debug_fps_metadata.accum_framearrivals[i*6+2], - debug_fps_metadata.accum_framearrivals[i*6+3], - debug_fps_metadata.accum_framearrivals[i*6+4], - debug_fps_metadata.accum_framearrivals[i*6+5]); - } - - /* We are done with displaying, now clear the stats */ - for (unsigned int i = 0; - i < debug_fps_metadata.framearrival_steps; - i++) - debug_fps_metadata.accum_framearrivals[i] = 0; - } - return; -} - -void CalcFps::calc_fps(nsecs_t currtime_us) -{ - static nsecs_t oldtime_us = 0; - - nsecs_t diff = currtime_us - oldtime_us; - - oldtime_us = currtime_us; - - if (debug_fps_metadata_t::DFM_FRAMES == debug_fps_metadata.type && - diff > debug_fps_metadata.ignorethresh_us) { + if (NULL == hnd) { + LOGE("sfdump: %s%sLayer[%d] private-handle is invalid.", + dumplogstr_raw, dumplogstr_png, layerIndex); return; } - if (debug_fps_metadata.curr_frame < MAX_FPS_CALC_PERIOD_IN_FRAMES) { - debug_fps_metadata.framearrivals[debug_fps_metadata.curr_frame] = diff; - } + if ((sfdump_counter_png <= sfdump_countlimit_png) && hnd->base) { + bool bResult = false; + char sfdumpfile_name[256]; + SkBitmap *tempSkBmp = new SkBitmap(); + SkBitmap::Config tempSkBmpConfig = SkBitmap::kNo_Config; + sprintf(sfdumpfile_name, "%s/sfdump%03d_layer%d.png", sfdumpdir_png, + sfdump_counter_png, layerIndex); - debug_fps_metadata.curr_frame++; - - if (debug_fps_level > 1) { - unsigned int currstep = (diff + debug_fps_metadata.margin_us) / 16666; - - if (currstep < debug_fps_metadata.framearrival_steps) { - debug_fps_metadata.accum_framearrivals[currstep-1]++; + switch (hnd->format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGBX_8888: + case HAL_PIXEL_FORMAT_BGRA_8888: + tempSkBmpConfig = SkBitmap::kARGB_8888_Config; + break; + case HAL_PIXEL_FORMAT_RGB_565: + case HAL_PIXEL_FORMAT_RGBA_5551: + case HAL_PIXEL_FORMAT_RGBA_4444: + tempSkBmpConfig = SkBitmap::kRGB_565_Config; + break; + case HAL_PIXEL_FORMAT_RGB_888: + default: + tempSkBmpConfig = SkBitmap::kNo_Config; + break; } + if (SkBitmap::kNo_Config != tempSkBmpConfig) { + tempSkBmp->setConfig(tempSkBmpConfig, hnd->width, hnd->height); + tempSkBmp->setPixels((void*)hnd->base); + bResult = SkImageEncoder::EncodeFile(sfdumpfile_name, + *tempSkBmp, SkImageEncoder::kPNG_Type, 100); + LOGE("sfdump: %sDumped Layer[%d] to %s: %s", dumplogstr_png, + layerIndex, sfdumpfile_name, bResult ? "Success" : "Fail"); + } + else { + LOGE("sfdump: %sSkipping Layer[%d] dump: Unsupported layer " + "format %s for png encoder.", dumplogstr_png, layerIndex, + pixelformatstr); + } + delete tempSkBmp; // Calls SkBitmap::freePixels() internally. } - if (debug_fps_metadata_t::DFM_FRAMES == debug_fps_metadata.type) { - if (debug_fps_metadata.curr_frame == debug_fps_metadata.period) { - /* time to calculate and display FPS */ - nsecs_t sum = 0; - for (unsigned int i = 0; i < debug_fps_metadata.period; i++) - sum += debug_fps_metadata.framearrivals[i]; - print_fps((debug_fps_metadata.period * float(1000000))/float(sum)); + if ((sfdump_counter_raw <= sfdump_countlimit_raw) && hnd->base) { + char sfdumpfile_name[256]; + bool bResult = false; + sprintf(sfdumpfile_name, "%s/sfdump%03d_layer%d_%dx%d_%s.raw", + sfdumpdir_raw, + sfdump_counter_raw, layerIndex, hnd->width, hnd->height, + pixelformatstr); + FILE* fp = fopen(sfdumpfile_name, "w+"); + if (fp != NULL) { + bResult = (bool) fwrite((void*)hnd->base, hnd->size, 1, fp); + fclose(fp); } + LOGE("sfdump: %s Dumped Layer[%d] to %s: %s", dumplogstr_raw, + layerIndex, sfdumpfile_name, bResult ? "Success" : "Fail"); } - else if (debug_fps_metadata_t::DFM_TIME == debug_fps_metadata.type) { - debug_fps_metadata.time_elapsed += ((float)diff/1000.0); - if (debug_fps_metadata.time_elapsed >= debug_fps_metadata.time_period) { - float fps = (1000.0 * debug_fps_metadata.curr_frame)/ - (float)debug_fps_metadata.time_elapsed; - print_fps(fps); - } - } - return; } -#endif + +bool needsAspectRatio (int wRatio, int hRatio) { + return ((wRatio != DEFAULT_WIDTH_RATIO) || (hRatio != DEFAULT_HEIGHT_RATIO)); +} + +void applyPixelAspectRatio (int wRatio, int hRatio, int orientation, int maxWidth, + int maxHeight, Rect& visibleRect, GLfloat mVertices[][2]) { + + if ((wRatio == 0) || (hRatio == 0)) + return; + + float wDelta = 0; + float hDelta = 0; + float aspectRatio; + float displayRatio; + float new_width, new_height; + float old_width = abs(visibleRect.right - visibleRect.left); + float old_height = abs(visibleRect.bottom - visibleRect.top); + + if (orientation == Transform::ROT_INVALID) { + // During animation, no defined orientation, rely on mTransformedBounds + if (old_width >= old_height) + orientation = Transform::ROT_0; + else + orientation = Transform::ROT_90; + } + + switch (orientation) { + + case Transform::ROT_0: + case Transform::ROT_180: + + // Calculated Aspect Ratio = Original Aspect Ratio x Pixel Aspect Ratio + aspectRatio = (old_width * wRatio) / (old_height * hRatio); + displayRatio = (float)maxWidth / (float)maxHeight; + + if (aspectRatio >= displayRatio) { + new_height = old_width / aspectRatio; + if (new_height > maxHeight) { + new_height = maxHeight; + new_width = new_height * aspectRatio; + wDelta = (new_width - old_width) / 2; + } + hDelta = (new_height - old_height) / 2; + } else { + new_width = old_height * aspectRatio; + if (new_width > maxWidth) { + new_width = maxWidth; + new_height = new_width / aspectRatio; + hDelta = (new_height - old_height) / 2; + } + wDelta = (new_width - old_width) / 2; + } + + if (hDelta != 0) { + visibleRect.top -= hDelta; + visibleRect.bottom += hDelta; + + // Set mVertices for GPU fallback (During rotation) + if (orientation == Transform::ROT_0) { + mVertices[1][1] = mVertices[2][1] = visibleRect.top; + mVertices[0][1] = mVertices[3][1] = visibleRect.bottom; + } else { + mVertices[0][1] = mVertices[3][1] = visibleRect.top; + mVertices[1][1] = mVertices[2][1] = visibleRect.bottom; + } + } + + if (wDelta != 0) { + visibleRect.left -= wDelta; + visibleRect.right += wDelta; + + // Set mVertices for GPU fallback (During rotation) + mVertices[0][0] = mVertices[1][0] = visibleRect.left; + mVertices[2][0] = mVertices[3][0] = visibleRect.right; + } + break; + + case Transform::ROT_90: + case Transform::ROT_270: + + // Calculated Aspect Ratio = Original Aspect Ratio x Pixel Aspect Ratio + aspectRatio = (old_height * wRatio) / (old_width * hRatio); + displayRatio = (float)maxHeight / (float)maxWidth; + + if (aspectRatio >= displayRatio) { + new_height = old_width * aspectRatio; + if (new_height > maxHeight) { + new_height = maxHeight; + new_width = new_height / aspectRatio; + wDelta = (new_width - old_width) / 2; + } + hDelta = (new_height - old_height) / 2; + } else { + new_width = old_height / aspectRatio; + if (new_width > maxWidth) { + new_width = maxWidth; + new_height = new_width * aspectRatio; + hDelta = (new_height - old_height) / 2; + } + wDelta = (new_width - old_width) / 2; + } + + if (hDelta != 0) { + visibleRect.top -= hDelta; + visibleRect.bottom += hDelta; + + // Set mVertices for GPU fallback (During rotation) + if (orientation == Transform::ROT_90) { + mVertices[2][1] = mVertices[3][1] = visibleRect.top; + mVertices[0][1] = mVertices[1][1] = visibleRect.bottom; + } else { + mVertices[0][1] = mVertices[1][1] = visibleRect.top; + mVertices[2][1] = mVertices[3][1] = visibleRect.bottom; + } + } + + if (wDelta != 0) { + visibleRect.left -= wDelta; + visibleRect.right += wDelta; + + // Set mVertices for GPU fallback (During rotation) + if (orientation == Transform::ROT_90) { + mVertices[1][0] = mVertices[2][0] = visibleRect.left; + mVertices[0][0] = mVertices[3][0] = visibleRect.right; + } else { + mVertices[0][0] = mVertices[3][0] = visibleRect.left; + mVertices[1][0] = mVertices[2][0] = visibleRect.right; + } + } + break; + + default: // Handled above. + break; + + } +} + + diff --git a/libqcomui/qcom_ui.h b/libqcomui/qcom_ui.h index 88462cc..89974bd 100644 --- a/libqcomui/qcom_ui.h +++ b/libqcomui/qcom_ui.h @@ -33,18 +33,19 @@ #include #include #include -#include #include #include +#include #include #include -#include "../libgralloc/gralloc_priv.h" using namespace android; using android::sp; using android::GraphicBuffer; #define HWC_BYPASS_INDEX_MASK 0x00000030 +#define DEFAULT_WIDTH_RATIO 1 +#define DEFAULT_HEIGHT_RATIO 1 /* * Qcom specific Native Window perform operations @@ -53,15 +54,7 @@ enum { NATIVE_WINDOW_SET_BUFFERS_SIZE = 0x10000000, NATIVE_WINDOW_UPDATE_BUFFERS_GEOMETRY = 0x20000000, NATIVE_WINDOW_SET_S3D_FORMAT = 0x40000000, -}; - -// Enum containing the supported composition types -enum { - COMPOSITION_TYPE_GPU = 0, - COMPOSITION_TYPE_MDP = 0x1, - COMPOSITION_TYPE_C2D = 0x2, - COMPOSITION_TYPE_CPU = 0x4, - COMPOSITION_TYPE_DYN = 0x8 + NATIVE_WINDOW_SET_PIXEL_ASPECT_RATIO = 0x80000000, }; /* @@ -80,17 +73,22 @@ enum { LAYER_ASYNCHRONOUS = 1<<1, }; +/* + * Layer Transformation - refers to Layer::setGeometry() + */ +#define SHIFT_SRC_TRANSFORM 4 +#define SRC_TRANSFORM_MASK 0x00F0 +#define FINAL_TRANSFORM_MASK 0x000F + /* * Flags set by the layer and sent to HWC */ enum { HWC_LAYER_NOT_UPDATING = 0x00000002, HWC_LAYER_ASYNCHRONOUS = 0x00000004, - HWC_USE_ORIGINAL_RESOLUTION = 0x10000000, - HWC_DO_NOT_USE_OVERLAY = 0x20000000, - HWC_COMP_BYPASS = 0x40000000, - HWC_USE_EXT_ONLY = 0x80000000, //Layer displayed on external only - HWC_USE_EXT_BLOCK = 0x01000000, //Layer displayed on external only + HWC_COMP_BYPASS = 0x10000000, + HWC_USE_EXT_ONLY = 0x20000000, //Layer displayed on external only + HWC_USE_EXT_BLOCK = 0x40000000, //Layer displayed on external only HWC_BYPASS_RESERVE_0 = 0x00000010, HWC_BYPASS_RESERVE_1 = 0x00000020, }; @@ -101,10 +99,41 @@ enum HWCCompositionType { HWC_USE_COPYBIT // This layer is to be handled by copybit }; -enum external_display { - EXT_DISPLAY_OFF, - EXT_DISPLAY_HDMI, - EXT_DISPLAY_WIFI +enum external_display_type { + EXT_TYPE_NONE, + EXT_TYPE_HDMI, + EXT_TYPE_WIFI +}; + +/* Events to the Display HAL perform function + As of now used for external display related such as + connect, disconnect, orientation, video started etc., + */ +enum { + EVENT_EXTERNAL_DISPLAY, // External display on/off Event + EVENT_VIDEO_OVERLAY, // Video Overlay start/stop Event + EVENT_ORIENTATION_CHANGE, // Orientation Change Event + EVENT_OVERLAY_STATE_CHANGE, // Overlay State Change Event + EVENT_OPEN_SECURE_START, // Start of secure session setup config by stagefright + EVENT_OPEN_SECURE_END, // End of secure session setup config by stagefright + EVENT_CLOSE_SECURE_START, // Start of secure session teardown config + EVENT_CLOSE_SECURE_END, // End of secure session teardown config + EVENT_RESET_POSTBUFFER, // Reset post framebuffer mutex + EVENT_WAIT_POSTBUFFER, // Wait until post framebuffer returns +}; + +// Video information sent to framebuffer HAl +// used for handling UI mirroring. +enum { + VIDEO_OVERLAY_ENDED = 0, + VIDEO_2D_OVERLAY_STARTED, + VIDEO_3D_OVERLAY_STARTED +}; + +// Information about overlay state change +enum { + OVERLAY_STATE_CHANGE_START = 0, + OVERLAY_STATE_CHANGE_END }; /* @@ -115,86 +144,18 @@ struct qBufGeometry { int height; int format; void set(int w, int h, int f) { - width = w; - height = h; - format = f; + width = w; + height = h; + format = f; } }; -#ifndef DEBUG_CALC_FPS -#define CALC_FPS() ((void)0) -#define CALC_INIT() ((void)0) -#else -#define CALC_FPS() CalcFps::getInstance().Fps() -#define CALC_INIT() CalcFps::getInstance().Init() - -class CalcFps : public Singleton { -public: - CalcFps(); - ~CalcFps(); - - void Init(); - void Fps(); - -private: - static const unsigned int MAX_FPS_CALC_PERIOD_IN_FRAMES = 128; - static const unsigned int MAX_FRAMEARRIVAL_STEPS = 50; - static const unsigned int MAX_DEBUG_FPS_LEVEL = 2; - - struct debug_fps_metadata_t { - /*fps calculation based on time or number of frames*/ - enum DfmType { - DFM_FRAMES = 0, - DFM_TIME = 1, - }; - - DfmType type; - - /* indicates how much time do we wait till we calculate FPS */ - unsigned long time_period; - - /*indicates how much time elapsed since we report fps*/ - float time_elapsed; - - /* indicates how many frames do we wait till we calculate FPS */ - unsigned int period; - /* current frame, will go upto period, and then reset */ - unsigned int curr_frame; - /* frame will arrive at a multiple of 16666 us at the display. - This indicates how many steps to consider for our calculations. - For example, if framearrival_steps = 10, then the frame that arrived - after 166660 us or more will be ignored. - */ - unsigned int framearrival_steps; - /* ignorethresh_us = framearrival_steps * 16666 */ - nsecs_t ignorethresh_us; - /* used to calculate the actual frame arrival step, the times might not be - accurate - */ - unsigned int margin_us; - - /* actual data storage */ - nsecs_t framearrivals[MAX_FPS_CALC_PERIOD_IN_FRAMES]; - nsecs_t accum_framearrivals[MAX_FRAMEARRIVAL_STEPS]; - }; - -private: - void populate_debug_fps_metadata(void); - void print_fps(float fps); - void calc_fps(nsecs_t currtime_us); - -private: - debug_fps_metadata_t debug_fps_metadata; - unsigned int debug_fps_level; -}; -#endif - #if 0 class QCBaseLayer { -// int mS3DFormat; + // int mS3DFormat; int32_t mComposeS3DFormat; -public: + public: QCBaseLayer() { mComposeS3DFormat = 0; @@ -203,10 +164,10 @@ public: eS3D_SIDE_BY_SIDE = 0x10000, eS3D_TOP_BOTTOM = 0x20000 }; -/* - virtual status_t setStereoscopic3DFormat(int format) { mS3DFormat = format; return 0; } - virtual int getStereoscopic3DFormat() const { return mS3DFormat; } - */ + /* + virtual status_t setStereoscopic3DFormat(int format) { mS3DFormat = format; return 0; } + virtual int getStereoscopic3DFormat() const { return mS3DFormat; } + */ void setS3DComposeFormat (int32_t hints) { if (hints & HWC_HINT_DRAW_S3D_SIDE_BY_SIDE) @@ -242,21 +203,6 @@ int checkBuffer(native_handle_t *buffer_handle, int size, int usage); */ bool isGPUSupportedFormat(int format); -/* - * Adreno is not optimized for GL_TEXTURE_EXTERNAL_OES - * texure target. DO NOT choose TEXTURE_EXTERNAL_OES - * target for RGB formats. - * - * Based on the pixel format, decide the texture target. - * - * @param : pixel format to check - * - * @return : GL_TEXTURE_2D for RGB formats, and - * GL_TEXTURE_EXTERNAL_OES for YUV formats. - * -*/ - -int decideTextureTarget (const int pixel_format); /* * Gets the number of arguments required for this operation. @@ -277,8 +223,8 @@ int getNumberOfArgsForOperation(int operation); * @return True if a memory reallocation is required. */ bool needNewBuffer(const qBufGeometry currentGeometry, - const qBufGeometry requiredGeometry, - const qBufGeometry updatedGeometry); + const qBufGeometry requiredGeometry, + const qBufGeometry updatedGeometry); /* * Update the geometry of this buffer without reallocation. @@ -326,13 +272,6 @@ int getPerFrameFlags(int hwclFlags, int layerFlags); bool isUpdatingFB(HWCCompositionType compositionType); -/* - * Get the current composition Type - * - * @return the compositon Type - */ -int getCompositionType(); - /* * Clear region implementation for C2D/MDP versions. * @@ -355,9 +294,8 @@ int qcomuiClearRegion(Region region, EGLDisplay dpy, EGLSurface sur); * @return: external display to be enabled * */ -external_display handleEventHDMI(external_display newEvent, external_display - currEvent); - +external_display_type handleEventHDMI(external_display_type disp, int value, + external_display_type currDispType); /* * Checks if layers need to be dumped based on system property "debug.sf.dump" * for raw dumps and "debug.sf.dump.png" for png dumps. @@ -389,6 +327,10 @@ bool needToDumpLayers(); * */ void dumpLayer(int moduleCompositionType, int listFlags, size_t layerIndex, - hwc_layer_t hwLayers[]); + hwc_layer_t hwLayers[]); + +bool needsAspectRatio (int wRatio, int hRatio); +void applyPixelAspectRatio (int wRatio, int hRatio, int orientation, int fbWidth, + int fbHeight, Rect& visibleRect, GLfloat vertices[][2]); #endif // INCLUDE_LIBQCOM_UI diff --git a/libqcomui/qcomutils/IdleInvalidator.cpp b/libqcomui/qcomutils/IdleInvalidator.cpp new file mode 100755 index 0000000..0b98e11 --- /dev/null +++ b/libqcomui/qcomutils/IdleInvalidator.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2012, 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 "IdleInvalidator.h" +#include + +#define II_DEBUG 1 + +static const char *threadName = "Invalidator"; +InvalidatorHandler IdleInvalidator::mHandler = NULL; +android::sp IdleInvalidator::sInstance(0); + +IdleInvalidator::IdleInvalidator(): Thread(false), mHwcContext(0), + mSleepAgain(false), mSleepTime(0) { + ALOGE_IF(II_DEBUG, "shs %s", __func__); + } + +int IdleInvalidator::init(InvalidatorHandler reg_handler, void* user_data, + unsigned int idleSleepTime) { + ALOGE_IF(II_DEBUG, "shs %s", __func__); + + /* store registered handler */ + mHandler = reg_handler; + mHwcContext = user_data; + mSleepTime = idleSleepTime; //Time in millis + return 0; +} + +bool IdleInvalidator::threadLoop() { + ALOGE_IF(II_DEBUG, "shs %s", __func__); + usleep(mSleepTime * 1000); + if(mSleepAgain) { + //We need to sleep again! + mSleepAgain = false; + return true; + } + + mHandler((void*)mHwcContext); + return false; +} + +int IdleInvalidator::readyToRun() { + ALOGE_IF(II_DEBUG, "shs %s", __func__); + return 0; /*NO_ERROR*/ +} + +void IdleInvalidator::onFirstRef() { + ALOGE_IF(II_DEBUG, "shs %s", __func__); +} + +void IdleInvalidator::markForSleep() { + mSleepAgain = true; + //Triggers the threadLoop to run, if not already running. + run(threadName, android::PRIORITY_AUDIO); +} + +IdleInvalidator *IdleInvalidator::getInstance() { + ALOGE_IF(II_DEBUG, "shs %s", __func__); + if(sInstance.get() == NULL) + sInstance = new IdleInvalidator(); + return sInstance.get(); +} diff --git a/libqcomui/qcomutils/IdleInvalidator.h b/libqcomui/qcomutils/IdleInvalidator.h new file mode 100755 index 0000000..930cd35 --- /dev/null +++ b/libqcomui/qcomutils/IdleInvalidator.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012, 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_IDLEINVALIDATOR +#define INCLUDE_IDLEINVALIDATOR + +#include +#include + +typedef void (*InvalidatorHandler)(void*); + +class IdleInvalidator : public android::Thread { + void *mHwcContext; + bool mSleepAgain; + unsigned int mSleepTime; + static InvalidatorHandler mHandler; + static android::sp sInstance; + + public: + IdleInvalidator(); + /* init timer obj */ + int init(InvalidatorHandler reg_handler, void* user_data, unsigned int + idleSleepTime); + void markForSleep(); + /*Overrides*/ + virtual bool threadLoop(); + virtual int readyToRun(); + virtual void onFirstRef(); + static IdleInvalidator *getInstance(); +}; + +#endif // INCLUDE_IDLEINVALIDATOR diff --git a/libqcomui/qcomutils/comptype.h b/libqcomui/qcomutils/comptype.h new file mode 100644 index 0000000..603e143 --- /dev/null +++ b/libqcomui/qcomutils/comptype.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2012, 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_COMPTYPES +#define INCLUDE_LIBQCOM_COMPTYPES + +#include +#include +#include + +using namespace android; + +// Enum containing the supported composition types +enum { + COMPOSITION_TYPE_GPU = 0, + COMPOSITION_TYPE_MDP = 0x1, + COMPOSITION_TYPE_C2D = 0x2, + COMPOSITION_TYPE_CPU = 0x4, + COMPOSITION_TYPE_DYN = 0x8 +}; + +/* This class caches the composition type + */ +class QCCompositionType : public Singleton +{ + public: + QCCompositionType(); + ~QCCompositionType() { } + int getCompositionType() {return mCompositionType;} + private: + int mCompositionType; + +}; + +ANDROID_SINGLETON_STATIC_INSTANCE(QCCompositionType); +inline QCCompositionType::QCCompositionType() +{ + char property[PROPERTY_VALUE_MAX]; + mCompositionType = 0; + if (property_get("debug.sf.hw", property, NULL) > 0) { + if(atoi(property) == 0) { + mCompositionType = COMPOSITION_TYPE_CPU; + } else { //debug.sf.hw = 1 + property_get("debug.composition.type", property, NULL); + if (property == NULL) { + mCompositionType = COMPOSITION_TYPE_GPU; + } else if ((strncmp(property, "mdp", 3)) == 0) { + mCompositionType = COMPOSITION_TYPE_MDP; + } else if ((strncmp(property, "c2d", 3)) == 0) { + mCompositionType = COMPOSITION_TYPE_C2D; + } else if ((strncmp(property, "dyn", 3)) == 0) { +#ifdef USE_MDP3 + mCompositionType = COMPOSITION_TYPE_DYN | COMPOSITION_TYPE_MDP; +#else + mCompositionType = COMPOSITION_TYPE_DYN | COMPOSITION_TYPE_C2D; +#endif + } else { + mCompositionType = COMPOSITION_TYPE_GPU; + } + } + } else { //debug.sf.hw is not set. Use cpu composition + mCompositionType = COMPOSITION_TYPE_CPU; + } + +} +#endif //INCLUDE_LIBQCOM_COMPTYPES diff --git a/libqcomui/qcomutils/profiler.cpp b/libqcomui/qcomutils/profiler.cpp new file mode 100755 index 0000000..73854bc --- /dev/null +++ b/libqcomui/qcomutils/profiler.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2011-2012, 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 "profiler.h" + +#ifdef DEBUG_CALC_FPS + +#define LOG_TAG "CALCFPS" +#define LOG_NDDEBUG 0 + +ANDROID_SINGLETON_STATIC_INSTANCE(CalcFps) ; + +CalcFps::CalcFps() { + debug_fps_level = 0; + Init(); +} + +CalcFps::~CalcFps() { +} + +void CalcFps::Init() { + char prop[PROPERTY_VALUE_MAX]; + property_get("debug.gr.calcfps", prop, "0"); + debug_fps_level = atoi(prop); + if (debug_fps_level > MAX_DEBUG_FPS_LEVEL) { + ALOGW("out of range value for debug.gr.calcfps, using 0"); + debug_fps_level = 0; + } + + ALOGD("DEBUG_CALC_FPS: %d", debug_fps_level); + populate_debug_fps_metadata(); +} + +void CalcFps::Fps() { + if (debug_fps_level > 0) + calc_fps(ns2us(systemTime())); +} + +void CalcFps::populate_debug_fps_metadata(void) +{ + char prop[PROPERTY_VALUE_MAX]; + + /*defaults calculation of fps to based on number of frames*/ + property_get("debug.gr.calcfps.type", prop, "0"); + debug_fps_metadata.type = (debug_fps_metadata_t::DfmType) atoi(prop); + + /*defaults to 1000ms*/ + property_get("debug.gr.calcfps.timeperiod", prop, "1000"); + debug_fps_metadata.time_period = atoi(prop); + + property_get("debug.gr.calcfps.period", prop, "10"); + debug_fps_metadata.period = atoi(prop); + + if (debug_fps_metadata.period > MAX_FPS_CALC_PERIOD_IN_FRAMES) { + debug_fps_metadata.period = MAX_FPS_CALC_PERIOD_IN_FRAMES; + } + + /* default ignorethresh_us: 500 milli seconds */ + property_get("debug.gr.calcfps.ignorethresh_us", prop, "500000"); + debug_fps_metadata.ignorethresh_us = atoi(prop); + + debug_fps_metadata.framearrival_steps = + (debug_fps_metadata.ignorethresh_us / 16666); + + if (debug_fps_metadata.framearrival_steps > MAX_FRAMEARRIVAL_STEPS) { + debug_fps_metadata.framearrival_steps = MAX_FRAMEARRIVAL_STEPS; + debug_fps_metadata.ignorethresh_us = + debug_fps_metadata.framearrival_steps * 16666; + } + + /* 2ms margin of error for the gettimeofday */ + debug_fps_metadata.margin_us = 2000; + + for (unsigned int i = 0; i < MAX_FRAMEARRIVAL_STEPS; i++) + debug_fps_metadata.accum_framearrivals[i] = 0; + + ALOGD("period: %d", debug_fps_metadata.period); + ALOGD("ignorethresh_us: %lld", debug_fps_metadata.ignorethresh_us); +} + +void CalcFps::print_fps(float fps) +{ + if (debug_fps_metadata_t::DFM_FRAMES == debug_fps_metadata.type) + ALOGD("FPS for last %d frames: %3.2f", debug_fps_metadata.period, fps); + else + ALOGD("FPS for last (%f ms, %d frames): %3.2f", + debug_fps_metadata.time_elapsed, + debug_fps_metadata.curr_frame, fps); + + debug_fps_metadata.curr_frame = 0; + debug_fps_metadata.time_elapsed = 0.0; + + if (debug_fps_level > 1) { + ALOGD("Frame Arrival Distribution:"); + for (unsigned int i = 0; + i < ((debug_fps_metadata.framearrival_steps / 6) + 1); + i++) { + ALOGD("%lld %lld %lld %lld %lld %lld", + debug_fps_metadata.accum_framearrivals[i*6], + debug_fps_metadata.accum_framearrivals[i*6+1], + debug_fps_metadata.accum_framearrivals[i*6+2], + debug_fps_metadata.accum_framearrivals[i*6+3], + debug_fps_metadata.accum_framearrivals[i*6+4], + debug_fps_metadata.accum_framearrivals[i*6+5]); + } + + /* We are done with displaying, now clear the stats */ + for (unsigned int i = 0; + i < debug_fps_metadata.framearrival_steps; + i++) + debug_fps_metadata.accum_framearrivals[i] = 0; + } + return; +} + +void CalcFps::calc_fps(nsecs_t currtime_us) +{ + static nsecs_t oldtime_us = 0; + + nsecs_t diff = currtime_us - oldtime_us; + + oldtime_us = currtime_us; + + if (debug_fps_metadata_t::DFM_FRAMES == debug_fps_metadata.type && + diff > debug_fps_metadata.ignorethresh_us) { + return; + } + + if (debug_fps_metadata.curr_frame < MAX_FPS_CALC_PERIOD_IN_FRAMES) { + debug_fps_metadata.framearrivals[debug_fps_metadata.curr_frame] = diff; + } + + debug_fps_metadata.curr_frame++; + + if (debug_fps_level > 1) { + unsigned int currstep = (diff + debug_fps_metadata.margin_us) / 16666; + + if (currstep < debug_fps_metadata.framearrival_steps) { + debug_fps_metadata.accum_framearrivals[currstep-1]++; + } + } + + if (debug_fps_metadata_t::DFM_FRAMES == debug_fps_metadata.type) { + if (debug_fps_metadata.curr_frame == debug_fps_metadata.period) { + /* time to calculate and display FPS */ + nsecs_t sum = 0; + for (unsigned int i = 0; i < debug_fps_metadata.period; i++) + sum += debug_fps_metadata.framearrivals[i]; + print_fps((debug_fps_metadata.period * float(1000000))/float(sum)); + } + } + else if (debug_fps_metadata_t::DFM_TIME == debug_fps_metadata.type) { + debug_fps_metadata.time_elapsed += ((float)diff/1000.0); + if (debug_fps_metadata.time_elapsed >= debug_fps_metadata.time_period) { + float fps = (1000.0 * debug_fps_metadata.curr_frame)/ + (float)debug_fps_metadata.time_elapsed; + print_fps(fps); + } + } + return; +} +#endif diff --git a/libqcomui/qcomutils/profiler.h b/libqcomui/qcomutils/profiler.h new file mode 100755 index 0000000..394f490 --- /dev/null +++ b/libqcomui/qcomutils/profiler.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2011-2012, 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_PROFILER +#define INCLUDE_PROFILER + +#include +#include +#include +#include +using namespace android; + +#ifndef DEBUG_CALC_FPS +#define CALC_FPS() ((void)0) +#define CALC_INIT() ((void)0) +#else +#define CALC_FPS() CalcFps::getInstance().Fps() +#define CALC_INIT() CalcFps::getInstance().Init() + +class CalcFps : public Singleton { + public: + CalcFps(); + ~CalcFps(); + + void Init(); + void Fps(); + + private: + static const unsigned int MAX_FPS_CALC_PERIOD_IN_FRAMES = 128; + static const unsigned int MAX_FRAMEARRIVAL_STEPS = 50; + static const unsigned int MAX_DEBUG_FPS_LEVEL = 2; + + struct debug_fps_metadata_t { + /*fps calculation based on time or number of frames*/ + enum DfmType { + DFM_FRAMES = 0, + DFM_TIME = 1, + }; + + DfmType type; + + /* indicates how much time do we wait till we calculate FPS */ + unsigned long time_period; + + /*indicates how much time elapsed since we report fps*/ + float time_elapsed; + + /* indicates how many frames do we wait till we calculate FPS */ + unsigned int period; + /* current frame, will go upto period, and then reset */ + unsigned int curr_frame; + /* frame will arrive at a multiple of 16666 us at the display. + This indicates how many steps to consider for our calculations. + For example, if framearrival_steps = 10, then the frame that arrived + after 166660 us or more will be ignored. + */ + unsigned int framearrival_steps; + /* ignorethresh_us = framearrival_steps * 16666 */ + nsecs_t ignorethresh_us; + /* used to calculate the actual frame arrival step, the times might not be + accurate + */ + unsigned int margin_us; + + /* actual data storage */ + nsecs_t framearrivals[MAX_FPS_CALC_PERIOD_IN_FRAMES]; + nsecs_t accum_framearrivals[MAX_FRAMEARRIVAL_STEPS]; + }; + + private: + void populate_debug_fps_metadata(void); + void print_fps(float fps); + void calc_fps(nsecs_t currtime_us); + + private: + debug_fps_metadata_t debug_fps_metadata; + unsigned int debug_fps_level; +}; +#endif + +#endif // INCLUDE_PROFILER diff --git a/libtilerenderer/tilerenderer.cpp b/libtilerenderer/tilerenderer.cpp index 6e8f847..4ed6895 100644 --- a/libtilerenderer/tilerenderer.cpp +++ b/libtilerenderer/tilerenderer.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 The Android Open Source Project - * Copyright (c) 2011 Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,7 +52,7 @@ void TileRenderer::startTileRendering(OpenGLRenderer* renderer, if (!left && !right && !top && !bottom) { //can't do tile rendering - LOGE("can't tile render; drity region, width, height not available"); + ALOGE("can't tile render; drity region, width, height not available"); return; } diff --git a/libtilerenderer/tilerenderer.h b/libtilerenderer/tilerenderer.h index bec225d..7f8d608 100644 --- a/libtilerenderer/tilerenderer.h +++ b/libtilerenderer/tilerenderer.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 The Android Open Source Project - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,14 +25,14 @@ namespace uirenderer { class OpenGLRenderer; class TileRenderer: public Singleton { -public: + public: TileRenderer(); ~TileRenderer(); void startTileRendering(OpenGLRenderer* renderer, int left, int top, int right, int bottom); void endTileRendering(OpenGLRenderer*); -private: + private: bool mIsTiled; };