msm8909: Populate display code for msm8x09
Copied from manifest tag LW.BR.1.0-00110-8x09w.0 for
LW.BR.1.0
Bug: 25691995
Change-Id: I42c50111d92ecbdc9198ce4f2a98c26300dfa715
diff --git a/Android.mk b/Android.mk
index 0b984bc..2c9d83a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -14,6 +14,10 @@
else
ifneq ($(filter msm8994 msm8992,$(TARGET_BOARD_PLATFORM)),)
include $(call all-named-subdir-makefiles,msm8994)
+else
+ifneq ($(filter msm8909,$(TARGET_BOARD_PLATFORM)),)
+ include $(call all-named-subdir-makefiles,msm8909)
+endif
endif
endif
endif
diff --git a/msm8909/Android.mk b/msm8909/Android.mk
new file mode 100644
index 0000000..d8b168d
--- /dev/null
+++ b/msm8909/Android.mk
@@ -0,0 +1,10 @@
+display-hals := libgralloc libgenlock libcopybit liblight
+display-hals += libhwcomposer liboverlay libqdutils libhdmi libqservice
+display-hals += libmemtrack
+ifeq ($(call is-vendor-board-platform,QCOM),true)
+ include $(call all-named-subdir-makefiles,$(display-hals))
+else
+ifneq ($(filter msm% apq%,$(TARGET_BOARD_PLATFORM)),)
+ include $(call all-named-subdir-makefiles,$(display-hals))
+endif
+endif
diff --git a/msm8909/common.mk b/msm8909/common.mk
new file mode 100644
index 0000000..252de80
--- /dev/null
+++ b/msm8909/common.mk
@@ -0,0 +1,61 @@
+#Common headers
+common_includes := $(LOCAL_PATH)/../libgralloc
+common_includes += $(LOCAL_PATH)/../liboverlay
+common_includes += $(LOCAL_PATH)/../libcopybit
+common_includes += $(LOCAL_PATH)/../libqdutils
+common_includes += $(LOCAL_PATH)/../libhwcomposer
+common_includes += $(LOCAL_PATH)/../libhdmi
+common_includes += $(LOCAL_PATH)/../libqservice
+
+ifeq ($(TARGET_USES_POST_PROCESSING),true)
+ common_flags += -DUSES_POST_PROCESSING
+ common_includes += $(TARGET_OUT_HEADERS)/pp/inc
+endif
+
+common_header_export_path := qcom/display
+
+#Common libraries external to display HAL
+common_libs := liblog libutils libcutils libhardware
+
+#Common C flags
+common_flags := -DDEBUG_CALC_FPS -Wno-missing-field-initializers
+common_flags += -Wconversion -Wall -Werror
+
+ifeq ($(ARCH_ARM_HAVE_NEON),true)
+ common_flags += -D__ARM_HAVE_NEON
+endif
+
+ifeq ($(call is-board-platform-in-list, $(MSM_VIDC_TARGET_LIST)), true)
+ common_flags += -DVENUS_COLOR_FORMAT
+endif
+
+ifeq ($(call is-board-platform-in-list, msm8974 msm8226 msm8610 apq8084 \
+ mpq8092 msm_bronze msm8916 msm8994), true)
+ common_flags += -DMDSS_TARGET
+endif
+ifeq ($(call is-board-platform-in-list, msm8909), true)
+ common_flags += -DVENUS_COLOR_FORMAT
+ common_flags += -DMDSS_TARGET
+endif
+
+common_deps :=
+kernel_includes :=
+
+# Executed only on QCOM BSPs
+ifeq ($(TARGET_USES_QCOM_BSP),true)
+# Enable QCOM Display features
+ common_flags += -DQTI_BSP
+ common_includes += vendor/qcom/opensource/display-frameworks/include
+endif
+ifneq ($(call is-platform-sdk-version-at-least,18),true)
+ common_flags += -DANDROID_JELLYBEAN_MR1=1
+endif
+ifeq ($(call is-vendor-board-platform,QCOM),true)
+# This check is to pick the kernel headers from the right location.
+# If the macro above is defined, we make the assumption that we have the kernel
+# available in the build tree.
+# If the macro is not present, the headers are picked from hardware/qcom/msmXXXX
+# failing which, they are picked from bionic.
+ common_deps += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+ kernel_includes += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+endif
diff --git a/msm8909/libcopybit/Android.mk b/msm8909/libcopybit/Android.mk
new file mode 100644
index 0000000..f6f7ed5
--- /dev/null
+++ b/msm8909/libcopybit/Android.mk
@@ -0,0 +1,48 @@
+# 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 $(LOCAL_PATH)/../common.mk
+include $(CLEAR_VARS)
+
+LOCAL_COPY_HEADERS_TO := $(common_header_export_path)
+LOCAL_COPY_HEADERS := copybit.h copybit_priv.h c2d2.h
+#Copy the headers regardless of whether copybit is built
+include $(BUILD_COPY_HEADERS)
+
+LOCAL_MODULE := copybit.$(TARGET_BOARD_PLATFORM)
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
+LOCAL_SHARED_LIBRARIES := $(common_libs) libdl libmemalloc
+LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdcopybit\"
+LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
+
+ifeq ($(TARGET_USES_C2D_COMPOSITION),true)
+ LOCAL_CFLAGS += -DCOPYBIT_Z180=1 -DC2D_SUPPORT_DISPLAY=1
+ LOCAL_SRC_FILES := copybit_c2d.cpp software_converter.cpp
+ 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)
+ LOCAL_CFLAGS += -DCOPYBIT_MSM7K=1
+ LOCAL_SRC_FILES := software_converter.cpp copybit.cpp
+ include $(BUILD_SHARED_LIBRARY)
+ endif
+ ifeq ($(call is-board-platform-in-list, msm8610 msm8909),true)
+ LOCAL_SRC_FILES := software_converter.cpp copybit.cpp
+ include $(BUILD_SHARED_LIBRARY)
+ endif
+ endif
+endif
diff --git a/msm8909/libcopybit/MODULE_LICENSE_APACHE2 b/msm8909/libcopybit/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/msm8909/libcopybit/MODULE_LICENSE_APACHE2
diff --git a/msm8909/libcopybit/NOTICE b/msm8909/libcopybit/NOTICE
new file mode 100644
index 0000000..9c1e63a
--- /dev/null
+++ b/msm8909/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/msm8909/libcopybit/c2d2.h b/msm8909/libcopybit/c2d2.h
new file mode 100644
index 0000000..886f38a
--- /dev/null
+++ b/msm8909/libcopybit/c2d2.h
@@ -0,0 +1,683 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. 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 The Linux Foundation. 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;
+
+/* Configuration bits, used in the config_mask field of C2D_OBJECT struct */
+typedef enum {
+ C2D_OVERRIDE_GLOBAL_TARGET_ROTATE_CONFIG = (1 << 27), /* Overrides TARGET Config */
+ C2D_OVERRIDE_TARGET_ROTATE_0 = (0 << 28), /* no rotation */
+ C2D_OVERRIDE_TARGET_ROTATE_90 = (1 << 28), /* 90 degree rotation */
+ C2D_OVERRIDE_TARGET_ROTATE_180 = (2 << 28), /* 180 degree rotation */
+ C2D_OVERRIDE_TARGET_ROTATE_270 = (3 << 28), /* 270 degree rotation */
+} C2D_SOURCE_TARGET_CONFIG;
+
+#define C2D_OVERRIDE_SOURCE_CONFIG_TARGET_ROTATION_SHIFT_MASK 28
+#define C2D_OVERRIDE_TARGET_CONFIG_TARGET_ROTATION_SHIFT_MASK 2
+
+
+/* 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;
+
+/* Configuration bits, driver capabilities used by 2Dapplications */
+typedef enum {
+ C2D_DRIVER_SUPPORTS_GLOBAL_ALPHA_OP = (1 << 0),
+ C2D_DRIVER_SUPPORTS_TILE_OP = (1 << 1),
+ C2D_DRIVER_SUPPORTS_COLOR_KEY_OP = (1 << 2),
+ C2D_DRIVER_SUPPORTS_NO_PIXEL_ALPHA_OP = (1 << 3),
+ C2D_DRIVER_SUPPORTS_TARGET_ROTATE_OP = (1 << 4),
+ C2D_DRIVER_SUPPORTS_ANTI_ALIASING_OP = (1 << 5), /* antialiasing */
+ C2D_DRIVER_SUPPORTS_BILINEAR_FILTER_OP = (1 << 6),
+ C2D_DRIVER_SUPPORTS_LENS_CORRECTION_OP = (1 << 7),
+ C2D_DRIVER_SUPPORTS_OVERRIDE_TARGET_ROTATE_OP = (1 << 8),
+ C2D_DRIVER_SUPPORTS_SHADER_BLOB_OP = (1 << 9),
+ C2D_DRIVER_SUPPORTS_MASK_SURFACE_OP = (1 << 10), /* mask surface */
+ C2D_DRIVER_SUPPORTS_MIRROR_H_OP = (1 << 11), /* horizontal flip */
+ C2D_DRIVER_SUPPORTS_MIRROR_V_OP = (1 << 12), /* vertical flip */
+ C2D_DRIVER_SUPPORTS_SCISSOR_RECT_OP = (1 << 13),
+ C2D_DRIVER_SUPPORTS_SOURCE_RECT_OP = (1 << 14),
+ C2D_DRIVER_SUPPORTS_TARGET_RECT_OP = (1 << 15),
+ C2D_DRIVER_SUPPORTS_ROTATE_OP = (1 << 16), /* all rotations */
+ C2D_DRIVER_SUPPORTS_FLUSH_WITH_FENCE_FD_OP = (1 << 17), /* all rotations */
+ C2D_DRIVER_SUPPORTS_ALL_CAPABILITIES_OP = ((0xFFFFFFFF) >> (31 - 17)) /* mask for all capabilities supported */
+} C2D_DRIVER_CAPABILITIES;
+
+/* 2D driver workaround bits used by the 2D applications */
+typedef enum {
+ C2D_DRIVER_WORKAROUND_NONE = 0, /* NO workaround */
+ C2D_DRIVER_WORKAROUND_SWAP_UV_FOR_YUV_TARGET = (1 << 0), /* Swap UV when this flag set */
+} C2D_DRIVER_WORKAROUND;
+
+/* Structure to query Driver information */
+typedef struct {
+ uint32 capabilities_mask;
+ uint32 workaround_mask;
+ uint32 reserved1;
+ uint32 reserved2;
+ uint32 reserved3;
+} C2D_DRIVER_INFO;
+
+/* Structure to query Driver information */
+typedef struct {
+ uint32 max_surface_template_needed;
+ uint32 reserved1;
+ uint32 reserved2;
+ uint32 reserved3;
+} C2D_DRIVER_SETUP_INFO;
+
+/*****************************************************************************/
+/**************************** 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);
+
+/* allows user to query driver capabilities.
+ * driver_info is the information about driver */
+C2D_API C2D_STATUS c2dGetDriverCapabilities( C2D_DRIVER_INFO * driver_info);
+
+/* create a fence fd for the timestamp */
+C2D_API C2D_STATUS c2dCreateFenceFD( uint32 target_id, c2d_ts_handle timestamp, int32 *fd);
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __c2d2_h_ */
diff --git a/msm8909/libcopybit/copybit.cpp b/msm8909/libcopybit/copybit.cpp
new file mode 100644
index 0000000..b2d0d40
--- /dev/null
+++ b/msm8909/libcopybit/copybit.cpp
@@ -0,0 +1,787 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (c) 2010 - 2014, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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 <cutils/log.h>
+
+#include <linux/msm_mdp.h>
+#include <linux/fb.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <copybit.h>
+
+#include "gralloc_priv.h"
+#include "software_converter.h"
+#include <qdMetaData.h>
+
+#define DEBUG_MDP_ERRORS 1
+
+/******************************************************************************/
+
+#define MAX_SCALE_FACTOR (4)
+#define MAX_DIMENSION (4096)
+
+/******************************************************************************/
+struct blitReq{
+ struct mdp_buf_sync sync;
+ uint32_t count;
+ struct mdp_blit_req req[10];
+};
+
+/** State information for each device instance */
+struct copybit_context_t {
+ struct copybit_device_t device;
+ int mFD;
+ uint8_t mAlpha;
+ int mFlags;
+ bool mBlitToFB;
+ int acqFence[MDP_MAX_FENCE_FD];
+ int relFence;
+ struct mdp_buf_sync sync;
+ struct blitReq list;
+ uint8_t dynamic_fps;
+};
+
+/**
+ * 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 (a<b) ? a : b;
+}
+
+/** max of int a, b */
+static inline int max(int a, int b) {
+ return (a>b) ? 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);
+}
+
+static bool validateCopybitRect(struct copybit_rect_t *rect) {
+ return ((rect->b > rect->t) && (rect->r > rect->l)) ;
+}
+
+/** 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_BGRX_8888: return MDP_BGRX_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_I: return MDP_YCRYCB_H2V1;
+ case HAL_PIXEL_FORMAT_YCbCr_422_I: return MDP_YCBYCR_H2V1;
+ case HAL_PIXEL_FORMAT_YCrCb_422_SP: return MDP_Y_CRCB_H2V1;
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP: return MDP_Y_CRCB_H2V2;
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP: return MDP_Y_CBCR_H2V1;
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP: return MDP_Y_CBCR_H2V2;
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: return MDP_Y_CBCR_H2V2_ADRENO;
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: return MDP_Y_CBCR_H2V2_VENUS;
+ case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: return MDP_Y_CBCR_H2V2;
+ }
+ 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 = (uint32_t)hnd->offset;
+ img->memory_id = hnd->fd;
+}
+/** setup rectangles */
+static bool 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) {
+ struct copybit_rect_t clip;
+ intersect(&clip, scissor, dst);
+
+ if (!validateCopybitRect(&clip))
+ return false;
+
+ 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);
+ }
+ }
+ return true;
+}
+
+/** setup mdp request */
+static void set_infos(struct copybit_context_t *dev,
+ struct mdp_blit_req *req, int flags)
+{
+ req->alpha = dev->mAlpha;
+ req->fps = dev->dynamic_fps;
+ req->transp_mask = MDP_TRANSP_NOP;
+ req->flags = dev->mFlags | flags;
+ // check if we are blitting to f/b
+ if (COPYBIT_ENABLE == dev->mBlitToFB) {
+ req->flags |= MDP_MEMORY_ID_TYPE_FB;
+ }
+#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;
+ if (dev->relFence != -1) {
+ close(dev->relFence);
+ dev->relFence = -1;
+ }
+ err = ioctl(dev->mFD, MSMFB_ASYNC_BLIT,
+ (struct mdp_async_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_async_blit_req_list const* l =
+ (struct mdp_async_blit_req_list const*)list;
+ for (unsigned int i=0 ; i<l->count ; 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=%08x, fps=%d"
+ ,
+ 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,
+ l->req[i].fps
+ );
+ }
+#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 = (uint8_t)value;
+ break;
+ case COPYBIT_DYNAMIC_FPS:
+ ctx->dynamic_fps = (uint8_t)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_BLEND_MODE:
+ if(value == COPYBIT_BLENDING_PREMULT) {
+ ctx->mFlags |= MDP_BLEND_FG_PREMULT;
+ } else {
+ ctx->mFlags &= ~MDP_BLEND_FG_PREMULT;
+ }
+ break;
+ case COPYBIT_TRANSFORM:
+ ctx->mFlags &= ~0x7;
+ ctx->mFlags |= value & 0x7;
+ break;
+ case COPYBIT_BLIT_TO_FRAMEBUFFER:
+ if (COPYBIT_ENABLE == value) {
+ ctx->mBlitToFB = value;
+ } else if (COPYBIT_DISABLE == value) {
+ ctx->mBlitToFB = value;
+ } else {
+ ALOGE ("%s:Invalid input for COPYBIT_BLIT_TO_FRAMEBUFFER : %d",
+ __FUNCTION__, value);
+ }
+ break;
+ case COPYBIT_FG_LAYER:
+ if(value == COPYBIT_ENABLE) {
+ ctx->mFlags |= MDP_IS_FG;
+ } else if (value == COPYBIT_DISABLE) {
+ ctx->mFlags &= ~MDP_IS_FG;
+ }
+ 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;
+}
+
+static int set_sync_copybit(struct copybit_device_t *dev,
+ int acquireFenceFd)
+{
+ struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
+ if (acquireFenceFd != -1) {
+ if (ctx->list.sync.acq_fen_fd_cnt < (MDP_MAX_FENCE_FD - 1)) {
+ ctx->acqFence[ctx->list.sync.acq_fen_fd_cnt++] = acquireFenceFd;
+ } else {
+ int ret = -EINVAL;
+ struct blitReq *list = &ctx->list;
+
+ // Since fence is full kick off what is already in the list
+ ret = msm_copybit(ctx, list);
+ if (ret < 0) {
+ ALOGE("%s: Blit call failed", __FUNCTION__);
+ return -EINVAL;
+ }
+ list->count = 0;
+ list->sync.acq_fen_fd_cnt = 0;
+ ctx->acqFence[list->sync.acq_fen_fd_cnt++] = acquireFenceFd;
+ }
+ }
+ return 0;
+}
+
+/** 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;
+ struct blitReq *list;
+ int status = 0;
+ private_handle_t *yv12_handle = NULL;
+
+ if (ctx) {
+ list = &ctx->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:
+ ALOGE ("%s : Unsupported Pixel format %d", __FUNCTION__,
+ src->format);
+ return -EINVAL;
+ }
+ }
+
+ if (src_rect->l < 0 || (uint32_t)src_rect->r > src->w ||
+ src_rect->t < 0 || (uint32_t)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_IOMMU_HEAP | GRALLOC_USAGE_PRIVATE_UNCACHED;
+ if (0 == alloc_buffer(&yv12_handle,src->w,src->h,
+ src->format, usage)){
+ if(0 == convertYV12toYCrCb420SP(src,yv12_handle)){
+ (const_cast<copybit_image_t *>(src))->format =
+ HAL_PIXEL_FORMAT_YCrCb_420_SP;
+ (const_cast<copybit_image_t *>(src))->handle =
+ yv12_handle;
+ (const_cast<copybit_image_t *>(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 =
+ (uint32_t)(sizeof(list->req)/sizeof(list->req[0]));
+ const struct copybit_rect_t bounds = { 0, 0, (int)dst->w, (int)dst->h };
+ struct copybit_rect_t clip;
+ 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_CACHED))) {
+ flags |= MDP_BLIT_NON_CACHED;
+ }
+
+ // Set Color Space for MDP to configure CSC matrix
+ req->color_space = ITU_R_601;
+ MetaData_t *metadata = NULL;
+
+ if (src_hnd != NULL)
+ metadata = (MetaData_t *)src_hnd->base_metadata;
+
+ if (metadata && (metadata->operation & UPDATE_COLOR_SPACE)) {
+ req->color_space = metadata->colorSpace;
+ }
+
+ set_infos(ctx, req, flags);
+ set_image(&req->dst, dst);
+ set_image(&req->src, src);
+ if (set_rects(ctx, req, dst_rect, src_rect, &clip) == false)
+ continue;
+
+ 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->sync.acq_fen_fd_cnt = 0;
+ list->count = 0;
+ }
+ }
+ if(yv12_handle) {
+ //Before freeing the buffer we need buffer passed through blit call
+ if (list->count != 0) {
+ status = msm_copybit(ctx, list);
+ list->sync.acq_fen_fd_cnt = 0;
+ list->count = 0;
+ }
+ free_buffer(yv12_handle);
+ }
+ } else {
+ ALOGE ("%s : Invalid COPYBIT context", __FUNCTION__);
+ status = -EINVAL;
+ }
+ 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, (int)dst->w, (int)dst->h };
+ struct copybit_rect_t sr = { 0, 0, (int)src->w, (int)src->h };
+ return stretch_copybit(dev, dst, src, &dr, &sr, region);
+}
+
+static int finish_copybit(struct copybit_device_t *dev)
+{
+ // NOP for MDP copybit
+ if(!dev)
+ return -EINVAL;
+
+ return 0;
+}
+static int clear_copybit(struct copybit_device_t *dev,
+ struct copybit_image_t const *buf,
+ struct copybit_rect_t *rect)
+{
+ struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
+ uint32_t color = 0; // black color
+
+ if (!ctx) {
+ ALOGE ("%s: Invalid copybit context", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ struct blitReq list1;
+ memset((char *)&list1 , 0 ,sizeof (struct blitReq) );
+ list1.count = 1;
+ int my_tmp_get_fence = -1;
+
+ list1.sync.acq_fen_fd = ctx->acqFence;
+ list1.sync.rel_fen_fd = &my_tmp_get_fence;
+ list1.sync.acq_fen_fd_cnt = ctx->list.sync.acq_fen_fd_cnt;
+ mdp_blit_req* req = &list1.req[0];
+
+ if(!req) {
+ ALOGE ("%s : Invalid request", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ set_image(&req->dst, buf);
+ set_image(&req->src, buf);
+
+ if (rect->l < 0 || (uint32_t)(rect->r - rect->l) > req->dst.width ||
+ rect->t < 0 || (uint32_t)(rect->b - rect->t) > req->dst.height) {
+ ALOGE ("%s : Invalid rect : src_rect l %d t %d r %d b %d",\
+ __FUNCTION__, rect->l, rect->t, rect->r, rect->b);
+ return -EINVAL;
+ }
+
+ req->dst_rect.x = rect->l;
+ req->dst_rect.y = rect->t;
+ req->dst_rect.w = rect->r - rect->l;
+ req->dst_rect.h = rect->b - rect->t;
+
+ req->src_rect = req->dst_rect;
+
+ req->const_color.b = (uint32_t)((color >> 16) & 0xff);
+ req->const_color.g = (uint32_t)((color >> 8) & 0xff);
+ req->const_color.r = (uint32_t)((color >> 0) & 0xff);
+ req->const_color.alpha = MDP_ALPHA_NOP;
+
+ req->transp_mask = MDP_TRANSP_NOP;
+ req->flags = MDP_SOLID_FILL | MDP_MEMORY_ID_TYPE_FB | MDP_BLEND_FG_PREMULT;
+ int status = msm_copybit(ctx, &list1);
+
+ ctx->list.sync.acq_fen_fd_cnt = 0;
+ if (my_tmp_get_fence != -1)
+ close(my_tmp_get_fence);
+
+ return status;
+}
+
+/** Fill the rect on dst with RGBA color **/
+static int fill_color(struct copybit_device_t *dev,
+ struct copybit_image_t const *dst,
+ struct copybit_rect_t const *rect,
+ uint32_t color)
+{
+ struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
+ if (!ctx) {
+ ALOGE("%s: Invalid copybit context", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ if (dst->w > MAX_DIMENSION || dst->h > MAX_DIMENSION) {
+ ALOGE("%s: Invalid DST w=%d h=%d", __FUNCTION__, dst->w, dst->h);
+ return -EINVAL;
+ }
+
+ if (rect->l < 0 || (uint32_t)(rect->r - rect->l) > dst->w ||
+ rect->t < 0 || (uint32_t)(rect->b - rect->t) > dst->h) {
+ ALOGE("%s: Invalid destination rect: l=%d t=%d r=%d b=%d",
+ __FUNCTION__, rect->l, rect->t, rect->r, rect->b);
+ return -EINVAL;
+ }
+
+ int status = 0;
+ struct blitReq* list = &ctx->list;
+ mdp_blit_req* req = &list->req[list->count++];
+ set_infos(ctx, req, MDP_SOLID_FILL);
+ set_image(&req->src, dst);
+ set_image(&req->dst, dst);
+
+ req->dst_rect.x = rect->l;
+ req->dst_rect.y = rect->t;
+ req->dst_rect.w = rect->r - rect->l;
+ req->dst_rect.h = rect->b - rect->t;
+ req->src_rect = req->dst_rect;
+
+ req->const_color.r = (uint32_t)((color >> 0) & 0xff);
+ req->const_color.g = (uint32_t)((color >> 8) & 0xff);
+ req->const_color.b = (uint32_t)((color >> 16) & 0xff);
+ req->const_color.alpha = (uint32_t)((color >> 24) & 0xff);
+
+ if (list->count == sizeof(list->req)/sizeof(list->req[0])) {
+ status = msm_copybit(ctx, list);
+ list->sync.acq_fen_fd_cnt = 0;
+ list->count = 0;
+ }
+ return status;
+}
+
+/*****************************************************************************/
+
+/** 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;
+}
+
+static int flush_get_fence(struct copybit_device_t *dev, int* fd)
+{
+ struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
+ struct blitReq *list = &ctx->list;
+ int ret = -EINVAL;
+
+ if (list->count) {
+ ret = msm_copybit(ctx, list);
+ if (ret < 0)
+ ALOGE("%s: Blit call failed", __FUNCTION__);
+ list->count = 0;
+ }
+ *fd = ctx->relFence;
+ list->sync.acq_fen_fd_cnt = 0;
+ ctx->relFence = -1;
+ return ret;
+}
+
+/** 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;
+
+ if (strcmp(name, COPYBIT_HARDWARE_COPYBIT0)) {
+ return COPYBIT_FAILURE;
+ }
+ copybit_context_t *ctx;
+ ctx = (copybit_context_t *)malloc(sizeof(copybit_context_t));
+
+ if (ctx == NULL ) {
+ return COPYBIT_FAILURE;
+ }
+
+ memset(ctx, 0, sizeof(*ctx));
+
+ ctx->device.common.tag = HARDWARE_DEVICE_TAG;
+ ctx->device.common.version = 1;
+ ctx->device.common.module = const_cast<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.set_sync = set_sync_copybit;
+ ctx->device.stretch = stretch_copybit;
+ ctx->device.finish = finish_copybit;
+ ctx->device.fill_color = fill_color;
+ ctx->device.flush_get_fence = flush_get_fence;
+ ctx->device.clear = clear_copybit;
+ ctx->mAlpha = MDP_ALPHA_NOP;
+ //dynamic_fps is zero means default
+ //panel refresh rate for driver.
+ ctx->dynamic_fps = 0;
+ ctx->mFlags = 0;
+ ctx->sync.flags = 0;
+ ctx->relFence = -1;
+ for (int i=0; i < MDP_MAX_FENCE_FD; i++) {
+ ctx->acqFence[i] = -1;
+ }
+ ctx->sync.acq_fen_fd = ctx->acqFence;
+ ctx->sync.rel_fen_fd = &ctx->relFence;
+ ctx->list.count = 0;
+ ctx->list.sync.acq_fen_fd_cnt = 0;
+ ctx->list.sync.rel_fen_fd = ctx->sync.rel_fen_fd;
+ ctx->list.sync.acq_fen_fd = ctx->sync.acq_fen_fd;
+ 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 {
+ status = 0;
+ *device = &ctx->device.common;
+ }
+ return status;
+}
diff --git a/msm8909/libcopybit/copybit.h b/msm8909/libcopybit/copybit.h
new file mode 100644
index 0000000..b4af021
--- /dev/null
+++ b/msm8909/libcopybit/copybit.h
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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 <hardware/hardware.h>
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <gralloc_priv.h>
+
+__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_YCbCr_422_SP = 0x10,
+ COPYBIT_FORMAT_YCrCb_420_SP = 0x11,
+};
+
+/* name for copybit_set_parameter */
+enum {
+ /* Default blit destination is offline buffer */
+ /* clients to set this to '1', if blitting to framebuffer */
+ /* and reset to '0', after calling blit/stretch */
+ COPYBIT_BLIT_TO_FRAMEBUFFER = 0,
+ /* 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,
+ /* Blend mode */
+ COPYBIT_BLEND_MODE = 6,
+ /* FB width */
+ COPYBIT_FRAMEBUFFER_WIDTH = 7,
+ /* FB height */
+ COPYBIT_FRAMEBUFFER_HEIGHT = 8,
+ COPYBIT_FG_LAYER = 9,
+ COPYBIT_DYNAMIC_FPS = 10,
+};
+
+/* 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
+};
+
+/*
+ * copybit blending values. same as HWC blending values
+ */
+enum {
+ /* no blending */
+ COPYBIT_BLENDING_NONE = 0x0100,
+
+ /* ONE / ONE_MINUS_SRC_ALPHA */
+ COPYBIT_BLENDING_PREMULT = 0x0105,
+
+ /* SRC_ALPHA / ONE_MINUS_SRC_ALPHA */
+ COPYBIT_BLENDING_COVERAGE = 0x0405
+};
+
+/* 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);
+
+ /**
+ * Give acquire fence to copybit to be used in upcoming stretch
+ * call
+ *
+ * @param dev from open
+ * @param acquireFenceFd is the acquire fence
+ *
+ * @return 0 if successful
+ */
+ int (*set_sync)(struct copybit_device_t *dev,
+ int acquireFenceFd);
+
+ /**
+ * 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);
+
+ /**
+ * Fill the rect on dst with RGBA color
+ *
+ * @param dev from open
+ * @param dst is destination image
+ * @param rect is destination rectangle
+ * @param color is RGBA color to fill
+ *
+ * @return 0 if successful
+ */
+ int (*fill_color)(struct copybit_device_t *dev,
+ struct copybit_image_t const *dst,
+ struct copybit_rect_t const *rect,
+ uint32_t color);
+
+ /**
+ * Execute the completion of the copybit draw operation.
+ *
+ * @param dev from open
+ *
+ * @return 0 if successful
+ */
+ int (*finish)(struct copybit_device_t *dev);
+
+ /**
+ * Trigger the copybit draw operation(async).
+ *
+ * @param dev from open
+ *
+ * @param fd - gets the fencefd
+ *
+ * @return 0 if successful
+ */
+ int (*flush_get_fence)(struct copybit_device_t *dev, int* fd);
+
+ /* Clears the buffer
+ */
+ int (*clear)(struct copybit_device_t *dev, struct copybit_image_t const *buf,
+ struct copybit_rect_t *rect);
+};
+
+
+/** 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/msm8909/libcopybit/copybit_c2d.cpp b/msm8909/libcopybit/copybit_c2d.cpp
new file mode 100644
index 0000000..158bdca
--- /dev/null
+++ b/msm8909/libcopybit/copybit_c2d.cpp
@@ -0,0 +1,1773 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (c) 2010-2015, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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 <cutils/log.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <linux/msm_kgsl.h>
+
+#include <EGL/eglplatform.h>
+#include <cutils/native_handle.h>
+
+#include <copybit.h>
+#include <alloc_controller.h>
+#include <memalloc.h>
+
+#include "c2d2.h"
+#include "software_converter.h"
+
+#include <dlfcn.h>
+
+using gralloc::IMemAlloc;
+using gralloc::IonController;
+using gralloc::alloc_data;
+
+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, size_t len,
+ size_t offset, uint32 flags, void ** gpuaddr);
+
+C2D_STATUS (*LINK_c2dUnMapAddr) ( void * gpuaddr);
+
+C2D_STATUS (*LINK_c2dGetDriverCapabilities) ( C2D_DRIVER_INFO * driver_info);
+
+/* create a fence fd for the timestamp */
+C2D_STATUS (*LINK_c2dCreateFenceFD) ( uint32 target_id, c2d_ts_handle timestamp,
+ int32 *fd);
+
+C2D_STATUS (*LINK_c2dFillSurface) ( uint32 surface_id, uint32 fill_color,
+ C2D_RECT * fill_rect);
+
+/******************************************************************************/
+
+#if defined(COPYBIT_Z180)
+#define MAX_SCALE_FACTOR (4096)
+#define MAX_DIMENSION (4096)
+#else
+#error "Unsupported HW version"
+#endif
+
+// The following defines can be changed as required i.e. as we encounter
+// complex use cases.
+#define MAX_RGB_SURFACES 32 // Max. RGB layers currently supported per draw
+#define MAX_YUV_2_PLANE_SURFACES 4// Max. 2-plane YUV layers currently supported per draw
+#define MAX_YUV_3_PLANE_SURFACES 1// Max. 3-plane YUV layers currently supported per draw
+// +1 for the destination surface. We cannot have multiple destination surfaces.
+#define MAX_SURFACES (MAX_RGB_SURFACES + MAX_YUV_2_PLANE_SURFACES + MAX_YUV_3_PLANE_SURFACES + 1)
+#define NUM_SURFACE_TYPES 3 // RGB_SURFACE + YUV_SURFACE_2_PLANES + YUV_SURFACE_3_PLANES
+#define MAX_BLIT_OBJECT_COUNT 50 // Max. blit objects that can be passed per draw
+
+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,
+ FLAGS_TEMP_SRC_DST = 1<<2
+};
+
+static gralloc::IAllocController* sAlloc = 0;
+/******************************************************************************/
+
+/** State information for each device instance */
+struct copybit_context_t {
+ struct copybit_device_t device;
+ // Templates for the various source surfaces. These templates are created
+ // to avoid the expensive create/destroy C2D Surfaces
+ C2D_OBJECT_STR blit_rgb_object[MAX_RGB_SURFACES];
+ C2D_OBJECT_STR blit_yuv_2_plane_object[MAX_YUV_2_PLANE_SURFACES];
+ C2D_OBJECT_STR blit_yuv_3_plane_object[MAX_YUV_3_PLANE_SURFACES];
+ C2D_OBJECT_STR blit_list[MAX_BLIT_OBJECT_COUNT]; // Z-ordered list of blit objects
+ C2D_DRIVER_INFO c2d_driver_info;
+ void *libc2d2;
+ alloc_data temp_src_buffer;
+ alloc_data temp_dst_buffer;
+ unsigned int dst[NUM_SURFACE_TYPES]; // dst surfaces
+ uintptr_t mapped_gpu_addr[MAX_SURFACES]; // GPU addresses mapped inside copybit
+ int blit_rgb_count; // Total RGB surfaces being blit
+ int blit_yuv_2_plane_count; // Total 2 plane YUV surfaces being
+ int blit_yuv_3_plane_count; // Total 3 plane YUV surfaces being blit
+ int blit_count; // Total blit objects.
+ unsigned int trg_transform; /* target transform */
+ int fb_width;
+ int fb_height;
+ int src_global_alpha;
+ int config_mask;
+ int dst_surface_type;
+ bool is_premultiplied_alpha;
+ void* time_stamp;
+ bool dst_surface_mapped; // Set when dst surface is mapped to GPU addr
+ void* dst_surface_base; // Stores the dst surface addr
+
+ // used for signaling the wait thread
+ bool wait_timestamp;
+ pthread_t wait_thread_id;
+ bool stop_thread;
+ pthread_mutex_t wait_cleanup_lock;
+ pthread_cond_t wait_cleanup_cond;
+
+};
+
+struct bufferInfo {
+ int width;
+ int height;
+ int format;
+};
+
+struct yuvPlaneInfo {
+ int yStride; //luma stride
+ int plane1_stride;
+ int plane2_stride;
+ size_t plane1_offset;
+ size_t 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
+ }
+};
+
+
+/* thread function which waits on the timeStamp and cleans up the surfaces */
+static void* c2d_wait_loop(void* ptr) {
+ copybit_context_t* ctx = (copybit_context_t*)(ptr);
+ char thread_name[64] = "copybitWaitThr";
+ prctl(PR_SET_NAME, (unsigned long) &thread_name, 0, 0, 0);
+ setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
+
+ while(ctx->stop_thread == false) {
+ pthread_mutex_lock(&ctx->wait_cleanup_lock);
+ while(ctx->wait_timestamp == false && !ctx->stop_thread) {
+ pthread_cond_wait(&(ctx->wait_cleanup_cond),
+ &(ctx->wait_cleanup_lock));
+ }
+ if(ctx->wait_timestamp) {
+ if(LINK_c2dWaitTimestamp(ctx->time_stamp)) {
+ ALOGE("%s: LINK_c2dWaitTimeStamp ERROR!!", __FUNCTION__);
+ }
+ ctx->wait_timestamp = false;
+ // Unmap any mapped addresses.
+ for (int i = 0; i < MAX_SURFACES; i++) {
+ if (ctx->mapped_gpu_addr[i]) {
+ LINK_c2dUnMapAddr( (void*)ctx->mapped_gpu_addr[i]);
+ ctx->mapped_gpu_addr[i] = 0;
+ }
+ }
+ // Reset the counts after the draw.
+ ctx->blit_rgb_count = 0;
+ ctx->blit_yuv_2_plane_count = 0;
+ ctx->blit_yuv_3_plane_count = 0;
+ ctx->blit_count = 0;
+ ctx->dst_surface_mapped = false;
+ ctx->dst_surface_base = 0;
+ }
+ pthread_mutex_unlock(&ctx->wait_cleanup_lock);
+ if(ctx->stop_thread)
+ break;
+ }
+ pthread_exit(NULL);
+ return NULL;
+}
+
+
+/* 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_RGB_888: return C2D_COLOR_FORMAT_888_RGB |
+ C2D_FORMAT_SWAP_RB;
+ 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_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_888_RGB:
+ c2dBpp = 24;
+ 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 size_t c2d_get_gpuaddr(copybit_context_t* ctx,
+ struct private_handle_t *handle, int &mapped_idx)
+{
+ uint32 memtype;
+ size_t *gpuaddr = 0;
+ C2D_STATUS rc;
+ int freeindex = 0;
+ bool mapaddr = false;
+
+ 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;
+ }
+
+ // Check for a freeindex in the mapped_gpu_addr list
+ for (freeindex = 0; freeindex < MAX_SURFACES; freeindex++) {
+ if (ctx->mapped_gpu_addr[freeindex] == 0) {
+ // free index is available
+ // map GPU addr and use this as mapped_idx
+ mapaddr = true;
+ break;
+ }
+ }
+
+ if(mapaddr) {
+ rc = LINK_c2dMapAddr(handle->fd, (void*)handle->base, handle->size,
+ handle->offset, memtype, (void**)&gpuaddr);
+
+ if (rc == C2D_STATUS_OK) {
+ // We have mapped the GPU address inside copybit. We need to unmap
+ // this address after the blit. Store this address
+ ctx->mapped_gpu_addr[freeindex] = (size_t)gpuaddr;
+ mapped_idx = freeindex;
+ }
+ }
+ return (size_t)gpuaddr;
+}
+
+static void unmap_gpuaddr(copybit_context_t* ctx, int mapped_idx)
+{
+ if (!ctx || (mapped_idx == -1))
+ return;
+
+ if (ctx->mapped_gpu_addr[mapped_idx]) {
+ LINK_c2dUnMapAddr( (void*)ctx->mapped_gpu_addr[mapped_idx]);
+ ctx->mapped_gpu_addr[mapped_idx] = 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_888:
+ case HAL_PIXEL_FORMAT_RGB_565:
+ case HAL_PIXEL_FORMAT_BGRA_8888: {
+ 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(copybit_context_t* ctx, uint32 surfaceId,
+ const struct copybit_image_t *rhs,
+ const eC2DFlags flags, int &mapped_idx)
+{
+ struct private_handle_t* handle = (struct private_handle_t*)rhs->handle;
+ C2D_SURFACE_TYPE surfaceType;
+ int status = COPYBIT_SUCCESS;
+ uint64_t gpuaddr = 0;
+ int c2d_format;
+ mapped_idx = -1;
+
+ if (flags & FLAGS_YUV_DESTINATION) {
+ c2d_format = get_c2d_format_for_yuv_destination(rhs->format);
+ } else {
+ c2d_format = get_format(rhs->format);
+ }
+
+ if(c2d_format == -EINVAL) {
+ ALOGE("%s: invalid format", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ if(handle == NULL) {
+ ALOGE("%s: invalid handle", __func__);
+ return -EINVAL;
+ }
+
+ if (handle->gpuaddr == 0) {
+ gpuaddr = c2d_get_gpuaddr(ctx, handle, mapped_idx);
+ if(!gpuaddr) {
+ ALOGE("%s: c2d_get_gpuaddr failed", __FUNCTION__);
+ return COPYBIT_FAILURE;
+ }
+ } else {
+ gpuaddr = handle->gpuaddr;
+ }
+
+ /* 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*) gpuaddr;
+ surfaceDef.buffer = (void*) (handle->base);
+
+ surfaceDef.format = c2d_format |
+ ((flags & FLAGS_PREMULTIPLIED_ALPHA) ? C2D_FORMAT_PREMULTIPLIED : 0);
+ surfaceDef.width = rhs->w;
+ surfaceDef.height = rhs->h;
+ int aligned_width = ALIGN((int)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__);
+ unmap_gpuaddr(ctx, mapped_idx);
+ 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 = c2d_format;
+
+ bufferInfo info;
+ info.width = rhs->w;
+ info.height = rhs->h;
+ info.format = rhs->format;
+
+ yuvPlaneInfo yuvInfo = {0};
+ status = calculate_yuv_offset_and_stride(info, yuvInfo);
+ if(status != COPYBIT_SUCCESS) {
+ ALOGE("%s: calculate_yuv_offset_and_stride error", __FUNCTION__);
+ unmap_gpuaddr(ctx, mapped_idx);
+ }
+
+ surfaceDef.width = rhs->w;
+ surfaceDef.height = rhs->h;
+ surfaceDef.plane0 = (void*) (handle->base);
+ surfaceDef.phys0 = (void*) (gpuaddr);
+ surfaceDef.stride0 = yuvInfo.yStride;
+
+ surfaceDef.plane1 = (void*) (handle->base + yuvInfo.plane1_offset);
+ surfaceDef.phys1 = (void*) (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*) (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__);
+ unmap_gpuaddr(ctx, mapped_idx);
+ status = COPYBIT_FAILURE;
+ }
+ } else {
+ ALOGE("%s: invalid format 0x%x", __FUNCTION__, rhs->format);
+ unmap_gpuaddr(ctx, mapped_idx);
+ status = COPYBIT_FAILURE;
+ }
+
+ return status;
+}
+
+/** copy the bits */
+static int msm_copybit(struct copybit_context_t *ctx, unsigned int target)
+{
+ if (ctx->blit_count == 0) {
+ return COPYBIT_SUCCESS;
+ }
+
+ for (int i = 0; i < ctx->blit_count; i++)
+ {
+ ctx->blit_list[i].next = &(ctx->blit_list[i+1]);
+ }
+ ctx->blit_list[ctx->blit_count-1].next = NULL;
+ uint32_t target_transform = ctx->trg_transform;
+ if (ctx->c2d_driver_info.capabilities_mask &
+ C2D_DRIVER_SUPPORTS_OVERRIDE_TARGET_ROTATE_OP) {
+ // For A3xx - set 0x0 as the transform is set in the config_mask
+ target_transform = 0x0;
+ }
+ if(LINK_c2dDraw(target, target_transform, 0x0, 0, 0, ctx->blit_list,
+ ctx->blit_count)) {
+ ALOGE("%s: LINK_c2dDraw ERROR", __FUNCTION__);
+ return COPYBIT_FAILURE;
+ }
+ return COPYBIT_SUCCESS;
+}
+
+
+
+static int flush_get_fence_copybit (struct copybit_device_t *dev, int* fd)
+{
+ struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
+ int status = COPYBIT_FAILURE;
+ if (!ctx)
+ return COPYBIT_FAILURE;
+ pthread_mutex_lock(&ctx->wait_cleanup_lock);
+ status = msm_copybit(ctx, ctx->dst[ctx->dst_surface_type]);
+
+ if(LINK_c2dFlush(ctx->dst[ctx->dst_surface_type], &ctx->time_stamp)) {
+ ALOGE("%s: LINK_c2dFlush ERROR", __FUNCTION__);
+ // unlock the mutex and return failure
+ pthread_mutex_unlock(&ctx->wait_cleanup_lock);
+ return COPYBIT_FAILURE;
+ }
+ if(LINK_c2dCreateFenceFD(ctx->dst[ctx->dst_surface_type], ctx->time_stamp,
+ fd)) {
+ ALOGE("%s: LINK_c2dCreateFenceFD ERROR", __FUNCTION__);
+ status = COPYBIT_FAILURE;
+ }
+ if(status == COPYBIT_SUCCESS) {
+ //signal the wait_thread
+ ctx->wait_timestamp = true;
+ pthread_cond_signal(&ctx->wait_cleanup_cond);
+ }
+ pthread_mutex_unlock(&ctx->wait_cleanup_lock);
+ return status;
+}
+
+static int finish_copybit(struct copybit_device_t *dev)
+{
+ struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
+ if (!ctx)
+ return COPYBIT_FAILURE;
+
+ int status = msm_copybit(ctx, ctx->dst[ctx->dst_surface_type]);
+
+ if(LINK_c2dFinish(ctx->dst[ctx->dst_surface_type])) {
+ ALOGE("%s: LINK_c2dFinish ERROR", __FUNCTION__);
+ return COPYBIT_FAILURE;
+ }
+
+ // Unmap any mapped addresses.
+ for (int i = 0; i < MAX_SURFACES; i++) {
+ if (ctx->mapped_gpu_addr[i]) {
+ LINK_c2dUnMapAddr( (void*)ctx->mapped_gpu_addr[i]);
+ ctx->mapped_gpu_addr[i] = 0;
+ }
+ }
+
+ // Reset the counts after the draw.
+ ctx->blit_rgb_count = 0;
+ ctx->blit_yuv_2_plane_count = 0;
+ ctx->blit_yuv_3_plane_count = 0;
+ ctx->blit_count = 0;
+ ctx->dst_surface_mapped = false;
+ ctx->dst_surface_base = 0;
+
+ return status;
+}
+
+static int clear_copybit(struct copybit_device_t *dev,
+ struct copybit_image_t const *buf,
+ struct copybit_rect_t *rect)
+{
+ int ret = COPYBIT_SUCCESS;
+ int flags = FLAGS_PREMULTIPLIED_ALPHA;
+ int mapped_dst_idx = -1;
+ struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
+ C2D_RECT c2drect = {rect->l, rect->t, rect->r - rect->l, rect->b - rect->t};
+ pthread_mutex_lock(&ctx->wait_cleanup_lock);
+ if(!ctx->dst_surface_mapped) {
+ ret = set_image(ctx, ctx->dst[RGB_SURFACE], buf,
+ (eC2DFlags)flags, mapped_dst_idx);
+ if(ret) {
+ ALOGE("%s: set_image error", __FUNCTION__);
+ unmap_gpuaddr(ctx, mapped_dst_idx);
+ pthread_mutex_unlock(&ctx->wait_cleanup_lock);
+ return COPYBIT_FAILURE;
+ }
+ //clear_copybit is the first call made by HWC for each composition
+ //with the dest surface, hence set dst_surface_mapped.
+ ctx->dst_surface_mapped = true;
+ ctx->dst_surface_base = buf->base;
+ ret = LINK_c2dFillSurface(ctx->dst[RGB_SURFACE], 0x0, &c2drect);
+ }
+ pthread_mutex_unlock(&ctx->wait_cleanup_lock);
+ return ret;
+}
+
+
+/** 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;
+}
+
+/*****************************************************************************/
+
+/** 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 = COPYBIT_SUCCESS;
+ if (!ctx) {
+ ALOGE("%s: null context", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ pthread_mutex_lock(&ctx->wait_cleanup_lock);
+ switch(name) {
+ case COPYBIT_PLANE_ALPHA:
+ {
+ if (value < 0) value = 0;
+ if (value >= 256) value = 255;
+
+ ctx->src_global_alpha = value;
+ if (value < 255)
+ ctx->config_mask |= C2D_GLOBAL_ALPHA_BIT;
+ else
+ ctx->config_mask &= ~C2D_GLOBAL_ALPHA_BIT;
+ }
+ break;
+ case COPYBIT_BLEND_MODE:
+ {
+ if (value == COPYBIT_BLENDING_NONE) {
+ ctx->config_mask |= C2D_ALPHA_BLEND_NONE;
+ ctx->is_premultiplied_alpha = true;
+ } else if (value == COPYBIT_BLENDING_PREMULT) {
+ ctx->is_premultiplied_alpha = true;
+ } else {
+ ctx->config_mask &= ~C2D_ALPHA_BLEND_NONE;
+ }
+ }
+ break;
+ case COPYBIT_TRANSFORM:
+ {
+ unsigned int transform = 0;
+ uint32 config_mask = 0;
+ config_mask |= C2D_OVERRIDE_GLOBAL_TARGET_ROTATE_CONFIG;
+ if((value & 0x7) == COPYBIT_TRANSFORM_ROT_180) {
+ transform = C2D_TARGET_ROTATE_180;
+ config_mask |= C2D_OVERRIDE_TARGET_ROTATE_180;
+ } else if((value & 0x7) == COPYBIT_TRANSFORM_ROT_270) {
+ transform = C2D_TARGET_ROTATE_90;
+ config_mask |= C2D_OVERRIDE_TARGET_ROTATE_90;
+ } else if(value == COPYBIT_TRANSFORM_ROT_90) {
+ transform = C2D_TARGET_ROTATE_270;
+ config_mask |= C2D_OVERRIDE_TARGET_ROTATE_270;
+ } else {
+ config_mask |= C2D_OVERRIDE_TARGET_ROTATE_0;
+ if(value & COPYBIT_TRANSFORM_FLIP_H) {
+ config_mask |= C2D_MIRROR_H_BIT;
+ } else if(value & COPYBIT_TRANSFORM_FLIP_V) {
+ config_mask |= C2D_MIRROR_V_BIT;
+ }
+ }
+
+ if (ctx->c2d_driver_info.capabilities_mask &
+ C2D_DRIVER_SUPPORTS_OVERRIDE_TARGET_ROTATE_OP) {
+ ctx->config_mask |= config_mask;
+ } else {
+ // The transform for this surface does not match the current
+ // target transform. Draw all previous surfaces. This will be
+ // changed once we have a new mechanism to send different
+ // target rotations to c2d.
+ finish_copybit(dev);
+ }
+ ctx->trg_transform = transform;
+ }
+ break;
+ case COPYBIT_FRAMEBUFFER_WIDTH:
+ ctx->fb_width = value;
+ break;
+ case COPYBIT_FRAMEBUFFER_HEIGHT:
+ ctx->fb_height = value;
+ break;
+ case COPYBIT_ROTATION_DEG:
+ case COPYBIT_DITHER:
+ case COPYBIT_BLUR:
+ case COPYBIT_BLIT_TO_FRAMEBUFFER:
+ // Do nothing
+ break;
+ default:
+ ALOGE("%s: default case param=0x%x", __FUNCTION__, name);
+ status = -EINVAL;
+ break;
+ }
+ pthread_mutex_unlock(&ctx->wait_cleanup_lock);
+ 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) {
+ 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 int get_size(const bufferInfo& info)
+{
+ int 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(aligned_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(aligned_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();
+ }
+
+ if (sAlloc == 0) {
+ ALOGE("%s: sAlloc is still NULL", __FUNCTION__);
+ return COPYBIT_FAILURE;
+ }
+
+ int err = sAlloc->allocate(data, allocFlags);
+ 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) {
+ IMemAlloc* 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;
+ }
+}
+
+static bool need_to_execute_draw(eC2DFlags flags)
+{
+ if (flags & FLAGS_TEMP_SRC_DST) {
+ return true;
+ }
+ if (flags & FLAGS_YUV_DESTINATION) {
+ return true;
+ }
+ return false;
+}
+
+/** 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;
+ int flags = 0;
+ int src_surface_type;
+ int mapped_src_idx = -1, mapped_dst_idx = -1;
+ C2D_OBJECT_STR src_surface;
+
+ 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;
+ }
+
+ if (is_valid_destination_format(dst->format) == COPYBIT_FAILURE) {
+ ALOGE("%s: Invalid destination format format = 0x%x", __FUNCTION__,
+ dst->format);
+ return COPYBIT_FAILURE;
+ }
+
+ int dst_surface_type;
+ if (is_supported_rgb_format(dst->format) == COPYBIT_SUCCESS) {
+ dst_surface_type = RGB_SURFACE;
+ flags |= FLAGS_PREMULTIPLIED_ALPHA;
+ } else if (is_supported_yuv_format(dst->format) == COPYBIT_SUCCESS) {
+ int num_planes = get_num_planes(dst->format);
+ flags |= FLAGS_YUV_DESTINATION;
+ if (num_planes == 2) {
+ dst_surface_type = YUV_SURFACE_2_PLANES;
+ } else if (num_planes == 3) {
+ dst_surface_type = 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;
+ }
+
+ if (ctx->blit_rgb_count == MAX_RGB_SURFACES ||
+ ctx->blit_yuv_2_plane_count == MAX_YUV_2_PLANE_SURFACES ||
+ ctx->blit_yuv_3_plane_count == MAX_YUV_2_PLANE_SURFACES ||
+ ctx->blit_count == MAX_BLIT_OBJECT_COUNT ||
+ ctx->dst_surface_type != dst_surface_type) {
+ // we have reached the max. limits of our internal structures or
+ // changed the target.
+ // Draw the remaining surfaces. We need to do the finish here since
+ // we need to free up the surface templates.
+ finish_copybit(dev);
+ }
+
+ ctx->dst_surface_type = dst_surface_type;
+
+ // Update the destination
+ 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 need_temp_dst = 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 (need_temp_dst) {
+ if (get_size(dst_info) != (int) 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 = (uintptr_t)(ctx->temp_dst_buffer.base);
+ dst_hnd->offset = ctx->temp_dst_buffer.offset;
+ dst_hnd->gpuaddr = 0;
+ dst_image.handle = dst_hnd;
+ }
+ if(!ctx->dst_surface_mapped) {
+ //map the destination surface to GPU address
+ status = set_image(ctx, ctx->dst[ctx->dst_surface_type], &dst_image,
+ (eC2DFlags)flags, mapped_dst_idx);
+ if(status) {
+ ALOGE("%s: dst: set_image error", __FUNCTION__);
+ delete_handle(dst_hnd);
+ unmap_gpuaddr(ctx, mapped_dst_idx);
+ return COPYBIT_FAILURE;
+ }
+ ctx->dst_surface_mapped = true;
+ ctx->dst_surface_base = dst->base;
+ } else if(ctx->dst_surface_mapped && ctx->dst_surface_base != dst->base) {
+ // Destination surface for the operation should be same for multiple
+ // requests, this check is catch if there is any case when the
+ // destination changes
+ ALOGE("%s: a different destination surface!!", __FUNCTION__);
+ }
+
+ // Update the source
+ flags = 0;
+ if(is_supported_rgb_format(src->format) == COPYBIT_SUCCESS) {
+ src_surface_type = RGB_SURFACE;
+ src_surface = ctx->blit_rgb_object[ctx->blit_rgb_count];
+ } else if (is_supported_yuv_format(src->format) == COPYBIT_SUCCESS) {
+ int num_planes = get_num_planes(src->format);
+ if (num_planes == 2) {
+ src_surface_type = YUV_SURFACE_2_PLANES;
+ src_surface = ctx->blit_yuv_2_plane_object[ctx->blit_yuv_2_plane_count];
+ } else if (num_planes == 3) {
+ src_surface_type = YUV_SURFACE_3_PLANES;
+ src_surface = ctx->blit_yuv_3_plane_object[ctx->blit_yuv_2_plane_count];
+ } else {
+ ALOGE("%s: src number of YUV planes is invalid src format = 0x%x",
+ __FUNCTION__, src->format);
+ delete_handle(dst_hnd);
+ unmap_gpuaddr(ctx, mapped_dst_idx);
+ return -EINVAL;
+ }
+ } else {
+ ALOGE("%s: Invalid source surface format 0x%x", __FUNCTION__,
+ src->format);
+ delete_handle(dst_hnd);
+ unmap_gpuaddr(ctx, mapped_dst_idx);
+ 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 need_temp_src = 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);
+ unmap_gpuaddr(ctx, mapped_dst_idx);
+ return COPYBIT_FAILURE;
+ }
+ if (need_temp_src) {
+ if (get_size(src_info) != (int) 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);
+ unmap_gpuaddr(ctx, mapped_dst_idx);
+ 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 = (uintptr_t)(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.
+ status = copy_image((private_handle_t *)src->handle, &src_image,
+ CONVERT_TO_C2D_FORMAT);
+ if (status == COPYBIT_FAILURE) {
+ ALOGE("%s:copy_image failed in temp source",__FUNCTION__);
+ delete_handle(dst_hnd);
+ delete_handle(src_hnd);
+ unmap_gpuaddr(ctx, mapped_dst_idx);
+ return status;
+ }
+
+ // Clean the cache
+ IMemAlloc* memalloc = sAlloc->getAllocator(src_hnd->flags);
+ if (memalloc->clean_buffer((void *)(src_hnd->base), src_hnd->size,
+ src_hnd->offset, src_hnd->fd,
+ gralloc::CACHE_CLEAN)) {
+ ALOGE("%s: clean_buffer failed", __FUNCTION__);
+ delete_handle(dst_hnd);
+ delete_handle(src_hnd);
+ unmap_gpuaddr(ctx, mapped_dst_idx);
+ return COPYBIT_FAILURE;
+ }
+ }
+
+ flags |= (ctx->is_premultiplied_alpha) ? FLAGS_PREMULTIPLIED_ALPHA : 0;
+ flags |= (ctx->dst_surface_type != RGB_SURFACE) ? FLAGS_YUV_DESTINATION : 0;
+ status = set_image(ctx, src_surface.surface_id, &src_image,
+ (eC2DFlags)flags, mapped_src_idx);
+ if(status) {
+ ALOGE("%s: set_image (src) error", __FUNCTION__);
+ delete_handle(dst_hnd);
+ delete_handle(src_hnd);
+ unmap_gpuaddr(ctx, mapped_dst_idx);
+ unmap_gpuaddr(ctx, mapped_src_idx);
+ return COPYBIT_FAILURE;
+ }
+
+ src_surface.config_mask = C2D_NO_ANTIALIASING_BIT | ctx->config_mask;
+ src_surface.global_alpha = ctx->src_global_alpha;
+ if (enableBlend) {
+ if(src_surface.config_mask & C2D_GLOBAL_ALPHA_BIT) {
+ src_surface.config_mask &= ~C2D_ALPHA_BLEND_NONE;
+ if(!(src_surface.global_alpha)) {
+ // src alpha is zero
+ delete_handle(dst_hnd);
+ delete_handle(src_hnd);
+ unmap_gpuaddr(ctx, mapped_dst_idx);
+ unmap_gpuaddr(ctx, mapped_src_idx);
+ return COPYBIT_FAILURE;
+ }
+ }
+ } else {
+ src_surface.config_mask |= C2D_ALPHA_BLEND_NONE;
+ }
+
+ if (src_surface_type == RGB_SURFACE) {
+ ctx->blit_rgb_object[ctx->blit_rgb_count] = src_surface;
+ ctx->blit_rgb_count++;
+ } else if (src_surface_type == YUV_SURFACE_2_PLANES) {
+ ctx->blit_yuv_2_plane_object[ctx->blit_yuv_2_plane_count] = src_surface;
+ ctx->blit_yuv_2_plane_count++;
+ } else {
+ ctx->blit_yuv_3_plane_object[ctx->blit_yuv_3_plane_count] = src_surface;
+ ctx->blit_yuv_3_plane_count++;
+ }
+
+ struct copybit_rect_t clip;
+ while ((status == 0) && region->next(region, &clip)) {
+ set_rects(ctx, &(src_surface), dst_rect, src_rect, &clip);
+ if (ctx->blit_count == MAX_BLIT_OBJECT_COUNT) {
+ ALOGW("Reached end of blit count");
+ finish_copybit(dev);
+ }
+ ctx->blit_list[ctx->blit_count] = src_surface;
+ ctx->blit_count++;
+ }
+
+ // Check if we need to perform an early draw-finish.
+ flags |= (need_temp_dst || need_temp_src) ? FLAGS_TEMP_SRC_DST : 0;
+ if (need_to_execute_draw((eC2DFlags)flags))
+ {
+ finish_copybit(dev);
+ }
+
+ if (need_temp_dst) {
+ // copy the temp. destination without the alignment to the actual
+ // destination.
+ status = copy_image(dst_hnd, dst, CONVERT_TO_ANDROID_FORMAT);
+ if (status == COPYBIT_FAILURE) {
+ ALOGE("%s:copy_image failed in temp Dest",__FUNCTION__);
+ delete_handle(dst_hnd);
+ delete_handle(src_hnd);
+ unmap_gpuaddr(ctx, mapped_dst_idx);
+ unmap_gpuaddr(ctx, mapped_src_idx);
+ return status;
+ }
+ // Clean the cache.
+ IMemAlloc* memalloc = sAlloc->getAllocator(dst_hnd->flags);
+ memalloc->clean_buffer((void *)(dst_hnd->base), dst_hnd->size,
+ dst_hnd->offset, dst_hnd->fd,
+ gralloc::CACHE_CLEAN);
+ }
+ delete_handle(dst_hnd);
+ delete_handle(src_hnd);
+
+ ctx->is_premultiplied_alpha = false;
+ ctx->fb_width = 0;
+ ctx->fb_height = 0;
+ ctx->config_mask = 0;
+ return status;
+}
+
+static int set_sync_copybit(struct copybit_device_t *dev,
+ int /*acquireFenceFd*/)
+{
+ if(!dev)
+ return -EINVAL;
+
+ return 0;
+}
+
+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 = COPYBIT_SUCCESS;
+ bool needsBlending = (ctx->src_global_alpha != 0);
+ pthread_mutex_lock(&ctx->wait_cleanup_lock);
+ status = stretch_copybit_internal(dev, dst, src, dst_rect, src_rect,
+ region, needsBlending);
+ pthread_mutex_unlock(&ctx->wait_cleanup_lock);
+ 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)
+{
+ int status = COPYBIT_SUCCESS;
+ struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
+ struct copybit_rect_t dr = { 0, 0, (int)dst->w, (int)dst->h };
+ struct copybit_rect_t sr = { 0, 0, (int)src->w, (int)src->h };
+ pthread_mutex_lock(&ctx->wait_cleanup_lock);
+ status = stretch_copybit_internal(dev, dst, src, &dr, &sr, region, false);
+ pthread_mutex_unlock(&ctx->wait_cleanup_lock);
+ return status;
+}
+
+/** Fill the rect on dst with RGBA color **/
+static int fill_color(struct copybit_device_t *dev,
+ struct copybit_image_t const *dst,
+ struct copybit_rect_t const *rect,
+ uint32_t /*color*/)
+{
+ // TODO: Implement once c2d driver supports color fill
+ if(!dev || !dst || !rect)
+ return -EINVAL;
+
+ return -EINVAL;
+}
+
+/*****************************************************************************/
+
+static void clean_up(copybit_context_t* ctx)
+{
+ void* ret;
+ if (!ctx)
+ return;
+
+ // stop the wait_cleanup_thread
+ pthread_mutex_lock(&ctx->wait_cleanup_lock);
+ ctx->stop_thread = true;
+ // Signal waiting thread
+ pthread_cond_signal(&ctx->wait_cleanup_cond);
+ pthread_mutex_unlock(&ctx->wait_cleanup_lock);
+ // waits for the cleanup thread to exit
+ pthread_join(ctx->wait_thread_id, &ret);
+ pthread_mutex_destroy(&ctx->wait_cleanup_lock);
+ pthread_cond_destroy (&ctx->wait_cleanup_cond);
+
+ for (int i = 0; i < NUM_SURFACE_TYPES; i++) {
+ if (ctx->dst[i])
+ LINK_c2dDestroySurface(ctx->dst[i]);
+ }
+
+ for (int i = 0; i < MAX_RGB_SURFACES; i++) {
+ if (ctx->blit_rgb_object[i].surface_id)
+ LINK_c2dDestroySurface(ctx->blit_rgb_object[i].surface_id);
+ }
+
+ for (int i = 0; i < MAX_YUV_2_PLANE_SURFACES; i++) {
+ if (ctx->blit_yuv_2_plane_object[i].surface_id)
+ LINK_c2dDestroySurface(ctx->blit_yuv_2_plane_object[i].surface_id);
+ }
+
+ for (int i = 0; i < MAX_YUV_3_PLANE_SURFACES; i++) {
+ if (ctx->blit_yuv_3_plane_object[i].surface_id)
+ LINK_c2dDestroySurface(ctx->blit_yuv_3_plane_object[i].surface_id);
+ }
+
+ if (ctx->libc2d2) {
+ ::dlclose(ctx->libc2d2);
+ ALOGV("dlclose(libc2d2)");
+ }
+
+ free(ctx);
+}
+
+/** 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) {
+ free_temp_buffer(ctx->temp_src_buffer);
+ free_temp_buffer(ctx->temp_dst_buffer);
+ }
+ clean_up(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;
+ if (strcmp(name, COPYBIT_HARDWARE_COPYBIT0)) {
+ return COPYBIT_FAILURE;
+ }
+
+ C2D_RGB_SURFACE_DEF surfDefinition = {0};
+ C2D_YUV_SURFACE_DEF yuvSurfaceDef = {0} ;
+ struct copybit_context_t *ctx;
+
+ 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));
+ ctx->libc2d2 = ::dlopen("libC2D2.so", RTLD_NOW);
+ if (!ctx->libc2d2) {
+ ALOGE("FATAL ERROR: could not dlopen libc2d2.so: %s", dlerror());
+ clean_up(ctx);
+ status = COPYBIT_FAILURE;
+ *device = NULL;
+ return status;
+ }
+ *(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");
+ *(void **)&LINK_c2dGetDriverCapabilities = ::dlsym(ctx->libc2d2,
+ "c2dGetDriverCapabilities");
+ *(void **)&LINK_c2dCreateFenceFD = ::dlsym(ctx->libc2d2,
+ "c2dCreateFenceFD");
+ *(void **)&LINK_c2dFillSurface = ::dlsym(ctx->libc2d2,
+ "c2dFillSurface");
+
+ if (!LINK_c2dCreateSurface || !LINK_c2dUpdateSurface || !LINK_c2dReadSurface
+ || !LINK_c2dDraw || !LINK_c2dFlush || !LINK_c2dWaitTimestamp ||
+ !LINK_c2dFinish || !LINK_c2dDestroySurface ||
+ !LINK_c2dGetDriverCapabilities || !LINK_c2dCreateFenceFD ||
+ !LINK_c2dFillSurface) {
+ ALOGE("%s: dlsym ERROR", __FUNCTION__);
+ clean_up(ctx);
+ status = COPYBIT_FAILURE;
+ *device = NULL;
+ return status;
+ }
+
+ 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.set_sync = set_sync_copybit;
+ ctx->device.stretch = stretch_copybit;
+ ctx->device.finish = finish_copybit;
+ ctx->device.flush_get_fence = flush_get_fence_copybit;
+ ctx->device.clear = clear_copybit;
+ ctx->device.fill_color = fill_color;
+
+ /* 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_surface[RGB_SURFACE] failed", __FUNCTION__);
+ ctx->dst[RGB_SURFACE] = 0;
+ clean_up(ctx);
+ status = COPYBIT_FAILURE;
+ *device = NULL;
+ return status;
+ }
+
+ unsigned int surface_id = 0;
+ for (int i = 0; i < MAX_RGB_SURFACES; i++)
+ {
+ if (LINK_c2dCreateSurface(&surface_id, C2D_TARGET | C2D_SOURCE,
+ (C2D_SURFACE_TYPE)(C2D_SURFACE_RGB_HOST |
+ C2D_SURFACE_WITH_PHYS |
+ C2D_SURFACE_WITH_PHYS_DUMMY ),
+ &surfDefinition)) {
+ ALOGE("%s: create RGB source surface %d failed", __FUNCTION__, i);
+ ctx->blit_rgb_object[i].surface_id = 0;
+ status = COPYBIT_FAILURE;
+ break;
+ } else {
+ ctx->blit_rgb_object[i].surface_id = surface_id;
+ ALOGW("%s i = %d surface_id=%d", __FUNCTION__, i,
+ ctx->blit_rgb_object[i].surface_id);
+ }
+ }
+
+ if (status == COPYBIT_FAILURE) {
+ clean_up(ctx);
+ status = COPYBIT_FAILURE;
+ *device = NULL;
+ return status;
+ }
+
+ // Create 2 plane YUV surfaces
+ 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->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] = 0;
+ clean_up(ctx);
+ status = COPYBIT_FAILURE;
+ *device = NULL;
+ return status;
+ }
+
+ for (int i=0; i < MAX_YUV_2_PLANE_SURFACES; i++)
+ {
+ if (LINK_c2dCreateSurface(&surface_id, C2D_TARGET | C2D_SOURCE,
+ (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST |
+ C2D_SURFACE_WITH_PHYS |
+ C2D_SURFACE_WITH_PHYS_DUMMY ),
+ &yuvSurfaceDef)) {
+ ALOGE("%s: create YUV source %d failed", __FUNCTION__, i);
+ ctx->blit_yuv_2_plane_object[i].surface_id = 0;
+ status = COPYBIT_FAILURE;
+ break;
+ } else {
+ ctx->blit_yuv_2_plane_object[i].surface_id = surface_id;
+ ALOGW("%s: 2 Plane YUV i=%d surface_id=%d", __FUNCTION__, i,
+ ctx->blit_yuv_2_plane_object[i].surface_id);
+ }
+ }
+
+ if (status == COPYBIT_FAILURE) {
+ clean_up(ctx);
+ status = COPYBIT_FAILURE;
+ *device = NULL;
+ return status;
+ }
+
+ // Create YUV 3 plane surfaces
+ yuvSurfaceDef.format = C2D_COLOR_FORMAT_420_YV12;
+ yuvSurfaceDef.plane2 = (void*)0xaaaaaaaa;
+ yuvSurfaceDef.phys2 = (void*) 0xaaaaaaaa;
+ yuvSurfaceDef.stride2 = 4;
+
+ 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] = 0;
+ clean_up(ctx);
+ status = COPYBIT_FAILURE;
+ *device = NULL;
+ return status;
+ }
+
+ for (int i=0; i < MAX_YUV_3_PLANE_SURFACES; i++)
+ {
+ if (LINK_c2dCreateSurface(&(surface_id),
+ C2D_TARGET | C2D_SOURCE,
+ (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST |
+ C2D_SURFACE_WITH_PHYS |
+ C2D_SURFACE_WITH_PHYS_DUMMY),
+ &yuvSurfaceDef)) {
+ ALOGE("%s: create 3 plane YUV surface %d failed", __FUNCTION__, i);
+ ctx->blit_yuv_3_plane_object[i].surface_id = 0;
+ status = COPYBIT_FAILURE;
+ break;
+ } else {
+ ctx->blit_yuv_3_plane_object[i].surface_id = surface_id;
+ ALOGW("%s: 3 Plane YUV i=%d surface_id=%d", __FUNCTION__, i,
+ ctx->blit_yuv_3_plane_object[i].surface_id);
+ }
+ }
+
+ if (status == COPYBIT_FAILURE) {
+ clean_up(ctx);
+ status = COPYBIT_FAILURE;
+ *device = NULL;
+ return status;
+ }
+
+ if (LINK_c2dGetDriverCapabilities(&(ctx->c2d_driver_info))) {
+ ALOGE("%s: LINK_c2dGetDriverCapabilities failed", __FUNCTION__);
+ clean_up(ctx);
+ status = COPYBIT_FAILURE;
+ *device = NULL;
+ return status;
+ }
+ // Initialize context variables.
+ ctx->trg_transform = C2D_TARGET_ROTATE_0;
+
+ 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->blit_rgb_count = 0;
+ ctx->blit_yuv_2_plane_count = 0;
+ ctx->blit_yuv_3_plane_count = 0;
+ ctx->blit_count = 0;
+
+ ctx->wait_timestamp = false;
+ ctx->stop_thread = false;
+ pthread_mutex_init(&(ctx->wait_cleanup_lock), NULL);
+ pthread_cond_init(&(ctx->wait_cleanup_cond), NULL);
+ /* Start the wait thread */
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ pthread_create(&ctx->wait_thread_id, &attr, &c2d_wait_loop,
+ (void *)ctx);
+ pthread_attr_destroy(&attr);
+
+ *device = &ctx->device.common;
+ return status;
+}
diff --git a/msm8909/libcopybit/copybit_priv.h b/msm8909/libcopybit/copybit_priv.h
new file mode 100644
index 0000000..68dfac4
--- /dev/null
+++ b/msm8909/libcopybit/copybit_priv.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011, The Linux Foundation. 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 The Linux Foundation 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 <copybit.h>
+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<copybit_iterator const*>(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/msm8909/libcopybit/software_converter.cpp b/msm8909/libcopybit/software_converter.cpp
new file mode 100644
index 0000000..e5c03b5
--- /dev/null
+++ b/msm8909/libcopybit/software_converter.cpp
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2011-2014, The Linux Foundation. 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 The Linux Foundation 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 <cutils/log.h>
+#include <stdlib.h>
+#include <errno.h>
+#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, (unsigned int)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);
+
+#if defined(__ARM_HAVE_NEON) && !defined(__aarch64__)
+ /* 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;
+ size_t src_plane1_offset;
+ size_t src_plane2_offset;
+ size_t dst_plane1_offset;
+ size_t dst_plane2_offset;
+};
+
+/* Internal function to do the actual copy of source to destination */
+static int copy_source_to_destination(const uintptr_t src_base,
+ const uintptr_t dst_base,
+ copyInfo& info)
+{
+ if (!src_base || !dst_base) {
+ ALOGE("%s: invalid memory src_base = 0x%p dst_base=0x%p",
+ __FUNCTION__, (void*)src_base, (void*)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((uintptr_t) hnd->base, (uintptr_t) 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((uintptr_t) hnd->base, (uintptr_t) dst_hnd->base, info);
+ return ret;
+}
diff --git a/msm8909/libcopybit/software_converter.h b/msm8909/libcopybit/software_converter.h
new file mode 100644
index 0000000..6e53e16
--- /dev/null
+++ b/msm8909/libcopybit/software_converter.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2011, The Linux Foundation. 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 The Linux Foundation 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 <copybit.h>
+#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/msm8909/libgralloc/Android.mk b/msm8909/libgralloc/Android.mk
new file mode 100644
index 0000000..412f1be
--- /dev/null
+++ b/msm8909/libgralloc/Android.mk
@@ -0,0 +1,46 @@
+# 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.
+
+# Gralloc module
+LOCAL_PATH := $(call my-dir)
+include $(LOCAL_PATH)/../common.mk
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := gralloc.$(TARGET_BOARD_PLATFORM)
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
+LOCAL_SHARED_LIBRARIES := $(common_libs) libmemalloc libqdMetaData
+LOCAL_SHARED_LIBRARIES += libqdutils libGLESv1_CM
+LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdgralloc\"
+LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps)
+LOCAL_SRC_FILES := gpu.cpp gralloc.cpp framebuffer.cpp mapper.cpp
+LOCAL_COPY_HEADERS_TO := $(common_header_export_path)
+LOCAL_COPY_HEADERS := gralloc_priv.h gr.h
+
+include $(BUILD_SHARED_LIBRARY)
+
+# MemAlloc Library
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libmemalloc
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
+LOCAL_SHARED_LIBRARIES := $(common_libs) libqdutils libdl
+LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdmemalloc\"
+LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps)
+LOCAL_SRC_FILES := ionalloc.cpp alloc_controller.cpp
+LOCAL_COPY_HEADERS := alloc_controller.h memalloc.h
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/msm8909/libgralloc/MODULE_LICENSE_APACHE2 b/msm8909/libgralloc/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/msm8909/libgralloc/MODULE_LICENSE_APACHE2
diff --git a/msm8909/libgralloc/NOTICE b/msm8909/libgralloc/NOTICE
new file mode 100644
index 0000000..3237da6
--- /dev/null
+++ b/msm8909/libgralloc/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2008-2009, 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/msm8909/libgralloc/alloc_controller.cpp b/msm8909/libgralloc/alloc_controller.cpp
new file mode 100644
index 0000000..3172c47
--- /dev/null
+++ b/msm8909/libgralloc/alloc_controller.cpp
@@ -0,0 +1,676 @@
+/*
+ * Copyright (c) 2011-2014, The Linux Foundation. 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 The Linux Foundation 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 <cutils/log.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+#include "gralloc_priv.h"
+#include "alloc_controller.h"
+#include "memalloc.h"
+#include "ionalloc.h"
+#include "gr.h"
+#include "comptype.h"
+#include "mdp_version.h"
+
+#ifdef VENUS_COLOR_FORMAT
+#include <media/msm_media_info.h>
+#else
+#define VENUS_Y_STRIDE(args...) 0
+#define VENUS_Y_SCANLINES(args...) 0
+#define VENUS_BUFFER_SIZE(args...) 0
+#endif
+
+#define ASTC_BLOCK_SIZE 16
+
+using namespace gralloc;
+using namespace qdutils;
+
+ANDROID_SINGLETON_STATIC_INSTANCE(AdrenoMemInfo);
+
+//Common functions
+static bool canFallback(int usage, bool triedSystem)
+{
+ // Fallback to system heap when alloc fails unless
+ // 1. Composition type is MDP
+ // 2. Alloc from system heap was already tried
+ // 3. The heap type is requsted explicitly
+ // 4. The heap type is protected
+ // 5. The buffer is meant for external display only
+
+ if(QCCompositionType::getInstance().getCompositionType() &
+ COMPOSITION_TYPE_MDP)
+ return false;
+ if(triedSystem)
+ return false;
+ if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_PROTECTED))
+ return false;
+ if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY))
+ return false;
+ //Return true by default
+ return true;
+}
+
+/* The default policy is to return cached buffers unless the client explicity
+ * sets the PRIVATE_UNCACHED flag or indicates that the buffer will be rarely
+ * read or written in software. Any combination with a _RARELY_ flag will be
+ * treated as uncached. */
+static bool useUncached(const int& usage) {
+ if((usage & GRALLOC_USAGE_PRIVATE_UNCACHED) or
+ ((usage & GRALLOC_USAGE_SW_WRITE_MASK) ==
+ GRALLOC_USAGE_SW_WRITE_RARELY) or
+ ((usage & GRALLOC_USAGE_SW_READ_MASK) ==
+ GRALLOC_USAGE_SW_READ_RARELY))
+ return true;
+
+ return false;
+}
+
+//-------------- AdrenoMemInfo-----------------------//
+AdrenoMemInfo::AdrenoMemInfo()
+{
+ LINK_adreno_compute_aligned_width_and_height = NULL;
+ LINK_adreno_compute_padding = NULL;
+ LINK_adreno_isMacroTilingSupportedByGpu = NULL;
+ LINK_adreno_compute_compressedfmt_aligned_width_and_height = NULL;
+ LINK_adreno_get_gpu_pixel_alignment = NULL;
+
+ libadreno_utils = ::dlopen("libadreno_utils.so", RTLD_NOW);
+ if (libadreno_utils) {
+ *(void **)&LINK_adreno_compute_aligned_width_and_height =
+ ::dlsym(libadreno_utils, "compute_aligned_width_and_height");
+ *(void **)&LINK_adreno_compute_padding =
+ ::dlsym(libadreno_utils, "compute_surface_padding");
+ *(void **)&LINK_adreno_isMacroTilingSupportedByGpu =
+ ::dlsym(libadreno_utils, "isMacroTilingSupportedByGpu");
+ *(void **)&LINK_adreno_compute_compressedfmt_aligned_width_and_height =
+ ::dlsym(libadreno_utils,
+ "compute_compressedfmt_aligned_width_and_height");
+ *(void **)&LINK_adreno_get_gpu_pixel_alignment =
+ ::dlsym(libadreno_utils, "get_gpu_pixel_alignment");
+ }
+}
+
+AdrenoMemInfo::~AdrenoMemInfo()
+{
+ if (libadreno_utils) {
+ ::dlclose(libadreno_utils);
+ }
+}
+
+int AdrenoMemInfo::isMacroTilingSupportedByGPU()
+{
+ if ((libadreno_utils)) {
+ if(LINK_adreno_isMacroTilingSupportedByGpu) {
+ return LINK_adreno_isMacroTilingSupportedByGpu();
+ }
+ }
+ return 0;
+}
+
+
+void AdrenoMemInfo::getAlignedWidthAndHeight(int width, int height, int format,
+ int tile_enabled, int& aligned_w, int& aligned_h)
+{
+ aligned_w = width;
+ aligned_h = height;
+ // Currently surface padding is only computed for RGB* surfaces.
+ if (format <= HAL_PIXEL_FORMAT_BGRA_8888) {
+ aligned_w = ALIGN(width, 32);
+ aligned_h = ALIGN(height, 32);
+ // Don't add any additional padding if debug.gralloc.map_fb_memory
+ // is enabled
+ char property[PROPERTY_VALUE_MAX];
+ if((property_get("debug.gralloc.map_fb_memory", property, NULL) > 0) &&
+ (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+ (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+ return;
+ }
+
+ int bpp = 4;
+ switch(format)
+ {
+ case HAL_PIXEL_FORMAT_RGB_888:
+ bpp = 3;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ bpp = 2;
+ break;
+ default: break;
+ }
+ if (libadreno_utils) {
+ int raster_mode = 0; // Adreno unknown raster mode.
+ int padding_threshold = 512; // Threshold for padding surfaces.
+ // the function below computes aligned width and aligned height
+ // based on linear or macro tile mode selected.
+ if(LINK_adreno_compute_aligned_width_and_height) {
+ LINK_adreno_compute_aligned_width_and_height(width,
+ height, bpp, tile_enabled,
+ raster_mode, padding_threshold,
+ &aligned_w, &aligned_h);
+
+ } else if(LINK_adreno_compute_padding) {
+ int surface_tile_height = 1; // Linear surface
+ aligned_w = LINK_adreno_compute_padding(width, bpp,
+ surface_tile_height, raster_mode,
+ padding_threshold);
+ ALOGW("%s: Warning!! Old GFX API is used to calculate stride",
+ __FUNCTION__);
+ } else {
+ ALOGW("%s: Warning!! Symbols compute_surface_padding and " \
+ "compute_aligned_width_and_height not found", __FUNCTION__);
+ }
+ }
+ } else {
+ int alignment = 32;
+ switch (format)
+ {
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP:
+ if (LINK_adreno_get_gpu_pixel_alignment) {
+ alignment = LINK_adreno_get_gpu_pixel_alignment();
+ }
+ aligned_w = ALIGN(width, alignment);
+ break;
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
+ aligned_w = ALIGN(width, alignment);
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
+ aligned_w = ALIGN(width, 128);
+ break;
+ case HAL_PIXEL_FORMAT_YV12:
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ case HAL_PIXEL_FORMAT_YCrCb_422_SP:
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ case HAL_PIXEL_FORMAT_YCrCb_422_I:
+ aligned_w = ALIGN(width, 16);
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+ case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
+ aligned_w = VENUS_Y_STRIDE(COLOR_FMT_NV12, width);
+ aligned_h = VENUS_Y_SCANLINES(COLOR_FMT_NV12, height);
+ break;
+ case HAL_PIXEL_FORMAT_BLOB:
+ break;
+ case HAL_PIXEL_FORMAT_NV21_ZSL:
+ aligned_w = ALIGN(width, 64);
+ aligned_h = ALIGN(height, 64);
+ break;
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_4x4_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x4_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x8_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x8_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x10_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x10_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x12_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
+ if(LINK_adreno_compute_compressedfmt_aligned_width_and_height) {
+ int bytesPerPixel = 0;
+ int raster_mode = 0; //Adreno unknown raster mode.
+ int padding_threshold = 512; //Threshold for padding
+ //surfaces.
+
+ LINK_adreno_compute_compressedfmt_aligned_width_and_height(
+ width, height, format, 0,raster_mode, padding_threshold,
+ &aligned_w, &aligned_h, &bytesPerPixel);
+
+ } else {
+ ALOGW("%s: Warning!! Symbols" \
+ " compute_compressedfmt_aligned_width_and_height" \
+ " not found", __FUNCTION__);
+ }
+ break;
+ default: break;
+ }
+ }
+}
+
+//-------------- IAllocController-----------------------//
+IAllocController* IAllocController::sController = NULL;
+IAllocController* IAllocController::getInstance(void)
+{
+ if(sController == NULL) {
+ sController = new IonController();
+ }
+ return sController;
+}
+
+
+//-------------- IonController-----------------------//
+IonController::IonController()
+{
+ allocateIonMem();
+}
+
+void IonController::allocateIonMem()
+{
+ mIonAlloc = new IonAlloc();
+}
+
+int IonController::allocate(alloc_data& data, int usage)
+{
+ int ionFlags = 0;
+ int ret;
+
+ data.uncached = useUncached(usage);
+ data.allocType = 0;
+
+ if(usage & GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP)
+ ionFlags |= ION_HEAP(ION_SF_HEAP_ID);
+
+ if(usage & GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP)
+ ionFlags |= ION_HEAP(ION_SYSTEM_HEAP_ID);
+
+ if(usage & GRALLOC_USAGE_PRIVATE_IOMMU_HEAP)
+ ionFlags |= ION_HEAP(ION_IOMMU_HEAP_ID);
+
+ if(usage & GRALLOC_USAGE_PROTECTED) {
+ if (usage & GRALLOC_USAGE_PRIVATE_MM_HEAP) {
+ ionFlags |= ION_HEAP(ION_CP_MM_HEAP_ID);
+ ionFlags |= ION_SECURE;
+ } else {
+ // for targets/OEMs which do not need HW level protection
+ // do not set ion secure flag & MM heap. Fallback to IOMMU heap.
+ ionFlags |= ION_HEAP(ION_IOMMU_HEAP_ID);
+ }
+ } else if(usage & GRALLOC_USAGE_PRIVATE_MM_HEAP) {
+ //MM Heap is exclusively a secure heap.
+ //If it is used for non secure cases, fallback to IOMMU heap
+ ALOGW("GRALLOC_USAGE_PRIVATE_MM_HEAP \
+ cannot be used as an insecure heap!\
+ trying to use IOMMU instead !!");
+ ionFlags |= ION_HEAP(ION_IOMMU_HEAP_ID);
+ }
+
+ if(usage & GRALLOC_USAGE_PRIVATE_CAMERA_HEAP)
+ ionFlags |= ION_HEAP(ION_CAMERA_HEAP_ID);
+
+ if(usage & GRALLOC_USAGE_PRIVATE_ADSP_HEAP)
+ ionFlags |= ION_HEAP(ION_ADSP_HEAP_ID);
+
+ if(ionFlags & ION_SECURE)
+ data.allocType |= private_handle_t::PRIV_FLAGS_SECURE_BUFFER;
+
+ // if no flags are set, default to
+ // SF + IOMMU heaps, so that bypass can work
+ // we can fall back to system heap if
+ // we run out.
+ if(!ionFlags)
+ ionFlags = ION_HEAP(ION_SF_HEAP_ID) | ION_HEAP(ION_IOMMU_HEAP_ID);
+
+ data.flags = ionFlags;
+ ret = mIonAlloc->alloc_buffer(data);
+
+ // Fallback
+ if(ret < 0 && canFallback(usage,
+ (ionFlags & ION_SYSTEM_HEAP_ID)))
+ {
+ ALOGW("Falling back to system heap");
+ data.flags = ION_HEAP(ION_SYSTEM_HEAP_ID);
+ ret = mIonAlloc->alloc_buffer(data);
+ }
+
+ if(ret >= 0 ) {
+ data.allocType |= private_handle_t::PRIV_FLAGS_USES_ION;
+ }
+
+ return ret;
+}
+
+IMemAlloc* IonController::getAllocator(int flags)
+{
+ IMemAlloc* memalloc = NULL;
+ if (flags & private_handle_t::PRIV_FLAGS_USES_ION) {
+ memalloc = mIonAlloc;
+ } else {
+ ALOGE("%s: Invalid flags passed: 0x%x", __FUNCTION__, flags);
+ }
+
+ return memalloc;
+}
+
+bool isMacroTileEnabled(int format, int usage)
+{
+ bool tileEnabled = false;
+
+ // Check whether GPU & MDSS supports MacroTiling feature
+ if(AdrenoMemInfo::getInstance().isMacroTilingSupportedByGPU() &&
+ qdutils::MDPVersion::getInstance().supportsMacroTile())
+ {
+ // check the format
+ switch(format)
+ {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ case HAL_PIXEL_FORMAT_RGB_565:
+ {
+ tileEnabled = true;
+ // check the usage flags
+ if (usage & (GRALLOC_USAGE_SW_READ_MASK |
+ GRALLOC_USAGE_SW_WRITE_MASK)) {
+ // Application intends to use CPU for rendering
+ tileEnabled = false;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return tileEnabled;
+}
+
+// helper function
+unsigned int getSize(int format, int width, int height, const int alignedw,
+ const int alignedh) {
+ unsigned int size = 0;
+
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ size = alignedw * alignedh * 4;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_888:
+ size = alignedw * alignedh * 3;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ case HAL_PIXEL_FORMAT_RAW16:
+ size = alignedw * alignedh * 2;
+ break;
+
+ // adreno formats
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: // NV21
+ size = ALIGN(alignedw*alignedh, 4096);
+ size += ALIGN(2 * ALIGN(width/2, 32) * ALIGN(height/2, 32), 4096);
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: // NV12
+ // The chroma plane is subsampled,
+ // but the pitch in bytes is unchanged
+ // The GPU needs 4K alignment, but the video decoder needs 8K
+ size = ALIGN( alignedw * alignedh, 8192);
+ size += ALIGN( alignedw * ALIGN(height/2, 32), 8192);
+ break;
+ case HAL_PIXEL_FORMAT_YV12:
+ if ((format == HAL_PIXEL_FORMAT_YV12) && ((width&1) || (height&1))) {
+ ALOGE("w or h is odd for the YV12 format");
+ return 0;
+ }
+ size = alignedw*alignedh +
+ (ALIGN(alignedw/2, 16) * (alignedh/2))*2;
+ size = ALIGN(size, (unsigned int)4096);
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP:
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ size = ALIGN((alignedw*alignedh) + (alignedw* alignedh)/2 + 1, 4096);
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ case HAL_PIXEL_FORMAT_YCrCb_422_SP:
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ case HAL_PIXEL_FORMAT_YCrCb_422_I:
+ if(width & 1) {
+ ALOGE("width is odd for the YUV422_SP format");
+ return 0;
+ }
+ size = ALIGN(alignedw * alignedh * 2, 4096);
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+ case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
+ size = VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height);
+ break;
+ case HAL_PIXEL_FORMAT_BLOB:
+ if(height != 1) {
+ ALOGE("%s: Buffers with format HAL_PIXEL_FORMAT_BLOB \
+ must have height==1 ", __FUNCTION__);
+ return 0;
+ }
+ size = width;
+ break;
+ case HAL_PIXEL_FORMAT_NV21_ZSL:
+ size = ALIGN((alignedw*alignedh) + (alignedw* alignedh)/2, 4096);
+ break;
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_4x4_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x4_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x8_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x8_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x10_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x10_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x12_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
+ case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
+ size = alignedw * alignedh * ASTC_BLOCK_SIZE;
+ break;
+ default:
+ ALOGE("unrecognized pixel format: 0x%x", format);
+ return 0;
+ }
+ return size;
+}
+
+unsigned int getBufferSizeAndDimensions(int width, int height, int format,
+ int& alignedw, int &alignedh)
+{
+ unsigned int size;
+
+ AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width,
+ height,
+ format,
+ false,
+ alignedw,
+ alignedh);
+
+ size = getSize(format, width, height, alignedw, alignedh);
+
+ return size;
+}
+
+
+unsigned int getBufferSizeAndDimensions(int width, int height, int format,
+ int usage, int& alignedw, int &alignedh)
+{
+ unsigned int size;
+ int tileEnabled = isMacroTileEnabled(format, usage);
+
+ AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width,
+ height,
+ format,
+ tileEnabled,
+ alignedw,
+ alignedh);
+
+ size = getSize(format, width, height, alignedw, alignedh);
+
+ return size;
+}
+
+
+void getBufferAttributes(int width, int height, int format, int usage,
+ int& alignedw, int &alignedh, int& tileEnabled, unsigned int& size)
+{
+ tileEnabled = isMacroTileEnabled(format, usage);
+
+ AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width,
+ height,
+ format,
+ tileEnabled,
+ alignedw,
+ alignedh);
+ size = getSize(format, width, height, alignedw, alignedh);
+}
+
+int getYUVPlaneInfo(private_handle_t* hnd, struct android_ycbcr* ycbcr)
+{
+ int err = 0;
+ unsigned int ystride, cstride;
+ memset(ycbcr->reserved, 0, sizeof(ycbcr->reserved));
+
+ // Get the chroma offsets from the handle width/height. We take advantage
+ // of the fact the width _is_ the stride
+ switch (hnd->format) {
+ //Semiplanar
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP:
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+ case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: //Same as YCbCr_420_SP_VENUS
+ ystride = cstride = hnd->width;
+ ycbcr->y = (void*)hnd->base;
+ ycbcr->cb = (void*)(hnd->base + ystride * hnd->height);
+ ycbcr->cr = (void*)(hnd->base + ystride * hnd->height + 1);
+ ycbcr->ystride = ystride;
+ ycbcr->cstride = cstride;
+ ycbcr->chroma_step = 2;
+ break;
+
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ case HAL_PIXEL_FORMAT_YCrCb_422_SP:
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
+ case HAL_PIXEL_FORMAT_NV21_ZSL:
+ ystride = cstride = hnd->width;
+ ycbcr->y = (void*)hnd->base;
+ ycbcr->cr = (void*)(hnd->base + ystride * hnd->height);
+ ycbcr->cb = (void*)(hnd->base + ystride * hnd->height + 1);
+ ycbcr->ystride = ystride;
+ ycbcr->cstride = cstride;
+ ycbcr->chroma_step = 2;
+ break;
+
+ //Planar
+ case HAL_PIXEL_FORMAT_YV12:
+ ystride = hnd->width;
+ cstride = ALIGN(hnd->width/2, 16);
+ ycbcr->y = (void*)hnd->base;
+ ycbcr->cr = (void*)(hnd->base + ystride * hnd->height);
+ ycbcr->cb = (void*)(hnd->base + ystride * hnd->height +
+ cstride * hnd->height/2);
+ ycbcr->ystride = ystride;
+ ycbcr->cstride = cstride;
+ ycbcr->chroma_step = 1;
+
+ break;
+ //Unsupported formats
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ case HAL_PIXEL_FORMAT_YCrCb_422_I:
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
+ default:
+ ALOGD("%s: Invalid format passed: 0x%x", __FUNCTION__,
+ hnd->format);
+ err = -EINVAL;
+ }
+ return err;
+
+}
+
+
+
+// Allocate buffer from width, height and format into a
+// private_handle_t. It is the responsibility of the caller
+// 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;
+ gralloc::IAllocController* sAlloc =
+ gralloc::IAllocController::getInstance();
+ data.base = 0;
+ data.fd = -1;
+ data.offset = 0;
+ data.size = getBufferSizeAndDimensions(w, h, format, usage, alignedw,
+ alignedh);
+
+ data.align = getpagesize();
+ data.uncached = useUncached(usage);
+ int allocFlags = usage;
+
+ int err = sAlloc->allocate(data, allocFlags);
+ 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 = (uint64_t) data.base;
+ hnd->offset = data.offset;
+ hnd->gpuaddr = 0;
+ *pHnd = hnd;
+ return 0;
+}
+
+void free_buffer(private_handle_t *hnd)
+{
+ gralloc::IAllocController* sAlloc =
+ gralloc::IAllocController::getInstance();
+ if (hnd && hnd->fd > 0) {
+ IMemAlloc* memalloc = sAlloc->getAllocator(hnd->flags);
+ memalloc->free_buffer((void*)hnd->base, hnd->size, hnd->offset, hnd->fd);
+ }
+ if(hnd)
+ delete hnd;
+
+}
diff --git a/msm8909/libgralloc/alloc_controller.h b/msm8909/libgralloc/alloc_controller.h
new file mode 100644
index 0000000..f0b8ed9
--- /dev/null
+++ b/msm8909/libgralloc/alloc_controller.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2011-2012, The Linux Foundation. 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 The Linux Foundation 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 GRALLOC_ALLOCCONTROLLER_H
+#define GRALLOC_ALLOCCONTROLLER_H
+
+namespace gralloc {
+
+struct alloc_data;
+class IMemAlloc;
+class IonAlloc;
+
+class IAllocController {
+
+ public:
+ /* Allocate using a suitable method
+ * Returns the type of buffer allocated
+ */
+ virtual int allocate(alloc_data& data, int usage) = 0;
+
+ virtual IMemAlloc* getAllocator(int flags) = 0;
+
+ virtual ~IAllocController() {};
+
+ static IAllocController* getInstance(void);
+
+ private:
+ static IAllocController* sController;
+
+};
+
+class IonController : public IAllocController {
+
+ public:
+ virtual int allocate(alloc_data& data, int usage);
+
+ virtual IMemAlloc* getAllocator(int flags);
+
+ IonController();
+
+ private:
+ IonAlloc* mIonAlloc;
+ void allocateIonMem();
+
+};
+} //end namespace gralloc
+#endif // GRALLOC_ALLOCCONTROLLER_H
diff --git a/msm8909/libgralloc/fb_priv.h b/msm8909/libgralloc/fb_priv.h
new file mode 100644
index 0000000..e2eba6a
--- /dev/null
+++ b/msm8909/libgralloc/fb_priv.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (c) 2012-2014, The Linux Foundation. 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 <linux/fb.h>
+#include <linux/msm_mdp.h>
+
+#define NUM_FRAMEBUFFERS_MIN 2
+#define NUM_FRAMEBUFFERS_MAX 3
+
+#define NO_SURFACEFLINGER_SWAPINTERVAL
+#define COLOR_FORMAT(x) (x & 0xFFF) // Max range for colorFormats is 0 - FFF
+
+struct private_handle_t;
+
+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 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;
+ struct fb_var_screeninfo info;
+ struct fb_fix_screeninfo finfo;
+ float xdpi;
+ float ydpi;
+ float fps;
+ uint32_t swapInterval;
+};
+
+
+
+#endif /* FB_PRIV_H */
diff --git a/msm8909/libgralloc/framebuffer.cpp b/msm8909/libgralloc/framebuffer.cpp
new file mode 100644
index 0000000..0ebc3db
--- /dev/null
+++ b/msm8909/libgralloc/framebuffer.cpp
@@ -0,0 +1,461 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (c) 2010-2014 The Linux Foundation. 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 <sys/mman.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include <dlfcn.h>
+
+#include <hardware/hardware.h>
+
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <cutils/atomic.h>
+
+#include <linux/fb.h>
+#include <linux/msm_mdp.h>
+
+#include <GLES/gl.h>
+
+#include "gralloc_priv.h"
+#include "fb_priv.h"
+#include "gr.h"
+#include <cutils/properties.h>
+#include <profiler.h>
+
+#define EVEN_OUT(x) if (x & 0x0001) {x--;}
+/** min of int a, b */
+static inline int min(int a, int b) {
+ return (a<b) ? a : b;
+}
+/** max of int a, b */
+static inline int max(int a, int b) {
+ return (a>b) ? a : b;
+}
+
+enum {
+ PAGE_FLIP = 0x00000001,
+};
+
+struct fb_context_t {
+ framebuffer_device_t device;
+ //fd - which is returned on open
+ int fbFd;
+};
+
+static int fb_setSwapInterval(struct framebuffer_device_t* dev,
+ int interval)
+{
+ //XXX: Get the value here and implement along with
+ //single vsync in HWC
+ char pval[PROPERTY_VALUE_MAX];
+ property_get("debug.egl.swapinterval", pval, "-1");
+ int property_interval = atoi(pval);
+ if (property_interval >= 0)
+ interval = property_interval;
+
+ private_module_t* m = reinterpret_cast<private_module_t*>(
+ dev->common.module);
+ if (interval < dev->minSwapInterval || interval > dev->maxSwapInterval)
+ return -EINVAL;
+
+ m->swapInterval = interval;
+ return 0;
+}
+
+static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
+{
+ private_module_t* m =
+ reinterpret_cast<private_module_t*>(dev->common.module);
+ private_handle_t *hnd = static_cast<private_handle_t*>
+ (const_cast<native_handle_t*>(buffer));
+ fb_context_t *ctx = reinterpret_cast<fb_context_t*>(dev);
+ const unsigned int offset = (unsigned int) (hnd->base -
+ m->framebuffer->base);
+ m->info.activate = FB_ACTIVATE_VBL;
+ m->info.yoffset = (int)(offset / m->finfo.line_length);
+ if (ioctl(ctx->fbFd, FBIOPUT_VSCREENINFO, &m->info) == -1) {
+ ALOGE("%s: FBIOPUT_VSCREENINFO for primary failed, str: %s",
+ __FUNCTION__, strerror(errno));
+ return -errno;
+ }
+ return 0;
+}
+
+static int fb_compositionComplete(struct framebuffer_device_t* dev)
+{
+ // TODO: Properly implement composition complete callback
+ if(!dev) {
+ return -1;
+ }
+ glFinish();
+
+ return 0;
+}
+
+int mapFrameBufferLocked(framebuffer_device_t *dev)
+{
+ private_module_t* module =
+ reinterpret_cast<private_module_t*>(dev->common.module);
+ fb_context_t *ctx = reinterpret_cast<fb_context_t*>(dev);
+ // already initialized...
+ if (module->framebuffer) {
+ return 0;
+ }
+ char const * const device_template[] = {
+ "/dev/graphics/fb%u",
+ "/dev/fb%u",
+ 0 };
+
+ int fd = -1;
+ int i=0;
+ char name[64];
+ char property[PROPERTY_VALUE_MAX];
+
+ while ((fd==-1) && device_template[i]) {
+ snprintf(name, 64, device_template[i], 0);
+ fd = open(name, O_RDWR, 0);
+ i++;
+ }
+ if (fd < 0)
+ return -errno;
+
+ struct fb_fix_screeninfo finfo;
+ if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) {
+ close(fd);
+ return -errno;
+ }
+
+ struct fb_var_screeninfo info;
+ if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1) {
+ close(fd);
+ return -errno;
+ }
+
+ info.reserved[0] = 0;
+ info.reserved[1] = 0;
+ info.reserved[2] = 0;
+ info.xoffset = 0;
+ info.yoffset = 0;
+ 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.
+ */
+
+ if(info.bits_per_pixel == 32) {
+ /*
+ * Explicitly request RGBA_8888
+ */
+ info.bits_per_pixel = 32;
+ info.red.offset = 24;
+ info.red.length = 8;
+ info.green.offset = 16;
+ info.green.length = 8;
+ info.blue.offset = 8;
+ info.blue.length = 8;
+ info.transp.offset = 0;
+ info.transp.length = 8;
+
+ /* Note: the GL driver does not have a r=8 g=8 b=8 a=0 config, so if we
+ * do not use the MDP for composition (i.e. hw composition == 0), ask
+ * for 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))
+ module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888;
+ else
+ module->fbFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+ } else {
+ /*
+ * Explicitly request 5/6/5
+ */
+ info.bits_per_pixel = 16;
+ info.red.offset = 11;
+ info.red.length = 5;
+ info.green.offset = 5;
+ info.green.length = 6;
+ info.blue.offset = 0;
+ info.blue.length = 5;
+ info.transp.offset = 0;
+ info.transp.length = 0;
+ module->fbFormat = HAL_PIXEL_FORMAT_RGB_565;
+ }
+
+ //adreno needs 4k aligned offsets. Max hole size is 4096-1
+ unsigned int size = roundUpToPageSize(info.yres * info.xres *
+ (info.bits_per_pixel/8));
+
+ /*
+ * 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);
+
+ if (property_get("debug.gr.numframebuffers", property, NULL) > 0) {
+ int num = atoi(property);
+ if ((num >= NUM_FRAMEBUFFERS_MIN) && (num <= NUM_FRAMEBUFFERS_MAX)) {
+ numberOfBuffers = num;
+ }
+ }
+ if (numberOfBuffers > NUM_FRAMEBUFFERS_MAX)
+ numberOfBuffers = NUM_FRAMEBUFFERS_MAX;
+
+ ALOGV("We support %d buffers", numberOfBuffers);
+
+ //consider the included hole by 4k alignment
+ uint32_t line_length = (info.xres * info.bits_per_pixel / 8);
+ info.yres_virtual = (uint32_t) ((size * numberOfBuffers) / line_length);
+
+ uint32_t flags = PAGE_FLIP;
+
+ if (info.yres_virtual < ((size * 2) / line_length) ) {
+ // we need at least 2 for page-flipping
+ info.yres_virtual = (int)(size / line_length);
+ flags &= ~PAGE_FLIP;
+ ALOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
+ info.yres_virtual, info.yres*2);
+ }
+
+ if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1) {
+ close(fd);
+ return -errno;
+ }
+
+ if (int(info.width) <= 0 || int(info.height) <= 0) {
+ // the driver doesn't return that information
+ // default to 160 dpi
+ info.width = (uint32_t)(((float)(info.xres) * 25.4f)/160.0f + 0.5f);
+ info.height = (uint32_t)(((float)(info.yres) * 25.4f)/160.0f + 0.5f);
+ }
+
+ float xdpi = ((float)(info.xres) * 25.4f) / (float)info.width;
+ float ydpi = ((float)(info.yres) * 25.4f) / (float)info.height;
+
+#ifdef MSMFB_METADATA_GET
+ struct msmfb_metadata metadata;
+ memset(&metadata, 0 , sizeof(metadata));
+ metadata.op = metadata_op_frame_rate;
+ if (ioctl(fd, MSMFB_METADATA_GET, &metadata) == -1) {
+ ALOGE("Error retrieving panel frame rate");
+ close(fd);
+ return -errno;
+ }
+ float fps = (float)metadata.data.panel_frame_rate;
+#else
+ //XXX: Remove reserved field usage on all baselines
+ //The reserved[3] field is used to store FPS by the driver.
+ float fps = info.reserved[3] & 0xFF;
+#endif
+ 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
+ );
+
+
+ if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) {
+ close(fd);
+ return -errno;
+ }
+
+ if (finfo.smem_len <= 0) {
+ close(fd);
+ return -errno;
+ }
+
+ module->flags = flags;
+ module->info = info;
+ module->finfo = finfo;
+ module->xdpi = xdpi;
+ module->ydpi = ydpi;
+ module->fps = fps;
+ module->swapInterval = 1;
+
+ CALC_INIT();
+
+ /*
+ * map the framebuffer
+ */
+
+ module->numBuffers = info.yres_virtual / info.yres;
+ module->bufferMask = 0;
+ //adreno needs page aligned offsets. Align the fbsize to pagesize.
+ unsigned int fbSize = roundUpToPageSize(finfo.line_length * info.yres)*
+ module->numBuffers;
+ 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));
+ close(fd);
+ return -errno;
+ }
+ //store the framebuffer fd in the ctx
+ ctx->fbFd = fd;
+#ifdef MSMFB_METADATA_GET
+ memset(&metadata, 0 , sizeof(metadata));
+ metadata.op = metadata_op_get_ion_fd;
+ // get the ION fd for the framebuffer, as GPU needs ION fd
+ if (ioctl(fd, MSMFB_METADATA_GET, &metadata) == -1) {
+ ALOGE("Error getting ION fd (%s)", strerror(errno));
+ close(fd);
+ return -errno;
+ }
+ if(metadata.data.fbmem_ionfd < 0) {
+ ALOGE("Error: Ioctl returned invalid ION fd = %d",
+ metadata.data.fbmem_ionfd);
+ close(fd);
+ return -errno;
+ }
+ fd = metadata.data.fbmem_ionfd;
+#endif
+ // Create framebuffer handle using the ION fd
+ module->framebuffer = new private_handle_t(fd, fbSize,
+ private_handle_t::PRIV_FLAGS_USES_ION,
+ BUFFER_TYPE_UI,
+ module->fbFormat, info.xres, info.yres);
+ module->framebuffer->base = uint64_t(vaddr);
+ memset(vaddr, 0, fbSize);
+ //Enable vsync
+ int enable = 1;
+ ioctl(ctx->fbFd, MSMFB_OVERLAY_VSYNC_CTRL, &enable);
+ return 0;
+}
+
+static int mapFrameBuffer(framebuffer_device_t *dev)
+{
+ int err = -1;
+ char property[PROPERTY_VALUE_MAX];
+ if((property_get("debug.gralloc.map_fb_memory", property, NULL) > 0) &&
+ (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+ (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+ private_module_t* module =
+ reinterpret_cast<private_module_t*>(dev->common.module);
+ pthread_mutex_lock(&module->lock);
+ err = mapFrameBufferLocked(dev);
+ pthread_mutex_unlock(&module->lock);
+ }
+ return err;
+}
+
+/*****************************************************************************/
+
+static int fb_close(struct hw_device_t *dev)
+{
+ fb_context_t* ctx = (fb_context_t*)dev;
+ if (ctx) {
+#ifdef MSMFB_METADATA_GET
+ if(ctx->fbFd >=0) {
+ close(ctx->fbFd);
+ }
+#endif
+ //Hack until fbdev is removed. Framework could close this causing hwc a
+ //pain.
+ //free(ctx);
+ }
+ return 0;
+}
+
+int fb_device_open(hw_module_t const* module, const char* name,
+ hw_device_t** device)
+{
+ int status = -EINVAL;
+ if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {
+ alloc_device_t* gralloc_device;
+ status = gralloc_open(module, &gralloc_device);
+ if (status < 0)
+ return status;
+
+ /* initialize our state here */
+ fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
+ if(dev == NULL) {
+ gralloc_close(gralloc_device);
+ return status;
+ }
+ 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<hw_module_t*>(module);
+ dev->device.common.close = fb_close;
+ dev->device.setSwapInterval = fb_setSwapInterval;
+ dev->device.post = fb_post;
+ dev->device.setUpdateRect = 0;
+ dev->device.compositionComplete = fb_compositionComplete;
+
+ status = mapFrameBuffer((framebuffer_device_t*)dev);
+ private_module_t* m = (private_module_t*)dev->device.common.module;
+ if (status >= 0) {
+ int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
+ const_cast<uint32_t&>(dev->device.flags) = 0;
+ const_cast<uint32_t&>(dev->device.width) = m->info.xres;
+ const_cast<uint32_t&>(dev->device.height) = m->info.yres;
+ const_cast<int&>(dev->device.stride) = stride;
+ const_cast<int&>(dev->device.format) = m->fbFormat;
+ const_cast<float&>(dev->device.xdpi) = m->xdpi;
+ const_cast<float&>(dev->device.ydpi) = m->ydpi;
+ const_cast<float&>(dev->device.fps) = m->fps;
+ const_cast<int&>(dev->device.minSwapInterval) =
+ PRIV_MIN_SWAP_INTERVAL;
+ const_cast<int&>(dev->device.maxSwapInterval) =
+ PRIV_MAX_SWAP_INTERVAL;
+ const_cast<int&>(dev->device.numFramebuffers) = m->numBuffers;
+ dev->device.setUpdateRect = 0;
+
+ *device = &dev->device.common;
+ }
+
+ // Close the gralloc module
+ gralloc_close(gralloc_device);
+ }
+ return status;
+}
diff --git a/msm8909/libgralloc/gpu.cpp b/msm8909/libgralloc/gpu.cpp
new file mode 100644
index 0000000..49274d0
--- /dev/null
+++ b/msm8909/libgralloc/gpu.cpp
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (c) 2011-2014 The Linux Foundation. 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 <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <cutils/properties.h>
+#include <sys/mman.h>
+
+#include "gr.h"
+#include "gpu.h"
+#include "memalloc.h"
+#include "alloc_controller.h"
+#include <qdMetaData.h>
+
+using namespace gralloc;
+
+#define SZ_1M 0x100000
+
+gpu_context_t::gpu_context_t(const private_module_t* module,
+ IAllocController* alloc_ctrl ) :
+ mAllocCtrl(alloc_ctrl)
+{
+ // Zero out the alloc_device_t
+ memset(static_cast<alloc_device_t*>(this), 0, sizeof(alloc_device_t));
+
+ // Initialize the procs
+ common.tag = HARDWARE_DEVICE_TAG;
+ common.version = 0;
+ common.module = const_cast<hw_module_t*>(&module->base.common);
+ common.close = gralloc_close;
+ alloc = gralloc_alloc;
+ free = gralloc_free;
+
+}
+
+int gpu_context_t::gralloc_alloc_buffer(unsigned int size, int usage,
+ buffer_handle_t* pHandle, int bufferType,
+ int format, int width, int height)
+{
+ int err = 0;
+ int flags = 0;
+ size = roundUpToPageSize(size);
+ alloc_data data;
+ data.offset = 0;
+ data.fd = -1;
+ data.base = 0;
+ if(format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED)
+ data.align = 8192;
+ else
+ data.align = getpagesize();
+
+ /* force 1MB alignment selectively for secure buffers, MDP5 onwards */
+#ifdef MDSS_TARGET
+ if ((usage & GRALLOC_USAGE_PROTECTED) &&
+ (usage & GRALLOC_USAGE_PRIVATE_MM_HEAP)) {
+ data.align = ALIGN((int) data.align, SZ_1M);
+ size = ALIGN(size, data.align);
+ }
+#endif
+
+ data.size = size;
+ data.pHandle = (uintptr_t) pHandle;
+ err = mAllocCtrl->allocate(data, usage);
+
+ if (!err) {
+ /* allocate memory for enhancement data */
+ alloc_data eData;
+ eData.fd = -1;
+ eData.base = 0;
+ eData.offset = 0;
+ eData.size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));
+ eData.pHandle = data.pHandle;
+ eData.align = getpagesize();
+ int eDataUsage = GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP;
+ int eDataErr = mAllocCtrl->allocate(eData, eDataUsage);
+ ALOGE_IF(eDataErr, "gralloc failed for eDataErr=%s",
+ strerror(-eDataErr));
+
+ if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY) {
+ flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY;
+ }
+ if (usage & GRALLOC_USAGE_PRIVATE_INTERNAL_ONLY) {
+ flags |= private_handle_t::PRIV_FLAGS_INTERNAL_ONLY;
+ }
+
+ ColorSpace_t colorSpace = ITU_R_601;
+ flags |= private_handle_t::PRIV_FLAGS_ITU_R_601;
+ if (bufferType == BUFFER_TYPE_VIDEO) {
+ if (usage & GRALLOC_USAGE_HW_CAMERA_WRITE) {
+#ifndef MDSS_TARGET
+ colorSpace = ITU_R_601_FR;
+ flags |= private_handle_t::PRIV_FLAGS_ITU_R_601_FR;
+#else
+ // Per the camera spec ITU 709 format should be set only for
+ // video encoding.
+ // It should be set to ITU 601 full range format for any other
+ // camera buffer
+ //
+ if (usage & GRALLOC_USAGE_HW_CAMERA_MASK) {
+ if (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) {
+ flags |= private_handle_t::PRIV_FLAGS_ITU_R_709;
+ colorSpace = ITU_R_709;
+ } else {
+ flags |= private_handle_t::PRIV_FLAGS_ITU_R_601_FR;
+ colorSpace = ITU_R_601_FR;
+ }
+ }
+#endif
+ }
+ }
+
+ if (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER ) {
+ flags |= private_handle_t::PRIV_FLAGS_VIDEO_ENCODER;
+ }
+
+ if (usage & GRALLOC_USAGE_HW_CAMERA_WRITE) {
+ flags |= private_handle_t::PRIV_FLAGS_CAMERA_WRITE;
+ }
+
+ if (usage & GRALLOC_USAGE_HW_CAMERA_READ) {
+ flags |= private_handle_t::PRIV_FLAGS_CAMERA_READ;
+ }
+
+ if (usage & GRALLOC_USAGE_HW_COMPOSER) {
+ flags |= private_handle_t::PRIV_FLAGS_HW_COMPOSER;
+ }
+
+ if (usage & GRALLOC_USAGE_HW_TEXTURE) {
+ flags |= private_handle_t::PRIV_FLAGS_HW_TEXTURE;
+ }
+
+ if(usage & GRALLOC_USAGE_PRIVATE_SECURE_DISPLAY) {
+ flags |= private_handle_t::PRIV_FLAGS_SECURE_DISPLAY;
+ }
+
+ if(isMacroTileEnabled(format, usage)) {
+ flags |= private_handle_t::PRIV_FLAGS_TILE_RENDERED;
+ }
+
+ if(usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) {
+ flags |= private_handle_t::PRIV_FLAGS_CPU_RENDERED;
+ }
+
+ if (usage & (GRALLOC_USAGE_HW_VIDEO_ENCODER |
+ GRALLOC_USAGE_HW_CAMERA_WRITE |
+ GRALLOC_USAGE_HW_RENDER |
+ GRALLOC_USAGE_HW_FB)) {
+ flags |= private_handle_t::PRIV_FLAGS_NON_CPU_WRITER;
+ }
+
+ if(false == data.uncached) {
+ flags |= private_handle_t::PRIV_FLAGS_CACHED;
+ }
+
+ flags |= data.allocType;
+ uint64_t eBaseAddr = (uint64_t)(eData.base) + eData.offset;
+ private_handle_t *hnd = new private_handle_t(data.fd, size, flags,
+ bufferType, format, width, height, eData.fd, eData.offset,
+ eBaseAddr);
+
+ hnd->offset = data.offset;
+ hnd->base = (uint64_t)(data.base) + data.offset;
+ hnd->gpuaddr = 0;
+ setMetaData(hnd, UPDATE_COLOR_SPACE, (void*) &colorSpace);
+
+ *pHandle = hnd;
+ }
+
+ ALOGE_IF(err, "gralloc failed err=%s", strerror(-err));
+
+ return err;
+}
+
+void gpu_context_t::getGrallocInformationFromFormat(int inputFormat,
+ int *bufferType)
+{
+ *bufferType = BUFFER_TYPE_VIDEO;
+
+ if (inputFormat <= HAL_PIXEL_FORMAT_BGRA_8888) {
+ // RGB formats
+ *bufferType = BUFFER_TYPE_UI;
+ } else if ((inputFormat == HAL_PIXEL_FORMAT_R_8) ||
+ (inputFormat == HAL_PIXEL_FORMAT_RG_88)) {
+ *bufferType = BUFFER_TYPE_UI;
+ }
+}
+
+int gpu_context_t::gralloc_alloc_framebuffer_locked(int usage,
+ buffer_handle_t* pHandle)
+{
+ private_module_t* m = reinterpret_cast<private_module_t*>(common.module);
+
+ // we don't support framebuffer allocations with graphics heap flags
+ if (usage & GRALLOC_HEAP_MASK) {
+ return -EINVAL;
+ }
+
+ if (m->framebuffer == NULL) {
+ ALOGE("%s: Invalid framebuffer", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ const unsigned int bufferMask = m->bufferMask;
+ const uint32_t numBuffers = m->numBuffers;
+ unsigned int bufferSize = m->finfo.line_length * m->info.yres;
+
+ //adreno needs FB size to be page aligned
+ bufferSize = roundUpToPageSize(bufferSize);
+
+ if (numBuffers == 1) {
+ // If we have only one buffer, we never use page-flipping. Instead,
+ // we return a regular buffer which will be memcpy'ed to the main
+ // screen when post is called.
+ int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;
+ return gralloc_alloc_buffer(bufferSize, newUsage, pHandle, BUFFER_TYPE_UI,
+ m->fbFormat, m->info.xres, m->info.yres);
+ }
+
+ if (bufferMask >= ((1LU<<numBuffers)-1)) {
+ // We ran out of buffers.
+ return -ENOMEM;
+ }
+
+ // create a "fake" handle for it
+ uint64_t vaddr = uint64_t(m->framebuffer->base);
+ // As GPU needs ION FD, the private handle is created
+ // using ION fd and ION flags are set
+ private_handle_t* hnd = new private_handle_t(
+ dup(m->framebuffer->fd), bufferSize,
+ private_handle_t::PRIV_FLAGS_USES_ION |
+ private_handle_t::PRIV_FLAGS_FRAMEBUFFER,
+ BUFFER_TYPE_UI, m->fbFormat, m->info.xres,
+ m->info.yres);
+
+ // find a free slot
+ for (uint32_t i=0 ; i<numBuffers ; i++) {
+ if ((bufferMask & (1LU<<i)) == 0) {
+ m->bufferMask |= (uint32_t)(1LU<<i);
+ break;
+ }
+ vaddr += bufferSize;
+ }
+ hnd->base = vaddr;
+ hnd->offset = (unsigned int)(vaddr - m->framebuffer->base);
+ *pHandle = hnd;
+ return 0;
+}
+
+
+int gpu_context_t::gralloc_alloc_framebuffer(int usage,
+ buffer_handle_t* pHandle)
+{
+ private_module_t* m = reinterpret_cast<private_module_t*>(common.module);
+ pthread_mutex_lock(&m->lock);
+ int err = gralloc_alloc_framebuffer_locked(usage, pHandle);
+ pthread_mutex_unlock(&m->lock);
+ return err;
+}
+
+int gpu_context_t::alloc_impl(int w, int h, int format, int usage,
+ buffer_handle_t* pHandle, int* pStride,
+ unsigned int bufferSize) {
+ if (!pHandle || !pStride)
+ return -EINVAL;
+
+ unsigned int size;
+ int alignedw, alignedh;
+ int grallocFormat = format;
+ int bufferType;
+
+ //If input format is HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED then based on
+ //the usage bits, gralloc assigns a format.
+ if(format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED ||
+ format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+ if(usage & GRALLOC_USAGE_HW_VIDEO_ENCODER)
+ grallocFormat = HAL_PIXEL_FORMAT_NV12_ENCODEABLE; //NV12
+ else if((usage & GRALLOC_USAGE_HW_CAMERA_MASK)
+ == GRALLOC_USAGE_HW_CAMERA_ZSL)
+ grallocFormat = HAL_PIXEL_FORMAT_NV21_ZSL; //NV21 ZSL
+ else if(usage & GRALLOC_USAGE_HW_CAMERA_READ)
+ grallocFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP; //NV21
+ else if(usage & GRALLOC_USAGE_HW_CAMERA_WRITE)
+ grallocFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP; //NV21
+ else if(usage & GRALLOC_USAGE_HW_COMPOSER)
+ //XXX: If we still haven't set a format, default to RGBA8888
+ grallocFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+ //If no other usage flags are detected, default the
+ //flexible YUV format to NV21.
+ else if(format == HAL_PIXEL_FORMAT_YCbCr_420_888)
+ grallocFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+ }
+
+ getGrallocInformationFromFormat(grallocFormat, &bufferType);
+ size = getBufferSizeAndDimensions(w, h, grallocFormat, usage, alignedw,
+ alignedh);
+
+ if ((unsigned int)size <= 0)
+ return -EINVAL;
+ size = (bufferSize >= size)? bufferSize : size;
+
+ bool useFbMem = false;
+ char property[PROPERTY_VALUE_MAX];
+ if((usage & GRALLOC_USAGE_HW_FB) &&
+ (property_get("debug.gralloc.map_fb_memory", property, NULL) > 0) &&
+ (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+ (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+ useFbMem = true;
+ }
+
+ int err = 0;
+ if(useFbMem) {
+ err = gralloc_alloc_framebuffer(usage, pHandle);
+ } else {
+ err = gralloc_alloc_buffer(size, usage, pHandle, bufferType,
+ grallocFormat, alignedw, alignedh);
+ }
+
+ if (err < 0) {
+ return err;
+ }
+
+ *pStride = alignedw;
+ return 0;
+}
+
+int gpu_context_t::free_impl(private_handle_t const* hnd) {
+ private_module_t* m = reinterpret_cast<private_module_t*>(common.module);
+ if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
+ const unsigned int bufferSize = m->finfo.line_length * m->info.yres;
+ unsigned int index = (unsigned int) ((hnd->base - m->framebuffer->base)
+ / bufferSize);
+ m->bufferMask &= (uint32_t)~(1LU<<index);
+ } else {
+
+ terminateBuffer(&m->base, const_cast<private_handle_t*>(hnd));
+ IMemAlloc* memalloc = mAllocCtrl->getAllocator(hnd->flags);
+ int err = memalloc->free_buffer((void*)hnd->base, hnd->size,
+ hnd->offset, hnd->fd);
+ if(err)
+ return err;
+ // free the metadata space
+ unsigned int size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));
+ err = memalloc->free_buffer((void*)hnd->base_metadata,
+ size, hnd->offset_metadata,
+ hnd->fd_metadata);
+ if (err)
+ return err;
+ }
+ delete hnd;
+ return 0;
+}
+
+int gpu_context_t::gralloc_alloc(alloc_device_t* dev, int w, int h, int format,
+ int usage, buffer_handle_t* pHandle,
+ int* pStride)
+{
+ if (!dev) {
+ return -EINVAL;
+ }
+ gpu_context_t* gpu = reinterpret_cast<gpu_context_t*>(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)
+{
+ if (!dev) {
+ return -EINVAL;
+ }
+ gpu_context_t* gpu = reinterpret_cast<gpu_context_t*>(dev);
+ return gpu->alloc_impl(w, h, format, usage, pHandle, pStride, bufferSize);
+}
+
+
+int gpu_context_t::gralloc_free(alloc_device_t* dev,
+ buffer_handle_t handle)
+{
+ if (private_handle_t::validate(handle) < 0)
+ return -EINVAL;
+
+ private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(handle);
+ gpu_context_t* gpu = reinterpret_cast<gpu_context_t*>(dev);
+ return gpu->free_impl(hnd);
+}
+
+/*****************************************************************************/
+
+int gpu_context_t::gralloc_close(struct hw_device_t *dev)
+{
+ gpu_context_t* ctx = reinterpret_cast<gpu_context_t*>(dev);
+ if (ctx) {
+ /* TODO: keep a list of all buffer_handle_t created, and free them
+ * all here.
+ */
+ delete ctx;
+ }
+ return 0;
+}
+
diff --git a/msm8909/libgralloc/gpu.h b/msm8909/libgralloc/gpu.h
new file mode 100644
index 0000000..2248d30
--- /dev/null
+++ b/msm8909/libgralloc/gpu.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (c) 2011-2014, The Linux Foundation. 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 GRALLOC_GPU_H_
+#define GRALLOC_GPU_H_
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cutils/log.h>
+
+#include "gralloc_priv.h"
+#include "fb_priv.h"
+
+namespace gralloc {
+class IAllocController;
+class gpu_context_t : public alloc_device_t {
+ public:
+ gpu_context_t(const private_module_t* module,
+ IAllocController* alloc_ctrl);
+
+ int gralloc_alloc_buffer(unsigned int size, int usage,
+ buffer_handle_t* pHandle,
+ int bufferType, int format,
+ int width, int height);
+
+ 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,
+ unsigned int bufferSize = 0);
+
+ static int gralloc_alloc(alloc_device_t* dev, int w, int h,
+ int format, int usage,
+ buffer_handle_t* pHandle,
+ int* pStride);
+ int gralloc_alloc_framebuffer_locked(int usage,
+ buffer_handle_t* pHandle);
+
+ int gralloc_alloc_framebuffer(int usage,
+ buffer_handle_t* pHandle);
+
+ 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_close(struct hw_device_t *dev);
+
+ private:
+ IAllocController* mAllocCtrl;
+ void getGrallocInformationFromFormat(int inputFormat,
+ int *bufferType);
+};
+}
+#endif // GRALLOC_GPU_H
diff --git a/msm8909/libgralloc/gr.h b/msm8909/libgralloc/gr.h
new file mode 100644
index 0000000..1f902a5
--- /dev/null
+++ b/msm8909/libgralloc/gr.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (c) 2011-2012, The Linux Foundation. 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 GR_H_
+#define GR_H_
+
+#include <stdint.h>
+#include <limits.h>
+#include <sys/cdefs.h>
+#include <hardware/gralloc.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include <cutils/native_handle.h>
+#include <utils/Singleton.h>
+
+/*****************************************************************************/
+
+struct private_module_t;
+struct private_handle_t;
+
+inline unsigned int roundUpToPageSize(unsigned int x) {
+ return (x + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
+}
+
+template <class Type>
+inline Type ALIGN(Type x, Type align) {
+ return (x + align-1) & ~(align-1);
+}
+
+#define FALSE 0
+#define TRUE 1
+
+int mapFrameBufferLocked(struct private_module_t* module);
+int terminateBuffer(gralloc_module_t const* module, private_handle_t* hnd);
+unsigned int getBufferSizeAndDimensions(int width, int height, int format,
+ int usage, int& alignedw, int &alignedh);
+unsigned int getBufferSizeAndDimensions(int width, int height, int format,
+ int& alignedw, int &alignedh);
+
+
+// Attributes include aligned width, aligned height, tileEnabled and size of the buffer
+void getBufferAttributes(int width, int height, int format, int usage,
+ int& alignedw, int &alignedh,
+ int& tileEnabled, unsigned int &size);
+
+
+bool isMacroTileEnabled(int format, int usage);
+
+int decideBufferHandlingMechanism(int format, const char *compositionUsed,
+ 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
+int alloc_buffer(private_handle_t **pHnd, int w, int h, int format, int usage);
+void free_buffer(private_handle_t *hnd);
+int getYUVPlaneInfo(private_handle_t* pHnd, struct android_ycbcr* ycbcr);
+
+/*****************************************************************************/
+
+class Locker {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ public:
+ class Autolock {
+ Locker& locker;
+ public:
+ inline Autolock(Locker& locker) : locker(locker) { locker.lock(); }
+ inline ~Autolock() { locker.unlock(); }
+ };
+ inline Locker() {
+ pthread_mutex_init(&mutex, 0);
+ pthread_cond_init(&cond, 0);
+ }
+ inline ~Locker() {
+ pthread_mutex_destroy(&mutex);
+ pthread_cond_destroy(&cond);
+ }
+ inline void lock() { pthread_mutex_lock(&mutex); }
+ inline void wait() { pthread_cond_wait(&cond, &mutex); }
+ inline void unlock() { pthread_mutex_unlock(&mutex); }
+ inline void signal() { pthread_cond_signal(&cond); }
+};
+
+
+class AdrenoMemInfo : public android::Singleton <AdrenoMemInfo>
+{
+ public:
+ AdrenoMemInfo();
+
+ ~AdrenoMemInfo();
+
+ /*
+ * Function to compute the adreno aligned width and aligned height
+ * based on the width and format.
+ *
+ * @return aligned width, aligned height
+ */
+ void getAlignedWidthAndHeight(int width, int height, int format,
+ int tileEnabled, int& alignedw, int &alignedh);
+
+ /*
+ * Function to return whether GPU support MacroTile feature
+ *
+ * @return >0 : supported
+ * 0 : not supported
+ */
+ int isMacroTilingSupportedByGPU();
+
+ private:
+ // Pointer to the padding library.
+ void *libadreno_utils;
+
+ // link(s)to adreno surface padding library.
+ int (*LINK_adreno_compute_padding) (int width, int bpp,
+ int surface_tile_height,
+ int screen_tile_height,
+ int padding_threshold);
+
+ void (*LINK_adreno_compute_aligned_width_and_height) (int width,
+ int height,
+ int bpp,
+ int tile_mode,
+ int raster_mode,
+ int padding_threshold,
+ int *aligned_w,
+ int *aligned_h);
+
+ int (*LINK_adreno_isMacroTilingSupportedByGpu) (void);
+
+ void(*LINK_adreno_compute_compressedfmt_aligned_width_and_height)(
+ int width,
+ int height,
+ int format,
+ int tile_mode,
+ int raster_mode,
+ int padding_threshold,
+ int *aligned_w,
+ int *aligned_h,
+ int *bpp);
+
+ unsigned int (*LINK_adreno_get_gpu_pixel_alignment) ();
+};
+#endif /* GR_H_ */
diff --git a/msm8909/libgralloc/gralloc.cpp b/msm8909/libgralloc/gralloc.cpp
new file mode 100644
index 0000000..c0aa8cb
--- /dev/null
+++ b/msm8909/libgralloc/gralloc.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2008, The Android Open Source Project
+ * Copyright (c) 2011-2012, The Linux Foundation. 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 <unistd.h>
+#include <fcntl.h>
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <cutils/properties.h>
+
+#include "gr.h"
+#include "gpu.h"
+#include "memalloc.h"
+#include "alloc_controller.h"
+
+using namespace gralloc;
+
+int fb_device_open(const hw_module_t* module, const char* name,
+ hw_device_t** device);
+
+static int gralloc_device_open(const hw_module_t* module, const char* name,
+ 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);
+
+extern int gralloc_lock_ycbcr(gralloc_module_t const* module,
+ buffer_handle_t handle, int usage,
+ int l, int t, int w, int h,
+ struct android_ycbcr *ycbcr);
+
+extern int gralloc_unlock(gralloc_module_t const* module,
+ buffer_handle_t handle);
+
+extern int gralloc_register_buffer(gralloc_module_t const* module,
+ buffer_handle_t handle);
+
+extern int gralloc_unregister_buffer(gralloc_module_t const* module,
+ buffer_handle_t handle);
+
+extern int gralloc_perform(struct gralloc_module_t const* module,
+ int operation, ... );
+
+// HAL module methods
+static struct hw_module_methods_t gralloc_module_methods = {
+ 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,
+ lock_ycbcr: gralloc_lock_ycbcr,
+ },
+ framebuffer: 0,
+ fbFormat: 0,
+ flags: 0,
+ numBuffers: 0,
+ bufferMask: 0,
+ lock: PTHREAD_MUTEX_INITIALIZER,
+};
+
+// Open Gralloc device
+int gralloc_device_open(const hw_module_t* module, const char* name,
+ hw_device_t** device)
+{
+ int status = -EINVAL;
+ if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
+ const private_module_t* m = reinterpret_cast<const private_module_t*>(
+ module);
+ gpu_context_t *dev;
+ IAllocController* alloc_ctrl = IAllocController::getInstance();
+ dev = new gpu_context_t(m, alloc_ctrl);
+ if(!dev)
+ return status;
+
+ *device = &dev->common;
+ status = 0;
+ } else {
+ status = fb_device_open(module, name, device);
+ }
+ return status;
+}
diff --git a/msm8909/libgralloc/gralloc_priv.h b/msm8909/libgralloc/gralloc_priv.h
new file mode 100644
index 0000000..2d19517
--- /dev/null
+++ b/msm8909/libgralloc/gralloc_priv.h
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (c) 2011-2014, The Linux Foundation. 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 GRALLOC_PRIV_H_
+#define GRALLOC_PRIV_H_
+
+#include <stdint.h>
+#include <limits.h>
+#include <sys/cdefs.h>
+#include <hardware/gralloc.h>
+#include <pthread.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <cutils/native_handle.h>
+
+#include <cutils/log.h>
+
+#define ROUND_UP_PAGESIZE(x) ( (((unsigned long)(x)) + PAGE_SIZE-1) & \
+ (~(PAGE_SIZE-1)) )
+
+enum {
+ /* gralloc usage bits indicating the type
+ * of allocation that should be used */
+
+ /* SYSTEM heap comes from kernel vmalloc,
+ * can never be uncached, is not secured*/
+ GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP = GRALLOC_USAGE_PRIVATE_0,
+ /* SF heap is used for application buffers, is not secured */
+ GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP = GRALLOC_USAGE_PRIVATE_1,
+ /* IOMMU heap comes from manually allocated pages,
+ * can be cached/uncached, is not secured */
+ GRALLOC_USAGE_PRIVATE_IOMMU_HEAP = GRALLOC_USAGE_PRIVATE_2,
+ /* MM heap is a carveout heap for video, can be secured*/
+ GRALLOC_USAGE_PRIVATE_MM_HEAP = GRALLOC_USAGE_PRIVATE_3,
+ /* ADSP heap is a carveout heap, is not secured*/
+ GRALLOC_USAGE_PRIVATE_ADSP_HEAP = 0x01000000,
+
+ /* Set this for allocating uncached memory (using O_DSYNC)
+ * cannot be used with noncontiguous heaps */
+ GRALLOC_USAGE_PRIVATE_UNCACHED = 0x02000000,
+
+ /* Buffer content should be displayed on an primary display only */
+ GRALLOC_USAGE_PRIVATE_INTERNAL_ONLY = 0x04000000,
+
+ /* Buffer content should be displayed on an external display only */
+ GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY = 0x08000000,
+
+ /* This flag is set for WFD usecase */
+ GRALLOC_USAGE_PRIVATE_WFD = 0x00200000,
+
+ /* CAMERA heap is a carveout heap for camera, is not secured*/
+ GRALLOC_USAGE_PRIVATE_CAMERA_HEAP = 0x00400000,
+
+ /* This flag is used for SECURE display usecase */
+ GRALLOC_USAGE_PRIVATE_SECURE_DISPLAY = 0x00800000,
+};
+
+enum {
+ /* Gralloc perform enums
+ */
+ GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER = 1,
+ // This will be deprecated from latest graphics drivers. This is kept
+ // for those backward compatibility i.e., newer Display HAL + older graphics
+ // libraries
+ GRALLOC_MODULE_PERFORM_GET_STRIDE,
+ GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_FROM_HANDLE,
+ GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_AND_HEIGHT_FROM_HANDLE,
+ GRALLOC_MODULE_PERFORM_GET_ATTRIBUTES,
+ GRALLOC_MODULE_PERFORM_GET_COLOR_SPACE_FROM_HANDLE,
+ GRALLOC_MODULE_PERFORM_GET_YUV_PLANE_INFO,
+};
+
+#define GRALLOC_HEAP_MASK (GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP |\
+ GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP |\
+ GRALLOC_USAGE_PRIVATE_IOMMU_HEAP |\
+ GRALLOC_USAGE_PRIVATE_MM_HEAP |\
+ GRALLOC_USAGE_PRIVATE_ADSP_HEAP)
+
+#define INTERLACE_MASK 0x80
+#define S3D_FORMAT_MASK 0xFF000
+/*****************************************************************************/
+enum {
+ /* OEM specific HAL formats */
+ HAL_PIXEL_FORMAT_RGBA_5551 = 6,
+ HAL_PIXEL_FORMAT_RGBA_4444 = 7,
+ HAL_PIXEL_FORMAT_NV12_ENCODEABLE = 0x102,
+ HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS = 0x7FA30C04,
+ HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED = 0x7FA30C03,
+ HAL_PIXEL_FORMAT_YCbCr_420_SP = 0x109,
+ HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO = 0x7FA30C01,
+ 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_YCrCb_422_I = 0x111,
+ HAL_PIXEL_FORMAT_BGRX_8888 = 0x112,
+ HAL_PIXEL_FORMAT_NV21_ZSL = 0x113,
+ HAL_PIXEL_FORMAT_INTERLACE = 0x180,
+ //v4l2_fourcc('Y', 'U', 'Y', 'L'). 24 bpp YUYV 4:2:2 10 bit per component
+ HAL_PIXEL_FORMAT_YCbCr_422_I_10BIT = 0x4C595559,
+ //v4l2_fourcc('Y', 'B', 'W', 'C'). 10 bit per component. This compressed
+ //format reduces the memory access bandwidth
+ HAL_PIXEL_FORMAT_YCbCr_422_I_10BIT_COMPRESSED = 0x43574259,
+
+ //Khronos ASTC formats
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_4x4_KHR = 0x93B0,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x4_KHR = 0x93B1,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x5_KHR = 0x93B2,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x5_KHR = 0x93B3,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x6_KHR = 0x93B4,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x5_KHR = 0x93B5,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x6_KHR = 0x93B6,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x8_KHR = 0x93B7,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x5_KHR = 0x93B8,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x6_KHR = 0x93B9,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x8_KHR = 0x93BA,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x10_KHR = 0x93BB,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x10_KHR = 0x93BC,
+ HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x12_KHR = 0x93BD,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR = 0x93D0,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR = 0x93D1,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR = 0x93D2,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR = 0x93D3,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR = 0x93D4,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR = 0x93D5,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR = 0x93D6,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR = 0x93D7,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR = 0x93D8,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR = 0x93D9,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR = 0x93DA,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR = 0x93DB,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR = 0x93DC,
+ HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 0x93DD,
+};
+
+/* 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 {
+ BUFFER_TYPE_UI = 0,
+ BUFFER_TYPE_VIDEO
+};
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+struct private_handle_t : public native_handle {
+#else
+ 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_INTERNAL_ONLY = 0x00000040,
+ PRIV_FLAGS_NON_CPU_WRITER = 0x00000080,
+ PRIV_FLAGS_NONCONTIGUOUS_MEM = 0x00000100,
+ PRIV_FLAGS_CACHED = 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,
+ PRIV_FLAGS_VIDEO_ENCODER = 0x00010000,
+ PRIV_FLAGS_CAMERA_WRITE = 0x00020000,
+ PRIV_FLAGS_CAMERA_READ = 0x00040000,
+ PRIV_FLAGS_HW_COMPOSER = 0x00080000,
+ PRIV_FLAGS_HW_TEXTURE = 0x00100000,
+ PRIV_FLAGS_ITU_R_601 = 0x00200000,
+ PRIV_FLAGS_ITU_R_601_FR = 0x00400000,
+ PRIV_FLAGS_ITU_R_709 = 0x00800000,
+ PRIV_FLAGS_SECURE_DISPLAY = 0x01000000,
+ // Buffer is rendered in Tile Format
+ PRIV_FLAGS_TILE_RENDERED = 0x02000000,
+ // Buffer rendered using CPU/SW renderer
+ PRIV_FLAGS_CPU_RENDERED = 0x04000000
+ };
+
+ // file-descriptors
+ int fd;
+ int fd_metadata; // fd for the meta-data
+ // ints
+ int magic;
+ int flags;
+ unsigned int size;
+ unsigned int offset;
+ int bufferType;
+ uint64_t base __attribute__((aligned(8)));
+ unsigned int offset_metadata;
+ // The gpu address mapped into the mmu.
+ uint64_t gpuaddr __attribute__((aligned(8)));
+ int format;
+ int width;
+ int height;
+ uint64_t base_metadata __attribute__((aligned(8)));
+
+#ifdef __cplusplus
+ static const int sNumFds = 2;
+ static inline int sNumInts() {
+ return ((sizeof(private_handle_t) - sizeof(native_handle_t)) /
+ sizeof(int)) - sNumFds;
+ }
+ static const int sMagic = 'gmsm';
+
+ private_handle_t(int fd, unsigned int size, int flags, int bufferType,
+ int format, int width, int height, int eFd = -1,
+ unsigned int eOffset = 0, uint64_t eBase = 0) :
+ fd(fd), fd_metadata(eFd), magic(sMagic),
+ flags(flags), size(size), offset(0), bufferType(bufferType),
+ base(0), offset_metadata(eOffset), gpuaddr(0),
+ format(format), width(width), height(height),
+ base_metadata(eBase)
+ {
+ version = (int) sizeof(native_handle);
+ numInts = sNumInts();
+ numFds = sNumFds;
+ }
+ ~private_handle_t() {
+ magic = 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) ||
+ h->numInts != sNumInts() || h->numFds != sNumFds ||
+ hnd->magic != sMagic)
+ {
+ ALOGD("Invalid gralloc handle (at %p): "
+ "ver(%d/%zu) 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;
+ }
+
+ static private_handle_t* dynamicCast(const native_handle* in) {
+ if (validate(in) == 0) {
+ return (private_handle_t*) in;
+ }
+ return NULL;
+ }
+#endif
+ };
+
+#endif /* GRALLOC_PRIV_H_ */
diff --git a/msm8909/libgralloc/ionalloc.cpp b/msm8909/libgralloc/ionalloc.cpp
new file mode 100644
index 0000000..23e225d
--- /dev/null
+++ b/msm8909/libgralloc/ionalloc.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2011-2014, The Linux Foundation. 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 The Linux Foundation 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 DEBUG 0
+#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <cutils/log.h>
+#include <errno.h>
+#include <utils/Trace.h>
+#include "gralloc_priv.h"
+#include "ionalloc.h"
+
+using gralloc::IonAlloc;
+
+#define ION_DEVICE "/dev/ion"
+
+int IonAlloc::open_device()
+{
+ if(mIonFd == FD_INIT)
+ mIonFd = open(ION_DEVICE, O_RDONLY);
+
+ if(mIonFd < 0 ) {
+ ALOGE("%s: Failed to open ion device - %s",
+ __FUNCTION__, strerror(errno));
+ mIonFd = FD_INIT;
+ return -errno;
+ }
+ return 0;
+}
+
+void IonAlloc::close_device()
+{
+ if(mIonFd >= 0)
+ close(mIonFd);
+ mIonFd = FD_INIT;
+}
+
+int IonAlloc::alloc_buffer(alloc_data& data)
+{
+ ATRACE_CALL();
+ Locker::Autolock _l(mLock);
+ int err = 0;
+ struct ion_handle_data handle_data;
+ struct ion_fd_data fd_data;
+ struct ion_allocation_data ionAllocData;
+ void *base = 0;
+
+ ionAllocData.len = data.size;
+ ionAllocData.align = data.align;
+ ionAllocData.heap_id_mask = data.flags & ~ION_SECURE;
+ ionAllocData.flags = data.uncached ? 0 : ION_FLAG_CACHED;
+ // ToDo: replace usage of alloc data structure with
+ // ionallocdata structure.
+ if (data.flags & ION_SECURE)
+ ionAllocData.flags |= ION_SECURE;
+
+ err = open_device();
+ if (err)
+ return err;
+ if(ioctl(mIonFd, ION_IOC_ALLOC, &ionAllocData)) {
+ err = -errno;
+ ALOGE("ION_IOC_ALLOC failed with error - %s", strerror(errno));
+ return err;
+ }
+
+ fd_data.handle = ionAllocData.handle;
+ handle_data.handle = ionAllocData.handle;
+ if(ioctl(mIonFd, ION_IOC_MAP, &fd_data)) {
+ err = -errno;
+ ALOGE("%s: ION_IOC_MAP failed with error - %s",
+ __FUNCTION__, strerror(errno));
+ ioctl(mIonFd, ION_IOC_FREE, &handle_data);
+ return err;
+ }
+
+ if(!(data.flags & ION_SECURE)) {
+ base = mmap(0, ionAllocData.len, PROT_READ|PROT_WRITE,
+ MAP_SHARED, fd_data.fd, 0);
+ if(base == MAP_FAILED) {
+ err = -errno;
+ ALOGE("%s: Failed to map the allocated memory: %s",
+ __FUNCTION__, strerror(errno));
+ ioctl(mIonFd, ION_IOC_FREE, &handle_data);
+ return err;
+ }
+ }
+
+ data.base = base;
+ data.fd = fd_data.fd;
+ ioctl(mIonFd, ION_IOC_FREE, &handle_data);
+ ALOGD_IF(DEBUG, "ion: Allocated buffer base:%p size:%zu fd:%d",
+ data.base, ionAllocData.len, data.fd);
+ return 0;
+}
+
+
+int IonAlloc::free_buffer(void* base, unsigned int size, unsigned int offset,
+ int fd)
+{
+ ATRACE_CALL();
+ Locker::Autolock _l(mLock);
+ ALOGD_IF(DEBUG, "ion: Freeing buffer base:%p size:%u fd:%d",
+ base, size, fd);
+ int err = 0;
+ err = open_device();
+ if (err)
+ return err;
+
+ if(base)
+ err = unmap_buffer(base, size, offset);
+ close(fd);
+ return err;
+}
+
+int IonAlloc::map_buffer(void **pBase, unsigned int size, unsigned int offset,
+ int fd)
+{
+ ATRACE_CALL();
+ int err = 0;
+ void *base = 0;
+ // It is a (quirky) requirement of ION to have opened the
+ // ion fd in the process that is doing the mapping
+ err = open_device();
+ if (err)
+ return err;
+
+ base = mmap(0, size, PROT_READ| PROT_WRITE,
+ MAP_SHARED, fd, 0);
+ *pBase = base;
+ if(base == MAP_FAILED) {
+ err = -errno;
+ ALOGE("ion: Failed to map memory in the client: %s",
+ strerror(errno));
+ } else {
+ ALOGD_IF(DEBUG, "ion: Mapped buffer base:%p size:%u offset:%u fd:%d",
+ base, size, offset, fd);
+ }
+ return err;
+}
+
+int IonAlloc::unmap_buffer(void *base, unsigned int size,
+ unsigned int /*offset*/)
+{
+ ATRACE_CALL();
+ ALOGD_IF(DEBUG, "ion: Unmapping buffer base:%p size:%u", base, size);
+ int err = 0;
+ if(munmap(base, size)) {
+ err = -errno;
+ ALOGE("ion: Failed to unmap memory at %p : %s",
+ base, strerror(errno));
+ }
+ return err;
+
+}
+int IonAlloc::clean_buffer(void *base, unsigned int size, unsigned int offset,
+ int fd, int op)
+{
+ ATRACE_CALL();
+ ATRACE_INT("operation id", op);
+ struct ion_flush_data flush_data;
+ struct ion_fd_data fd_data;
+ struct ion_handle_data handle_data;
+ int err = 0;
+
+ err = open_device();
+ if (err)
+ return err;
+
+ fd_data.fd = fd;
+ if (ioctl(mIonFd, ION_IOC_IMPORT, &fd_data)) {
+ err = -errno;
+ ALOGE("%s: ION_IOC_IMPORT failed with error - %s",
+ __FUNCTION__, strerror(errno));
+ return err;
+ }
+
+ handle_data.handle = fd_data.handle;
+ flush_data.handle = fd_data.handle;
+ flush_data.vaddr = base;
+ // offset and length are unsigned int
+ flush_data.offset = offset;
+ flush_data.length = size;
+
+ struct ion_custom_data d;
+ switch(op) {
+ case CACHE_CLEAN:
+ d.cmd = ION_IOC_CLEAN_CACHES;
+ break;
+ case CACHE_INVALIDATE:
+ d.cmd = ION_IOC_INV_CACHES;
+ break;
+ case CACHE_CLEAN_AND_INVALIDATE:
+ default:
+ d.cmd = ION_IOC_CLEAN_INV_CACHES;
+ }
+
+ d.arg = (unsigned long int)&flush_data;
+
+ if(ioctl(mIonFd, ION_IOC_CUSTOM, &d)) {
+ err = -errno;
+ ALOGE("%s: ION_IOC_CLEAN_INV_CACHES failed with error - %s",
+
+ __FUNCTION__, strerror(errno));
+ ioctl(mIonFd, ION_IOC_FREE, &handle_data);
+ return err;
+ }
+ ioctl(mIonFd, ION_IOC_FREE, &handle_data);
+ return 0;
+}
+
diff --git a/msm8909/libgralloc/ionalloc.h b/msm8909/libgralloc/ionalloc.h
new file mode 100644
index 0000000..635bda5
--- /dev/null
+++ b/msm8909/libgralloc/ionalloc.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2011-2014, The Linux Foundation. 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 The Linux Foundation 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 GRALLOC_IONALLOC_H
+#define GRALLOC_IONALLOC_H
+
+#include <linux/msm_ion.h>
+#include "memalloc.h"
+#include "gr.h"
+
+namespace gralloc {
+
+class IonAlloc : public IMemAlloc {
+
+ public:
+ virtual int alloc_buffer(alloc_data& data);
+
+ virtual int free_buffer(void *base, unsigned int size,
+ unsigned int offset, int fd);
+
+ virtual int map_buffer(void **pBase, unsigned int size,
+ unsigned int offset, int fd);
+
+ virtual int unmap_buffer(void *base, unsigned int size,
+ unsigned int offset);
+
+ virtual int clean_buffer(void*base, unsigned int size,
+ unsigned int offset, int fd, int op);
+
+ IonAlloc() { mIonFd = FD_INIT; }
+
+ ~IonAlloc() { close_device(); }
+
+ private:
+ int mIonFd;
+
+ int open_device();
+
+ void close_device();
+
+ mutable Locker mLock;
+
+};
+
+}
+
+#endif /* GRALLOC_IONALLOC_H */
+
diff --git a/msm8909/libgralloc/mapper.cpp b/msm8909/libgralloc/mapper.cpp
new file mode 100644
index 0000000..147d148
--- /dev/null
+++ b/msm8909/libgralloc/mapper.cpp
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (c) 2011-2014, The Linux Foundation. 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 ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
+#include <limits.h>
+#include <errno.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <utils/Trace.h>
+
+#include <hardware/hardware.h>
+#include <hardware/gralloc.h>
+
+#include "gralloc_priv.h"
+#include "gr.h"
+#include "alloc_controller.h"
+#include "memalloc.h"
+#include <qdMetaData.h>
+
+
+using namespace gralloc;
+/*****************************************************************************/
+
+// Return the type of allocator -
+// these are used for mapping/unmapping
+static IMemAlloc* getAllocator(int flags)
+{
+ IMemAlloc* memalloc;
+ IAllocController* alloc_ctrl = IAllocController::getInstance();
+ memalloc = alloc_ctrl->getAllocator(flags);
+ return memalloc;
+}
+
+static int gralloc_map(gralloc_module_t const* module,
+ buffer_handle_t handle)
+{
+ ATRACE_CALL();
+ if(!module)
+ return -EINVAL;
+
+ private_handle_t* hnd = (private_handle_t*)handle;
+ unsigned int size = 0;
+ int err = 0;
+ IMemAlloc* memalloc = getAllocator(hnd->flags) ;
+ void *mappedAddress;
+ // Dont map FRAMEBUFFER and SECURE_BUFFERS
+ if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) &&
+ !(hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER)) {
+ size = hnd->size;
+ err = memalloc->map_buffer(&mappedAddress, size,
+ hnd->offset, hnd->fd);
+ if(err || mappedAddress == MAP_FAILED) {
+ ALOGE("Could not mmap handle %p, fd=%d (%s)",
+ handle, hnd->fd, strerror(errno));
+ hnd->base = 0;
+ return -errno;
+ }
+
+ hnd->base = uint64_t(mappedAddress) + hnd->offset;
+ }
+
+ //Allow mapping of metadata for all buffers and SECURE_BUFFER
+ if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
+ mappedAddress = MAP_FAILED;
+ size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));
+ err = memalloc->map_buffer(&mappedAddress, size,
+ hnd->offset_metadata, hnd->fd_metadata);
+ if(err || mappedAddress == MAP_FAILED) {
+ ALOGE("Could not mmap handle %p, fd=%d (%s)",
+ handle, hnd->fd_metadata, strerror(errno));
+ hnd->base_metadata = 0;
+ return -errno;
+ }
+ hnd->base_metadata = uint64_t(mappedAddress) + hnd->offset_metadata;
+ }
+ return 0;
+}
+
+static int gralloc_unmap(gralloc_module_t const* module,
+ buffer_handle_t handle)
+{
+ ATRACE_CALL();
+ if(!module)
+ return -EINVAL;
+
+ private_handle_t* hnd = (private_handle_t*)handle;
+ if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
+ int err = -EINVAL;
+ void* base = (void*)hnd->base;
+ unsigned int size = hnd->size;
+ IMemAlloc* memalloc = getAllocator(hnd->flags) ;
+ if(memalloc != NULL) {
+ err = memalloc->unmap_buffer(base, size, hnd->offset);
+ if (err) {
+ ALOGE("Could not unmap memory at address %p", base);
+ }
+ base = (void*)hnd->base_metadata;
+ size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));
+ err = memalloc->unmap_buffer(base, size, hnd->offset_metadata);
+ if (err) {
+ ALOGE("Could not unmap memory at address %p", base);
+ }
+ }
+ }
+ /* need to initialize the pointer to NULL otherwise unmapping for that
+ * buffer happens twice which leads to crash */
+ hnd->base = 0;
+ hnd->base_metadata = 0;
+ return 0;
+}
+
+/*****************************************************************************/
+
+static pthread_mutex_t sMapLock = PTHREAD_MUTEX_INITIALIZER;
+
+/*****************************************************************************/
+
+int gralloc_register_buffer(gralloc_module_t const* module,
+ buffer_handle_t handle)
+{
+ ATRACE_CALL();
+ if (!module || private_handle_t::validate(handle) < 0)
+ return -EINVAL;
+
+ // In this implementation, we don't need to do anything here
+
+ /* NOTE: we need to initialize the buffer as not mapped/not locked
+ * because it shouldn't when this function is called the first time
+ * in a new process. Ideally these flags shouldn't be part of the
+ * handle, but instead maintained in the kernel or at least
+ * out-of-line
+ */
+
+ private_handle_t* hnd = (private_handle_t*)handle;
+ hnd->base = 0;
+ hnd->base_metadata = 0;
+ int err = gralloc_map(module, handle);
+ if (err) {
+ ALOGE("%s: gralloc_map failed", __FUNCTION__);
+ return err;
+ }
+
+ return 0;
+}
+
+int gralloc_unregister_buffer(gralloc_module_t const* module,
+ buffer_handle_t handle)
+{
+ ATRACE_CALL();
+ if (!module || private_handle_t::validate(handle) < 0)
+ return -EINVAL;
+
+ /*
+ * If the buffer has been mapped during a lock operation, it's time
+ * to un-map it. It's an error to be here with a locked buffer.
+ * NOTE: the framebuffer is handled differently and is never unmapped.
+ */
+
+ private_handle_t* hnd = (private_handle_t*)handle;
+
+ if (hnd->base != 0) {
+ gralloc_unmap(module, handle);
+ }
+ hnd->base = 0;
+ hnd->base_metadata = 0;
+ return 0;
+}
+
+int terminateBuffer(gralloc_module_t const* module,
+ private_handle_t* hnd)
+{
+ ATRACE_CALL();
+ if(!module)
+ return -EINVAL;
+
+ /*
+ * If the buffer has been mapped during a lock operation, it's time
+ * to un-map it. It's an error to be here with a locked buffer.
+ */
+
+ if (hnd->base != 0) {
+ // this buffer was mapped, unmap it now
+ if (hnd->flags & (private_handle_t::PRIV_FLAGS_USES_PMEM |
+ private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP |
+ private_handle_t::PRIV_FLAGS_USES_ASHMEM |
+ private_handle_t::PRIV_FLAGS_USES_ION)) {
+ gralloc_unmap(module, hnd);
+ } else {
+ ALOGE("terminateBuffer: unmapping a non pmem/ashmem buffer flags = 0x%x",
+ hnd->flags);
+ gralloc_unmap(module, hnd);
+ }
+ }
+
+ return 0;
+}
+
+static int gralloc_map_and_invalidate (gralloc_module_t const* module,
+ buffer_handle_t handle, int usage)
+{
+ ATRACE_CALL();
+ if (!module || private_handle_t::validate(handle) < 0)
+ return -EINVAL;
+
+ int err = 0;
+ private_handle_t* hnd = (private_handle_t*)handle;
+ if (usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) {
+ if (hnd->base == 0) {
+ // we need to map for real
+ pthread_mutex_t* const lock = &sMapLock;
+ pthread_mutex_lock(lock);
+ err = gralloc_map(module, handle);
+ pthread_mutex_unlock(lock);
+ }
+ if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_ION and
+ hnd->flags & private_handle_t::PRIV_FLAGS_CACHED) {
+ //Invalidate if CPU reads in software and there are non-CPU
+ //writers. No need to do this for the metadata buffer as it is
+ //only read/written in software.
+ if ((usage & GRALLOC_USAGE_SW_READ_MASK) and
+ (hnd->flags & private_handle_t::PRIV_FLAGS_NON_CPU_WRITER))
+ {
+ IMemAlloc* memalloc = getAllocator(hnd->flags) ;
+ err = memalloc->clean_buffer((void*)hnd->base,
+ hnd->size, hnd->offset, hnd->fd,
+ CACHE_INVALIDATE);
+ }
+ //Mark the buffer to be flushed after CPU write.
+ if (usage & GRALLOC_USAGE_SW_WRITE_MASK) {
+ hnd->flags |= private_handle_t::PRIV_FLAGS_NEEDS_FLUSH;
+ }
+ }
+ }
+
+ return err;
+}
+
+int gralloc_lock(gralloc_module_t const* module,
+ buffer_handle_t handle, int usage,
+ int /*l*/, int /*t*/, int /*w*/, int /*h*/,
+ void** vaddr)
+{
+ ATRACE_CALL();
+ private_handle_t* hnd = (private_handle_t*)handle;
+ int err = gralloc_map_and_invalidate(module, handle, usage);
+ if(!err)
+ *vaddr = (void*)hnd->base;
+ return err;
+}
+
+int gralloc_lock_ycbcr(gralloc_module_t const* module,
+ buffer_handle_t handle, int usage,
+ int /*l*/, int /*t*/, int /*w*/, int /*h*/,
+ struct android_ycbcr *ycbcr)
+{
+ ATRACE_CALL();
+ private_handle_t* hnd = (private_handle_t*)handle;
+ int err = gralloc_map_and_invalidate(module, handle, usage);
+ if(!err)
+ err = getYUVPlaneInfo(hnd, ycbcr);
+ return err;
+}
+
+int gralloc_unlock(gralloc_module_t const* module,
+ buffer_handle_t handle)
+{
+ ATRACE_CALL();
+ if (!module || private_handle_t::validate(handle) < 0)
+ return -EINVAL;
+
+ int err = 0;
+ private_handle_t* hnd = (private_handle_t*)handle;
+
+ IMemAlloc* memalloc = getAllocator(hnd->flags);
+ if (hnd->flags & private_handle_t::PRIV_FLAGS_NEEDS_FLUSH) {
+ err = memalloc->clean_buffer((void*)hnd->base,
+ hnd->size, hnd->offset, hnd->fd,
+ CACHE_CLEAN);
+ hnd->flags &= ~private_handle_t::PRIV_FLAGS_NEEDS_FLUSH;
+ }
+
+ return err;
+}
+
+/*****************************************************************************/
+
+int gralloc_perform(struct gralloc_module_t const* module,
+ int operation, ... )
+{
+ int res = -EINVAL;
+ va_list args;
+ if(!module)
+ return res;
+
+ va_start(args, operation);
+ switch (operation) {
+ case GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER:
+ {
+ int fd = va_arg(args, int);
+ unsigned int size = va_arg(args, unsigned int);
+ unsigned int offset = va_arg(args, unsigned int);
+ void* base = va_arg(args, void*);
+ int width = va_arg(args, int);
+ int height = va_arg(args, int);
+ int format = va_arg(args, int);
+
+ native_handle_t** handle = va_arg(args, native_handle_t**);
+ private_handle_t* hnd = (private_handle_t*)native_handle_create(
+ private_handle_t::sNumFds, private_handle_t::sNumInts());
+ if (hnd) {
+ hnd->magic = private_handle_t::sMagic;
+ hnd->fd = fd;
+ hnd->flags = private_handle_t::PRIV_FLAGS_USES_ION;
+ hnd->size = size;
+ hnd->offset = offset;
+ hnd->base = uint64_t(base) + offset;
+ hnd->gpuaddr = 0;
+ hnd->width = width;
+ hnd->height = height;
+ hnd->format = format;
+ *handle = (native_handle_t *)hnd;
+ res = 0;
+ }
+ break;
+
+ }
+ case GRALLOC_MODULE_PERFORM_GET_STRIDE:
+ {
+ int width = va_arg(args, int);
+ int format = va_arg(args, int);
+ int *stride = va_arg(args, int *);
+ int alignedw = 0, alignedh = 0;
+ AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width,
+ 0, format, false, alignedw, alignedh);
+ *stride = alignedw;
+ res = 0;
+ } break;
+
+ case GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_FROM_HANDLE:
+ {
+ private_handle_t* hnd = va_arg(args, private_handle_t*);
+ int *stride = va_arg(args, int *);
+ if (private_handle_t::validate(hnd)) {
+ return res;
+ }
+ MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+ if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) {
+ *stride = metadata->bufferDim.sliceWidth;
+ } else {
+ *stride = hnd->width;
+ }
+ res = 0;
+ } break;
+
+ case GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_AND_HEIGHT_FROM_HANDLE:
+ {
+ private_handle_t* hnd = va_arg(args, private_handle_t*);
+ int *stride = va_arg(args, int *);
+ int *height = va_arg(args, int *);
+ if (private_handle_t::validate(hnd)) {
+ return res;
+ }
+ MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+ if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) {
+ *stride = metadata->bufferDim.sliceWidth;
+ *height = metadata->bufferDim.sliceHeight;
+ } else {
+ *stride = hnd->width;
+ *height = hnd->height;
+ }
+ res = 0;
+ } break;
+
+ case GRALLOC_MODULE_PERFORM_GET_ATTRIBUTES:
+ {
+ int width = va_arg(args, int);
+ int height = va_arg(args, int);
+ int format = va_arg(args, int);
+ int usage = va_arg(args, int);
+ int *alignedWidth = va_arg(args, int *);
+ int *alignedHeight = va_arg(args, int *);
+ int *tileEnabled = va_arg(args,int *);
+ *tileEnabled = isMacroTileEnabled(format, usage);
+ AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width,
+ height, format, *tileEnabled, *alignedWidth,
+ *alignedHeight);
+ res = 0;
+ } break;
+
+ case GRALLOC_MODULE_PERFORM_GET_COLOR_SPACE_FROM_HANDLE:
+ {
+ private_handle_t* hnd = va_arg(args, private_handle_t*);
+ int *color_space = va_arg(args, int *);
+ if (private_handle_t::validate(hnd)) {
+ return res;
+ }
+ MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+ if(metadata && metadata->operation & UPDATE_COLOR_SPACE) {
+ *color_space = metadata->colorSpace;
+ res = 0;
+ }
+ } break;
+ case GRALLOC_MODULE_PERFORM_GET_YUV_PLANE_INFO:
+ {
+ private_handle_t* hnd = va_arg(args, private_handle_t*);
+ android_ycbcr* ycbcr = va_arg(args, struct android_ycbcr *);
+ if (!private_handle_t::validate(hnd)) {
+ res = getYUVPlaneInfo(hnd, ycbcr);
+ }
+ } break;
+
+ default:
+ break;
+ }
+ va_end(args);
+ return res;
+}
diff --git a/msm8909/libgralloc/memalloc.h b/msm8909/libgralloc/memalloc.h
new file mode 100644
index 0000000..2bc1ddf
--- /dev/null
+++ b/msm8909/libgralloc/memalloc.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2011-2014, The Linux Foundation. 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 The Linux Foundation 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 GRALLOC_MEMALLOC_H
+#define GRALLOC_MEMALLOC_H
+
+#include <stdlib.h>
+
+namespace gralloc {
+
+enum {
+ CACHE_CLEAN = 0x1,
+ CACHE_INVALIDATE,
+ CACHE_CLEAN_AND_INVALIDATE,
+};
+
+struct alloc_data {
+ void *base;
+ int fd;
+ unsigned int offset;
+ unsigned int size;
+ unsigned int align;
+ uintptr_t pHandle;
+ bool uncached;
+ unsigned int flags;
+ int allocType;
+};
+
+class IMemAlloc {
+
+ 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, unsigned int size,
+ unsigned int offset, int fd) = 0;
+
+ // Map buffer
+ virtual int map_buffer(void **pBase, unsigned int size,
+ unsigned int offset, int fd) = 0;
+
+ // Unmap buffer
+ virtual int unmap_buffer(void *base, unsigned int size,
+ unsigned int offset) = 0;
+
+ // Clean and invalidate
+ virtual int clean_buffer(void *base, unsigned int size,
+ unsigned int offset, int fd, int op) = 0;
+
+ // Destructor
+ virtual ~IMemAlloc() {};
+
+ enum {
+ FD_INIT = -1,
+ };
+
+};
+
+} // end gralloc namespace
+#endif // GRALLOC_MEMALLOC_H
diff --git a/msm8909/libhdmi/Android.mk b/msm8909/libhdmi/Android.mk
new file mode 100644
index 0000000..89ba4a9
--- /dev/null
+++ b/msm8909/libhdmi/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH := $(call my-dir)
+include $(LOCAL_PATH)/../common.mk
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libhdmi
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
+LOCAL_SHARED_LIBRARIES := $(common_libs) liboverlay libqdutils
+LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdhdmi\"
+LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
+LOCAL_SRC_FILES := hdmi.cpp
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/msm8909/libhdmi/hdmi.cpp b/msm8909/libhdmi/hdmi.cpp
new file mode 100644
index 0000000..4fb7cfa
--- /dev/null
+++ b/msm8909/libhdmi/hdmi.cpp
@@ -0,0 +1,699 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are
+ * retained for attribution purposes only.
+ *
+ * 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 DEBUG 0
+#include <fcntl.h>
+#include <linux/msm_mdp.h>
+#include <video/msm_hdmi_modes.h>
+#include <linux/fb.h>
+#include <sys/ioctl.h>
+#include <cutils/properties.h>
+#include "hwc_utils.h"
+#include "hdmi.h"
+#include "overlayUtils.h"
+#include "overlay.h"
+#include "qd_utils.h"
+
+using namespace android;
+using namespace qdutils;
+
+namespace qhwc {
+#define UNKNOWN_STRING "unknown"
+#define SPD_NAME_LENGTH 16
+
+/* The array gEDIDData contains a list of modes currently
+ * supported by HDMI and display, and modes that are not
+ * supported i.e. interlaced modes.
+
+ * In order to add support for a new mode, the mode must be
+ * appended to the end of the array.
+ *
+ * Each new entry must contain the following:
+ * -Mode: a video format defined in msm_hdmi_modes.h
+ * -Width: x resolution for the mode
+ * -Height: y resolution for the mode
+ * -FPS: the frame rate for the mode
+ * -Mode Order: the priority for the new mode that is used when determining
+ * the best mode when the HDMI display is connected.
+ */
+EDIDData gEDIDData [] = {
+ EDIDData(HDMI_VFRMT_1440x480i60_4_3, 1440, 480, 60, 1),
+ EDIDData(HDMI_VFRMT_1440x480i60_16_9, 1440, 480, 60, 2),
+ EDIDData(HDMI_VFRMT_1440x576i50_4_3, 1440, 576, 50, 3),
+ EDIDData(HDMI_VFRMT_1440x576i50_16_9, 1440, 576, 50, 4),
+ EDIDData(HDMI_VFRMT_1920x1080i60_16_9, 1920, 1080, 60, 5),
+ EDIDData(HDMI_VFRMT_640x480p60_4_3, 640, 480, 60, 6),
+ EDIDData(HDMI_VFRMT_720x480p60_4_3, 720, 480, 60, 7),
+ EDIDData(HDMI_VFRMT_720x480p60_16_9, 720, 480, 60, 8),
+ EDIDData(HDMI_VFRMT_720x576p50_4_3, 720, 576, 50, 9),
+ EDIDData(HDMI_VFRMT_720x576p50_16_9, 720, 576, 50, 10),
+ EDIDData(HDMI_VFRMT_800x600p60_4_3, 800, 600, 60, 11),
+ EDIDData(HDMI_VFRMT_848x480p60_16_9, 848, 480, 60, 12),
+ EDIDData(HDMI_VFRMT_1024x768p60_4_3, 1024, 768, 60, 13),
+ EDIDData(HDMI_VFRMT_1280x1024p60_5_4, 1280, 1024, 60, 14),
+ EDIDData(HDMI_VFRMT_1280x720p50_16_9, 1280, 720, 50, 15),
+ EDIDData(HDMI_VFRMT_1280x720p60_16_9, 1280, 720, 60, 16),
+ EDIDData(HDMI_VFRMT_1280x800p60_16_10, 1280, 800, 60, 17),
+ EDIDData(HDMI_VFRMT_1280x960p60_4_3, 1280, 960, 60, 18),
+ EDIDData(HDMI_VFRMT_1360x768p60_16_9, 1360, 768, 60, 19),
+ EDIDData(HDMI_VFRMT_1366x768p60_16_10, 1366, 768, 60, 20),
+ EDIDData(HDMI_VFRMT_1440x900p60_16_10, 1440, 900, 60, 21),
+ EDIDData(HDMI_VFRMT_1400x1050p60_4_3, 1400, 1050, 60, 22),
+ EDIDData(HDMI_VFRMT_1680x1050p60_16_10, 1680, 1050, 60, 23),
+ EDIDData(HDMI_VFRMT_1600x1200p60_4_3, 1600, 1200, 60, 24),
+ EDIDData(HDMI_VFRMT_1920x1080p24_16_9, 1920, 1080, 24, 25),
+ EDIDData(HDMI_VFRMT_1920x1080p25_16_9, 1920, 1080, 25, 26),
+ EDIDData(HDMI_VFRMT_1920x1080p30_16_9, 1920, 1080, 30, 27),
+ EDIDData(HDMI_VFRMT_1920x1080p50_16_9, 1920, 1080, 50, 28),
+ EDIDData(HDMI_VFRMT_1920x1080p60_16_9, 1920, 1080, 60, 29),
+ EDIDData(HDMI_VFRMT_1920x1200p60_16_10, 1920, 1200, 60, 30),
+ EDIDData(HDMI_VFRMT_2560x1600p60_16_9, 2560, 1600, 60, 31),
+ EDIDData(HDMI_VFRMT_3840x2160p24_16_9, 3840, 2160, 24, 32),
+ EDIDData(HDMI_VFRMT_3840x2160p25_16_9, 3840, 2160, 25, 33),
+ EDIDData(HDMI_VFRMT_3840x2160p30_16_9, 3840, 2160, 30, 34),
+ EDIDData(HDMI_VFRMT_4096x2160p24_16_9, 4096, 2160, 24, 35),
+};
+
+// Number of modes in gEDIDData
+const int gEDIDCount = (sizeof(gEDIDData)/sizeof(gEDIDData)[0]);
+
+int HDMIDisplay::configure() {
+ if(!openFrameBuffer()) {
+ ALOGE("%s: Failed to open FB: %d", __FUNCTION__, mFbNum);
+ return -1;
+ }
+ readCEUnderscanInfo();
+ readResolution();
+ // TODO: Move this to activate
+ /* Used for changing the resolution
+ * getUserMode will get the preferred
+ * mode set thru adb shell */
+ mCurrentMode = getUserMode();
+ if (mCurrentMode == -1) {
+ //Get the best mode and set
+ mCurrentMode = getBestMode();
+ }
+ setAttributes();
+ // set system property
+ property_set("hw.hdmiON", "1");
+
+ // Read the system property to determine if downscale feature is enabled.
+ char value[PROPERTY_VALUE_MAX];
+ mMDPDownscaleEnabled = false;
+ if(property_get("sys.hwc.mdp_downscale_enabled", value, "false")
+ && !strcmp(value, "true")) {
+ mMDPDownscaleEnabled = true;
+ }
+ return 0;
+}
+
+void HDMIDisplay::getAttributes(uint32_t& width, uint32_t& height) {
+ uint32_t fps = 0;
+ getAttrForMode(width, height, fps);
+}
+
+int HDMIDisplay::teardown() {
+ closeFrameBuffer();
+ resetInfo();
+ // unset system property
+ property_set("hw.hdmiON", "0");
+ return 0;
+}
+
+HDMIDisplay::HDMIDisplay():mFd(-1),
+ mCurrentMode(-1), mModeCount(0), mPrimaryWidth(0), mPrimaryHeight(0),
+ mUnderscanSupported(false)
+{
+ memset(&mVInfo, 0, sizeof(mVInfo));
+
+ mDisplayId = HWC_DISPLAY_EXTERNAL;
+ // Update the display if HDMI is connected as primary
+ if (isHDMIPrimaryDisplay()) {
+ mDisplayId = HWC_DISPLAY_PRIMARY;
+ }
+
+ mFbNum = overlay::Overlay::getInstance()->getFbForDpy(mDisplayId);
+ // disable HPD at start, it will be enabled later
+ // when the display powers on
+ // This helps for framework reboot or adb shell stop/start
+ writeHPDOption(0);
+
+ // for HDMI - retreive all the modes supported by the driver
+ if(mFbNum != -1) {
+ supported_video_mode_lut =
+ new msm_hdmi_mode_timing_info[HDMI_VFRMT_MAX];
+ // Populate the mode table for supported modes
+ MSM_HDMI_MODES_INIT_TIMINGS(supported_video_mode_lut);
+ MSM_HDMI_MODES_SET_SUPP_TIMINGS(supported_video_mode_lut,
+ MSM_HDMI_MODES_ALL);
+ // Update the Source Product Information
+ // Vendor Name
+ setSPDInfo("vendor_name", "ro.product.manufacturer");
+ // Product Description
+ setSPDInfo("product_description", "ro.product.name");
+ }
+
+ ALOGD_IF(DEBUG, "%s mDisplayId(%d) mFbNum(%d)",
+ __FUNCTION__, mDisplayId, mFbNum);
+}
+/* gets the product manufacturer and product name and writes it
+ * to the sysfs node, so that the driver can get that information
+ * Used to show QCOM 8974 instead of Input 1 for example
+ */
+void HDMIDisplay::setSPDInfo(const char* node, const char* property) {
+ char info[PROPERTY_VALUE_MAX];
+ ssize_t err = -1;
+ int spdFile = openDeviceNode(node, O_RDWR);
+ if (spdFile >= 0) {
+ memset(info, 0, sizeof(info));
+ property_get(property, info, UNKNOWN_STRING);
+ ALOGD_IF(DEBUG, "In %s: %s = %s",
+ __FUNCTION__, property, info);
+ if (strncmp(info, UNKNOWN_STRING, SPD_NAME_LENGTH)) {
+ err = write(spdFile, info, strlen(info));
+ if (err <= 0) {
+ ALOGE("%s: file write failed for '%s'"
+ "err no = %d", __FUNCTION__, node, errno);
+ }
+ } else {
+ ALOGD_IF(DEBUG, "%s: property_get failed for SPD %s",
+ __FUNCTION__, node);
+ }
+ close(spdFile);
+ }
+}
+
+void HDMIDisplay::setHPD(uint32_t value) {
+ ALOGD_IF(DEBUG,"HPD enabled=%d", value);
+ writeHPDOption(value);
+}
+
+void HDMIDisplay::setActionSafeDimension(int w, int h) {
+ ALOGD_IF(DEBUG,"ActionSafe w=%d h=%d", w, h);
+ char actionsafeWidth[PROPERTY_VALUE_MAX];
+ char actionsafeHeight[PROPERTY_VALUE_MAX];
+ snprintf(actionsafeWidth, sizeof(actionsafeWidth), "%d", w);
+ property_set("persist.sys.actionsafe.width", actionsafeWidth);
+ snprintf(actionsafeHeight, sizeof(actionsafeHeight), "%d", h);
+ property_set("persist.sys.actionsafe.height", actionsafeHeight);
+}
+
+int HDMIDisplay::getModeCount() const {
+ ALOGD_IF(DEBUG,"HPD mModeCount=%d", mModeCount);
+ return mModeCount;
+}
+
+void HDMIDisplay::readCEUnderscanInfo()
+{
+ int hdmiScanInfoFile = -1;
+ ssize_t len = -1;
+ char scanInfo[17];
+ char *ce_info_str = NULL;
+ char *save_ptr;
+ const char token[] = ", \n";
+ int ce_info = -1;
+
+ memset(scanInfo, 0, sizeof(scanInfo));
+ hdmiScanInfoFile = openDeviceNode("scan_info", O_RDONLY);
+ if (hdmiScanInfoFile < 0) {
+ return;
+ } else {
+ len = read(hdmiScanInfoFile, scanInfo, sizeof(scanInfo)-1);
+ ALOGD("%s: Scan Info string: %s length = %zu",
+ __FUNCTION__, scanInfo, len);
+ if (len <= 0) {
+ close(hdmiScanInfoFile);
+ ALOGE("%s: Scan Info file empty", __FUNCTION__);
+ return;
+ }
+ scanInfo[len] = '\0'; /* null terminate the string */
+ close(hdmiScanInfoFile);
+ }
+
+ /*
+ * The scan_info contains the three fields
+ * PT - preferred video format
+ * IT - video format
+ * CE video format - containing the underscan support information
+ */
+
+ /* PT */
+ ce_info_str = strtok_r(scanInfo, token, &save_ptr);
+ if (ce_info_str) {
+ /* IT */
+ ce_info_str = strtok_r(NULL, token, &save_ptr);
+ if (ce_info_str) {
+ /* CE */
+ ce_info_str = strtok_r(NULL, token, &save_ptr);
+ if (ce_info_str)
+ ce_info = atoi(ce_info_str);
+ }
+ }
+
+ if (ce_info_str) {
+ // ce_info contains the underscan information
+ if (ce_info == HDMI_SCAN_ALWAYS_UNDERSCANED ||
+ ce_info == HDMI_SCAN_BOTH_SUPPORTED)
+ // if TV supported underscan, then driver will always underscan
+ // hence no need to apply action safe rectangle
+ mUnderscanSupported = true;
+ } else {
+ ALOGE("%s: scan_info string error", __FUNCTION__);
+ }
+
+ // Store underscan support info in a system property
+ const char* prop = (mUnderscanSupported) ? "1" : "0";
+ property_set("hw.underscan_supported", prop);
+ return;
+}
+
+HDMIDisplay::~HDMIDisplay()
+{
+ delete [] supported_video_mode_lut;
+ closeFrameBuffer();
+}
+
+/*
+ * sets the fb_var_screeninfo from the hdmi_mode_timing_info
+ */
+void setDisplayTiming(struct fb_var_screeninfo &info,
+ const msm_hdmi_mode_timing_info* mode)
+{
+ info.reserved[0] = 0;
+ info.reserved[1] = 0;
+ info.reserved[2] = 0;
+#ifndef FB_METADATA_VIDEO_INFO_CODE_SUPPORT
+ info.reserved[3] = (info.reserved[3] & 0xFFFF) |
+ (mode->video_format << 16);
+#endif
+ info.xoffset = 0;
+ info.yoffset = 0;
+ info.xres = mode->active_h;
+ info.yres = mode->active_v;
+
+ info.pixclock = (mode->pixel_freq)*1000;
+ info.vmode = mode->interlaced ?
+ FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;
+
+ info.right_margin = mode->front_porch_h;
+ info.hsync_len = mode->pulse_width_h;
+ info.left_margin = mode->back_porch_h;
+ info.lower_margin = mode->front_porch_v;
+ info.vsync_len = mode->pulse_width_v;
+ info.upper_margin = mode->back_porch_v;
+}
+
+int HDMIDisplay::parseResolution(char* edidStr)
+{
+ char delim = ',';
+ int count = 0;
+ char *start, *end;
+ // EDIDs are string delimited by ','
+ // Ex: 16,4,5,3,32,34,1
+ // Parse this string to get mode(int)
+ start = (char*) edidStr;
+ end = &delim;
+ while(*end == delim) {
+ mEDIDModes[count] = (int) strtol(start, &end, 10);
+ start = end+1;
+ count++;
+ }
+ ALOGD_IF(DEBUG, "In %s: count = %d", __FUNCTION__, count);
+ for (int i = 0; i < count; i++)
+ ALOGD_IF(DEBUG, "Mode[%d] = %d", i, mEDIDModes[i]);
+ return count;
+}
+
+bool HDMIDisplay::readResolution()
+{
+ ssize_t len = -1;
+ char edidStr[128] = {'\0'};
+
+ int hdmiEDIDFile = openDeviceNode("edid_modes", O_RDONLY);
+ if (hdmiEDIDFile < 0) {
+ return false;
+ } else {
+ len = read(hdmiEDIDFile, edidStr, sizeof(edidStr)-1);
+ ALOGD_IF(DEBUG, "%s: EDID string: %s length = %zu",
+ __FUNCTION__, edidStr, len);
+ if (len <= 0) {
+ ALOGE("%s: edid_modes file empty", __FUNCTION__);
+ edidStr[0] = '\0';
+ }
+ else {
+ while (len > 1 && isspace(edidStr[len-1])) {
+ --len;
+ }
+ edidStr[len] = '\0';
+ }
+ close(hdmiEDIDFile);
+ }
+ if(len > 0) {
+ // Get EDID modes from the EDID strings
+ mModeCount = parseResolution(edidStr);
+ ALOGD_IF(DEBUG, "%s: mModeCount = %d", __FUNCTION__,
+ mModeCount);
+ }
+
+ return (len > 0);
+}
+
+bool HDMIDisplay::openFrameBuffer()
+{
+ if (mFd == -1) {
+ char strDevPath[MAX_SYSFS_FILE_PATH];
+ snprintf(strDevPath, MAX_SYSFS_FILE_PATH, "/dev/graphics/fb%d", mFbNum);
+ mFd = open(strDevPath, O_RDWR);
+ if (mFd < 0)
+ ALOGE("%s: %s is not available", __FUNCTION__, strDevPath);
+ }
+ return (mFd > 0);
+}
+
+bool HDMIDisplay::closeFrameBuffer()
+{
+ int ret = 0;
+ if(mFd >= 0) {
+ ret = close(mFd);
+ mFd = -1;
+ }
+ return (ret == 0);
+}
+
+// clears the vinfo, edid, best modes
+void HDMIDisplay::resetInfo()
+{
+ memset(&mVInfo, 0, sizeof(mVInfo));
+ memset(mEDIDModes, 0, sizeof(mEDIDModes));
+ mModeCount = 0;
+ mCurrentMode = -1;
+ mUnderscanSupported = false;
+ mXres = 0;
+ mYres = 0;
+ mVsyncPeriod = 0;
+ mMDPScalingMode = false;
+ // Reset the underscan supported system property
+ const char* prop = "0";
+ property_set("hw.underscan_supported", prop);
+}
+
+int HDMIDisplay::getModeOrder(int mode)
+{
+ for (int dataIndex = 0; dataIndex < gEDIDCount; dataIndex++) {
+ if (gEDIDData[dataIndex].mMode == mode) {
+ return gEDIDData[dataIndex].mModeOrder;
+ }
+ }
+ ALOGE("%s Mode not found: %d", __FUNCTION__, mode);
+ return -1;
+}
+
+/// Returns the user mode set(if any) using adb shell
+int HDMIDisplay::getUserMode() {
+ /* Based on the property set the resolution */
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get("hw.hdmi.resolution", property_value, "-1");
+ int mode = atoi(property_value);
+ // We dont support interlaced modes
+ if(isValidMode(mode) && !isInterlacedMode(mode)) {
+ ALOGD_IF(DEBUG, "%s: setting the HDMI mode = %d", __FUNCTION__, mode);
+ return mode;
+ }
+ return -1;
+}
+
+// Get the best mode for the current HD TV
+int HDMIDisplay::getBestMode() {
+ int bestOrder = 0;
+ int bestMode = HDMI_VFRMT_640x480p60_4_3;
+ // for all the edid read, get the best mode
+ for(int i = 0; i < mModeCount; i++) {
+ int mode = mEDIDModes[i];
+ int order = getModeOrder(mode);
+ if (order > bestOrder) {
+ bestOrder = order;
+ bestMode = mode;
+ }
+ }
+ return bestMode;
+}
+
+inline bool HDMIDisplay::isValidMode(int ID)
+{
+ bool valid = false;
+ for (int i = 0; i < mModeCount; i++) {
+ if(ID == mEDIDModes[i]) {
+ valid = true;
+ break;
+ }
+ }
+ return valid;
+}
+
+// returns true if the mode(ID) is interlaced mode format
+bool HDMIDisplay::isInterlacedMode(int ID) {
+ bool interlaced = false;
+ switch(ID) {
+ case HDMI_VFRMT_1440x480i60_4_3:
+ case HDMI_VFRMT_1440x480i60_16_9:
+ case HDMI_VFRMT_1440x576i50_4_3:
+ case HDMI_VFRMT_1440x576i50_16_9:
+ case HDMI_VFRMT_1920x1080i60_16_9:
+ interlaced = true;
+ break;
+ default:
+ interlaced = false;
+ break;
+ }
+ return interlaced;
+}
+
+// Does a put_vscreen info on the HDMI interface which will update
+// the configuration (resolution, timing info) to match mCurrentMode
+void HDMIDisplay::activateDisplay()
+{
+ int ret = 0;
+ ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo);
+ if(ret < 0) {
+ ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__,
+ strerror(errno));
+ }
+ ALOGD_IF(DEBUG, "%s: GET Info<ID=%d %dx%d (%d,%d,%d),"
+ "(%d,%d,%d) %dMHz>", __FUNCTION__,
+ mVInfo.reserved[3], mVInfo.xres, mVInfo.yres,
+ mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin,
+ mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin,
+ mVInfo.pixclock/1000/1000);
+
+ const struct msm_hdmi_mode_timing_info *mode =
+ &supported_video_mode_lut[0];
+ for (unsigned int i = 0; i < HDMI_VFRMT_MAX; ++i) {
+ const struct msm_hdmi_mode_timing_info *cur =
+ &supported_video_mode_lut[i];
+ if (cur->video_format == (uint32_t)mCurrentMode) {
+ mode = cur;
+ break;
+ }
+ }
+ setDisplayTiming(mVInfo, mode);
+ ALOGD_IF(DEBUG, "%s: SET Info<ID=%d => Info<ID=%d %dx %d"
+ "(%d,%d,%d), (%d,%d,%d) %dMHz>", __FUNCTION__, mCurrentMode,
+ mode->video_format, mVInfo.xres, mVInfo.yres,
+ mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin,
+ mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin,
+ mVInfo.pixclock/1000/1000);
+#ifdef FB_METADATA_VIDEO_INFO_CODE_SUPPORT
+ struct msmfb_metadata metadata;
+ memset(&metadata, 0 , sizeof(metadata));
+ metadata.op = metadata_op_vic;
+ metadata.data.video_info_code = mode->video_format;
+ if (ioctl(mFd, MSMFB_METADATA_SET, &metadata) == -1) {
+ ALOGD("In %s: MSMFB_METADATA_SET failed Err Str = %s",
+ __FUNCTION__, strerror(errno));
+ }
+#endif
+ mVInfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE;
+ ret = ioctl(mFd, FBIOPUT_VSCREENINFO, &mVInfo);
+ if(ret < 0) {
+ ALOGD("In %s: FBIOPUT_VSCREENINFO failed Err Str = %s",
+ __FUNCTION__, strerror(errno));
+ }
+}
+
+bool HDMIDisplay::writeHPDOption(int userOption) const
+{
+ bool ret = true;
+ if(mFbNum != -1) {
+ int hdmiHPDFile = openDeviceNode("hpd", O_RDWR);
+ if (hdmiHPDFile >= 0) {
+ ssize_t err = -1;
+ ALOGD_IF(DEBUG, "%s: option = %d",
+ __FUNCTION__, userOption);
+ if(userOption)
+ err = write(hdmiHPDFile, "1", 2);
+ else
+ err = write(hdmiHPDFile, "0" , 2);
+ if (err <= 0) {
+ ALOGE("%s: file write failed 'hpd'", __FUNCTION__);
+ ret = false;
+ }
+ close(hdmiHPDFile);
+ }
+ }
+ return ret;
+}
+
+
+void HDMIDisplay::setAttributes() {
+ uint32_t fps = 0;
+ // Always set dpyAttr res to mVInfo res
+ getAttrForMode(mXres, mYres, fps);
+ mMDPScalingMode = false;
+
+ if(overlay::Overlay::getInstance()->isUIScalingOnExternalSupported()
+ && mMDPDownscaleEnabled) {
+ // if primary resolution is more than the hdmi resolution
+ // configure dpy attr to primary resolution and set MDP
+ // scaling mode
+ // Restrict this upto 1080p resolution max, if target does not
+ // support source split feature.
+ uint32_t primaryArea = mPrimaryWidth * mPrimaryHeight;
+ if(((primaryArea) > (mXres * mYres)) &&
+ (((primaryArea) <= SUPPORTED_DOWNSCALE_AREA) ||
+ qdutils::MDPVersion::getInstance().isSrcSplit())) {
+ // tmpW and tmpH will hold the primary dimensions before we
+ // update the aspect ratio if necessary.
+ int tmpW = mPrimaryWidth;
+ int tmpH = mPrimaryHeight;
+ // HDMI is always in landscape, so always assign the higher
+ // dimension to hdmi's xres
+ if(mPrimaryHeight > mPrimaryWidth) {
+ tmpW = mPrimaryHeight;
+ tmpH = mPrimaryWidth;
+ }
+ // The aspect ratios of the external and primary displays
+ // can be different. As a result, directly assigning primary
+ // resolution could lead to an incorrect final image.
+ // We get around this by calculating a new resolution by
+ // keeping aspect ratio intact.
+ hwc_rect r = {0, 0, 0, 0};
+ qdutils::getAspectRatioPosition(tmpW, tmpH, mXres, mYres, r);
+ uint32_t newExtW = r.right - r.left;
+ uint32_t newExtH = r.bottom - r.top;
+ uint32_t alignedExtW;
+ uint32_t alignedExtH;
+ // On 8994 and below targets MDP supports only 4X downscaling,
+ // Restricting selected external resolution to be exactly 4X
+ // greater resolution than actual external resolution
+ uint32_t maxMDPDownScale =
+ qdutils::MDPVersion::getInstance().getMaxMDPDownscale();
+ if((mXres * mYres * maxMDPDownScale) < (newExtW * newExtH)) {
+ float upScaleFactor = (float)maxMDPDownScale / 2.0f;
+ newExtW = (int)((float)mXres * upScaleFactor);
+ newExtH = (int)((float)mYres * upScaleFactor);
+ }
+ // Align it down so that the new aligned resolution does not
+ // exceed the maxMDPDownscale factor
+ alignedExtW = overlay::utils::aligndown(newExtW, 4);
+ alignedExtH = overlay::utils::aligndown(newExtH, 4);
+ mXres = alignedExtW;
+ mYres = alignedExtH;
+ // Set External Display MDP Downscale mode indicator
+ mMDPScalingMode = true;
+ }
+ }
+ ALOGD_IF(DEBUG_MDPDOWNSCALE, "Selected external resolution [%d X %d] "
+ "maxMDPDownScale %d mMDPScalingMode %d srcSplitEnabled %d "
+ "MDPDownscale feature %d",
+ mXres, mYres,
+ qdutils::MDPVersion::getInstance().getMaxMDPDownscale(),
+ mMDPScalingMode, qdutils::MDPVersion::getInstance().isSrcSplit(),
+ mMDPDownscaleEnabled);
+ mVsyncPeriod = (int) 1000000000l / fps;
+ ALOGD_IF(DEBUG, "%s xres=%d, yres=%d", __FUNCTION__, mXres, mYres);
+}
+
+void HDMIDisplay::getAttrForMode(uint32_t& width, uint32_t& height,
+ uint32_t& fps) {
+ for (int dataIndex = 0; dataIndex < gEDIDCount; dataIndex++) {
+ if (gEDIDData[dataIndex].mMode == mCurrentMode) {
+ width = gEDIDData[dataIndex].mWidth;
+ height = gEDIDData[dataIndex].mHeight;
+ fps = gEDIDData[dataIndex].mFps;
+ return;
+ }
+ }
+ ALOGE("%s Unable to get attributes for %d", __FUNCTION__, mCurrentMode);
+}
+
+/* returns the fd related to the node specified*/
+int HDMIDisplay::openDeviceNode(const char* node, int fileMode) const {
+ char sysFsFilePath[MAX_SYSFS_FILE_PATH];
+ memset(sysFsFilePath, 0, sizeof(sysFsFilePath));
+ snprintf(sysFsFilePath , sizeof(sysFsFilePath),
+ "/sys/devices/virtual/graphics/fb%d/%s",
+ mFbNum, node);
+
+ int fd = open(sysFsFilePath, fileMode, 0);
+
+ if (fd < 0) {
+ ALOGE("%s: file '%s' not found : ret = %d err str: %s",
+ __FUNCTION__, sysFsFilePath, fd, strerror(errno));
+ }
+ return fd;
+}
+
+bool HDMIDisplay::isHDMIPrimaryDisplay() {
+ int hdmiNode = qdutils::getHDMINode();
+ return (hdmiNode == HWC_DISPLAY_PRIMARY);
+}
+
+int HDMIDisplay::getConnectedState() {
+ int ret = -1;
+ int mFbNum = qdutils::getHDMINode();
+ int connectedNode = openDeviceNode("connected", O_RDONLY);
+ if(connectedNode >= 0) {
+ char opStr[4];
+ ssize_t bytesRead = read(connectedNode, opStr, sizeof(opStr) - 1);
+ if(bytesRead > 0) {
+ opStr[bytesRead] = '\0';
+ ret = atoi(opStr);
+ ALOGD_IF(DEBUG, "%s: Read %d from connected", __FUNCTION__, ret);
+ } else if(bytesRead == 0) {
+ ALOGE("%s: HDMI connected node empty", __FUNCTION__);
+ } else {
+ ALOGE("%s: Read from HDMI connected node failed with error %s",
+ __FUNCTION__, strerror(errno));
+ }
+ close(connectedNode);
+ } else {
+ ALOGD("%s: /sys/class/graphics/fb%d/connected could not be opened : %s",
+ __FUNCTION__, mFbNum, strerror(errno));
+ }
+ return ret;
+}
+
+void HDMIDisplay::setPrimaryAttributes(uint32_t primaryWidth,
+ uint32_t primaryHeight) {
+ mPrimaryHeight = primaryHeight;
+ mPrimaryWidth = primaryWidth;
+}
+
+};
diff --git a/msm8909/libhdmi/hdmi.h b/msm8909/libhdmi/hdmi.h
new file mode 100644
index 0000000..605d9be
--- /dev/null
+++ b/msm8909/libhdmi/hdmi.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are
+ * retained for attribution purposes only.
+
+ * 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_HDMI_DISPLAY_H
+#define HWC_HDMI_DISPLAY_H
+
+#include <linux/fb.h>
+
+struct msm_hdmi_mode_timing_info;
+
+namespace qhwc {
+
+//Type of scanning of EDID(Video Capability Data Block)
+enum hdmi_scansupport_type {
+ HDMI_SCAN_NOT_SUPPORTED = 0,
+ HDMI_SCAN_ALWAYS_OVERSCANED = 1,
+ HDMI_SCAN_ALWAYS_UNDERSCANED = 2,
+ HDMI_SCAN_BOTH_SUPPORTED = 3
+};
+
+// Structure to store EDID related data
+struct EDIDData {
+ int mMode, mWidth, mHeight, mFps;
+ // Predetermined ordering for each mode
+ int mModeOrder;
+ EDIDData(int mode, int width, int height, int fps, int order)
+ : mMode(mode), mWidth(width), mHeight(height), mFps(fps), mModeOrder(order)
+ { }
+};
+
+class HDMIDisplay
+{
+public:
+ HDMIDisplay();
+ ~HDMIDisplay();
+ void setHPD(uint32_t startEnd);
+ void setActionSafeDimension(int w, int h);
+ bool isCEUnderscanSupported() { return mUnderscanSupported; }
+ int configure();
+ void getAttributes(uint32_t& width, uint32_t& height);
+ int teardown();
+ uint32_t getWidth() const { return mXres; };
+ uint32_t getHeight() const { return mYres; };
+ uint32_t getVsyncPeriod() const { return mVsyncPeriod; };
+ int getFd() const { return mFd; };
+ bool getMDPScalingMode() const { return mMDPScalingMode; }
+ void activateDisplay();
+ /* Returns true if HDMI is the PRIMARY display device*/
+ bool isHDMIPrimaryDisplay();
+ int getConnectedState();
+ /* when HDMI is an EXTERNAL display, PRIMARY display attributes are needed
+ for scaling mode */
+ void setPrimaryAttributes(uint32_t primaryWidth, uint32_t primaryHeight);
+
+private:
+ int getModeCount() const;
+ void setSPDInfo(const char* node, const char* property);
+ void readCEUnderscanInfo();
+ bool readResolution();
+ int parseResolution(char* edidMode);
+ bool openFrameBuffer();
+ bool closeFrameBuffer();
+ bool writeHPDOption(int userOption) const;
+ bool isValidMode(int mode);
+ int getModeOrder(int mode);
+ int getUserMode();
+ int getBestMode();
+ bool isInterlacedMode(int mode);
+ void resetInfo();
+ void setAttributes();
+ void getAttrForMode(uint32_t& width, uint32_t& height, uint32_t& fps);
+ int openDeviceNode(const char* node, int fileMode) const;
+
+ int mFd;
+ int mFbNum;
+ int mCurrentMode;
+ int mEDIDModes[64];
+ int mModeCount;
+ fb_var_screeninfo mVInfo;
+ // Holds all the HDMI modes and timing info supported by driver
+ msm_hdmi_mode_timing_info* supported_video_mode_lut;
+ uint32_t mXres, mYres, mVsyncPeriod, mPrimaryWidth, mPrimaryHeight;
+ bool mMDPScalingMode;
+ bool mUnderscanSupported;
+ // Downscale feature switch, set via system property
+ // sys.hwc.mdp_downscale_enabled
+ bool mMDPDownscaleEnabled;
+ int mDisplayId;
+};
+
+}; //qhwc
+// ---------------------------------------------------------------------------
+#endif //HWC_HDMI_DISPLAY_H
diff --git a/msm8909/libhwcomposer/Android.mk b/msm8909/libhwcomposer/Android.mk
new file mode 100644
index 0000000..cb2c257
--- /dev/null
+++ b/msm8909/libhwcomposer/Android.mk
@@ -0,0 +1,66 @@
+LOCAL_PATH := $(call my-dir)
+include $(LOCAL_PATH)/../common.mk
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := hwcomposer.$(TARGET_BOARD_PLATFORM)
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes) \
+ $(TOP)/external/skia/include/core \
+ $(TOP)/external/skia/include/images
+
+ifeq ($(strip $(TARGET_USES_QCOM_DISPLAY_PP)),true)
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/qdcm/inc \
+ $(TARGET_OUT_HEADERS)/common/inc \
+ $(TARGET_OUT_HEADERS)/pp/inc
+endif
+
+LOCAL_SHARED_LIBRARIES := $(common_libs) libEGL liboverlay \
+ libhdmi libqdutils libhardware_legacy \
+ libdl libmemalloc libqservice libsync \
+ libbinder libmedia
+
+LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdhwcomposer\"
+ifeq ($(TARGET_USES_QCOM_BSP),true)
+LOCAL_SHARED_LIBRARIES += libskia
+ifeq ($(GET_FRAMEBUFFER_FORMAT_FROM_HWC),true)
+ LOCAL_CFLAGS += -DGET_FRAMEBUFFER_FORMAT_FROM_HWC
+endif
+endif #TARGET_USES_QCOM_BSP
+
+#Enable Dynamic FPS if PHASE_OFFSET is not set
+ifeq ($(VSYNC_EVENT_PHASE_OFFSET_NS),)
+ LOCAL_CFLAGS += -DDYNAMIC_FPS
+endif
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
+LOCAL_SRC_FILES := hwc.cpp \
+ hwc_utils.cpp \
+ hwc_uevents.cpp \
+ hwc_vsync.cpp \
+ hwc_fbupdate.cpp \
+ hwc_mdpcomp.cpp \
+ hwc_copybit.cpp \
+ hwc_qclient.cpp \
+ hwc_dump_layers.cpp \
+ hwc_ad.cpp \
+ hwc_virtual.cpp
+
+TARGET_MIGRATE_QDCM_LIST := msm8909
+TARGET_MIGRATE_QDCM := $(call is-board-platform-in-list,$(TARGET_MIGRATE_QDCM_LIST))
+
+ifeq ($(TARGET_MIGRATE_QDCM), true)
+ifeq ($(strip $(TARGET_USES_QCOM_DISPLAY_PP)),true)
+LOCAL_SRC_FILES += hwc_qdcm.cpp
+else
+LOCAL_SRC_FILES += hwc_qdcm_legacy.cpp
+endif
+else
+LOCAL_SRC_FILES += hwc_qdcm_legacy.cpp
+endif
+
+ifeq ($(TARGET_SUPPORTS_ANDROID_WEAR), true)
+ LOCAL_CFLAGS += -DSUPPORT_BLIT_TO_FB
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/msm8909/libhwcomposer/hwc.cpp b/msm8909/libhwcomposer/hwc.cpp
new file mode 100644
index 0000000..30ff9b3
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc.cpp
@@ -0,0 +1,978 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2015, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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 ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
+#include <fcntl.h>
+#include <errno.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <EGL/egl.h>
+#include <utils/Trace.h>
+#include <sys/ioctl.h>
+#include <overlay.h>
+#include <overlayRotator.h>
+#include <overlayWriteback.h>
+#include <mdp_version.h>
+#include "hwc_utils.h"
+#include "hwc_fbupdate.h"
+#include "hwc_mdpcomp.h"
+#include "hwc_dump_layers.h"
+#include "hdmi.h"
+#include "hwc_copybit.h"
+#include "hwc_ad.h"
+#include "profiler.h"
+#include "hwc_virtual.h"
+#include "hwc_qdcm.h"
+
+using namespace qhwc;
+using namespace overlay;
+using namespace qQdcm;
+
+#define VSYNC_DEBUG 0
+#define POWER_MODE_DEBUG 1
+
+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
+};
+
+static void reset_panel(struct hwc_composer_device_1* dev);
+
+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_1* dev,
+ hwc_procs_t const* procs)
+{
+ ALOGI("%s", __FUNCTION__);
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+ if(!ctx) {
+ ALOGE("%s: Invalid context", __FUNCTION__);
+ return;
+ }
+ ctx->proc = procs;
+
+ // Now that we have the functions needed, kick off
+ // the uevent & vsync threads
+ init_uevent_thread(ctx);
+ init_vsync_thread(ctx);
+}
+
+static void setPaddingRound(hwc_context_t *ctx, int numDisplays,
+ hwc_display_contents_1_t** displays) {
+ ctx->isPaddingRound = false;
+ for(int i = 0; i < numDisplays; i++) {
+ hwc_display_contents_1_t *list = displays[i];
+ if (LIKELY(list && list->numHwLayers > 0)) {
+ if((ctx->mPrevHwLayerCount[i] == 1 or
+ ctx->mPrevHwLayerCount[i] == 0) and
+ (list->numHwLayers > 1)) {
+ /* If the previous cycle for dpy 'i' has 0 AppLayers and the
+ * current cycle has atleast 1 AppLayer, padding round needs
+ * to be invoked in current cycle on all the active displays
+ * to free up the resources.
+ */
+ ctx->isPaddingRound = true;
+ }
+ ctx->mPrevHwLayerCount[i] = (int)list->numHwLayers;
+ } else {
+ ctx->mPrevHwLayerCount[i] = 0;
+ }
+ }
+}
+
+/* Based on certain conditions, isPaddingRound will be set
+ * to make this function self-contained */
+static void setDMAState(hwc_context_t *ctx, int numDisplays,
+ hwc_display_contents_1_t** displays) {
+
+ if(ctx->mRotMgr->getNumActiveSessions() == 0)
+ Overlay::setDMAMode(Overlay::DMA_LINE_MODE);
+
+ for(int dpy = 0; dpy < numDisplays; dpy++) {
+ hwc_display_contents_1_t *list = displays[dpy];
+ if (LIKELY(list && list->numHwLayers > 0)) {
+ for(size_t layerIndex = 0; layerIndex < list->numHwLayers;
+ layerIndex++) {
+ if(list->hwLayers[layerIndex].compositionType !=
+ HWC_FRAMEBUFFER_TARGET)
+ {
+ hwc_layer_1_t const* layer = &list->hwLayers[layerIndex];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+
+ /* If a layer requires rotation, set the DMA state
+ * to BLOCK_MODE */
+
+ if (canUseRotator(ctx, dpy) &&
+ (has90Transform(layer) || getRotDownscale(ctx, layer))
+ && isRotationDoable(ctx, hnd)) {
+ if(not (ctx->mOverlay->isDMAMultiplexingSupported() &&
+ dpy)) {
+ if(ctx->mOverlay->isPipeTypeAttached(
+ overlay::utils::OV_MDP_PIPE_DMA))
+ ctx->isPaddingRound = true;
+ }
+ Overlay::setDMAMode(Overlay::DMA_BLOCK_MODE);
+ }
+ }
+ }
+ if(dpy) {
+ /* Uncomment the below code for testing purpose.
+ Assuming the orientation value is in terms of HAL_TRANSFORM,
+ this needs mapping to HAL, if its in different convention */
+
+ /* char value[PROPERTY_VALUE_MAX];
+ property_get("sys.ext_orientation", value, "0");
+ ctx->mExtOrientation = atoi(value);*/
+
+ if(ctx->mExtOrientation || ctx->mBufferMirrorMode) {
+ if(ctx->mOverlay->isPipeTypeAttached(
+ overlay::utils::OV_MDP_PIPE_DMA)) {
+ ctx->isPaddingRound = true;
+ }
+ Overlay::setDMAMode(Overlay::DMA_BLOCK_MODE);
+ }
+ }
+ }
+ }
+}
+
+static void setNumActiveDisplays(hwc_context_t *ctx, int numDisplays,
+ hwc_display_contents_1_t** displays) {
+
+ ctx->numActiveDisplays = 0;
+ for(int i = 0; i < numDisplays; i++) {
+ hwc_display_contents_1_t *list = displays[i];
+ if (LIKELY(list && list->numHwLayers > 0)) {
+ /* For display devices like SSD and screenrecord, we cannot
+ * rely on isActive and connected attributes of dpyAttr to
+ * determine if the displaydevice is active. Hence in case if
+ * the layer-list is non-null and numHwLayers > 0, we assume
+ * the display device to be active.
+ */
+ ctx->numActiveDisplays += 1;
+ }
+ }
+}
+
+static bool validDisplay(int disp) {
+ switch(disp) {
+ case HWC_DISPLAY_PRIMARY:
+ case HWC_DISPLAY_EXTERNAL:
+ case HWC_DISPLAY_VIRTUAL:
+ return true;
+ break;
+ default:
+ return false;
+ }
+}
+
+static void reset(hwc_context_t *ctx, int numDisplays,
+ hwc_display_contents_1_t** displays) {
+
+
+ for(int i = 0; i < numDisplays; i++) {
+ hwc_display_contents_1_t *list = displays[i];
+ // XXX:SurfaceFlinger no longer guarantees that this
+ // value is reset on every prepare. However, for the layer
+ // cache we need to reset it.
+ // We can probably rethink that later on
+ if (LIKELY(list && list->numHwLayers > 0)) {
+ for(size_t j = 0; j < list->numHwLayers; j++) {
+ if(list->hwLayers[j].compositionType != HWC_FRAMEBUFFER_TARGET)
+ list->hwLayers[j].compositionType = HWC_FRAMEBUFFER;
+ }
+
+ }
+
+ if(ctx->mMDPComp[i])
+ ctx->mMDPComp[i]->reset();
+ if(ctx->mFBUpdate[i])
+ ctx->mFBUpdate[i]->reset();
+ if(ctx->mCopyBit[i])
+ ctx->mCopyBit[i]->reset();
+ if(ctx->mLayerRotMap[i])
+ ctx->mLayerRotMap[i]->reset();
+ }
+
+ ctx->mAD->reset();
+
+}
+
+static void scaleDisplayFrame(hwc_context_t *ctx, int dpy,
+ hwc_display_contents_1_t *list) {
+ uint32_t origXres = ctx->dpyAttr[dpy].xres;
+ uint32_t origYres = ctx->dpyAttr[dpy].yres;
+ uint32_t newXres = ctx->dpyAttr[dpy].xres_new;
+ uint32_t newYres = ctx->dpyAttr[dpy].yres_new;
+ float xresRatio = (float)origXres / (float)newXres;
+ float yresRatio = (float)origYres / (float)newYres;
+ for (size_t i = 0; i < list->numHwLayers; i++) {
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ hwc_rect_t& displayFrame = layer->displayFrame;
+ hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
+ uint32_t layerWidth = displayFrame.right - displayFrame.left;
+ uint32_t layerHeight = displayFrame.bottom - displayFrame.top;
+ displayFrame.left = (int)(xresRatio * (float)displayFrame.left);
+ displayFrame.top = (int)(yresRatio * (float)displayFrame.top);
+ displayFrame.right = (int)((float)displayFrame.left +
+ (float)layerWidth * xresRatio);
+ displayFrame.bottom = (int)((float)displayFrame.top +
+ (float)layerHeight * yresRatio);
+ }
+}
+
+static int hwc_prepare_primary(hwc_composer_device_1 *dev,
+ hwc_display_contents_1_t *list) {
+ ATRACE_CALL();
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+ const int dpy = HWC_DISPLAY_PRIMARY;
+ bool fbComp = false;
+ static int compStart = false;
+ if (!ctx->mBootAnimCompleted)
+ processBootAnimCompleted(ctx);
+
+ if (LIKELY(list && (list->numHwLayers > 1 ||
+ (ctx->mMDP.version < qdutils::MDP_V4_0 && compStart))) &&
+ (ctx->dpyAttr[dpy].isActive ||
+ ctx->mHDMIDisplay->isHDMIPrimaryDisplay())
+ && !ctx->dpyAttr[dpy].isPause) {
+ compStart = true;
+
+ // When HDMI is primary we should rely on the first valid
+ // draw call in order to activate the display
+ if (!ctx->dpyAttr[dpy].isActive) {
+ // If the cable is connected after HWC initialization and before
+ // the UEvent thread is initialized then we will miss the ONLINE
+ // event. We need to update the display appropriately when we get
+ // the first valid frame.
+ int cableConnected = ctx->mHDMIDisplay->getConnectedState();
+ if ((cableConnected == 1) && !ctx->dpyAttr[dpy].connected) {
+ qhwc::handle_online(ctx, dpy);
+ }
+ ctx->mHDMIDisplay->activateDisplay();
+ ctx->dpyAttr[dpy].isActive = true;
+ }
+
+ if (ctx->dpyAttr[dpy].customFBSize &&
+ list->flags & HWC_GEOMETRY_CHANGED)
+ scaleDisplayFrame(ctx, dpy, list);
+
+ reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1);
+ setListStats(ctx, list, dpy);
+
+ fbComp = (ctx->mMDPComp[dpy]->prepare(ctx, list) < 0);
+
+ if (fbComp) {
+ const int fbZ = 0;
+ if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ)) {
+ ctx->mOverlay->clear(dpy);
+ ctx->mLayerRotMap[dpy]->clear();
+ }
+ }
+
+ if (ctx->mMDP.version < qdutils::MDP_V4_0) {
+ if(ctx->mCopyBit[dpy])
+ ctx->mCopyBit[dpy]->prepare(ctx, list, dpy);
+ }
+ setGPUHint(ctx, list);
+ }
+ return 0;
+}
+
+static int hwc_prepare_external(hwc_composer_device_1 *dev,
+ hwc_display_contents_1_t *list) {
+ ATRACE_CALL();
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+ const int dpy = HWC_DISPLAY_EXTERNAL;
+
+ if (LIKELY(list && list->numHwLayers > 1) &&
+ ctx->dpyAttr[dpy].isActive &&
+ ctx->dpyAttr[dpy].connected) {
+ reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1);
+ if(!ctx->dpyAttr[dpy].isPause) {
+ ctx->dpyAttr[dpy].isConfiguring = false;
+ setListStats(ctx, list, dpy);
+ if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
+ const int fbZ = 0;
+ if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ))
+ {
+ ctx->mOverlay->clear(dpy);
+ ctx->mLayerRotMap[dpy]->clear();
+ }
+ }
+ } else {
+ /* External Display is in Pause state.
+ * Mark all application layers as OVERLAY so that
+ * GPU will not compose.
+ */
+ for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ layer->compositionType = HWC_OVERLAY;
+ }
+ }
+ }
+ return 0;
+}
+
+static int hwc_prepare(hwc_composer_device_1 *dev, size_t numDisplays,
+ hwc_display_contents_1_t** displays)
+{
+ int ret = 0;
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+
+ if (ctx->mPanelResetStatus) {
+ ALOGW("%s: panel is in bad state. reset the panel", __FUNCTION__);
+ reset_panel(dev);
+ }
+
+ //Will be unlocked at the end of set
+ ctx->mDrawLock.lock();
+ setPaddingRound(ctx, (int)numDisplays, displays);
+ setDMAState(ctx, (int)numDisplays, displays);
+ setNumActiveDisplays(ctx, (int)numDisplays, displays);
+ reset(ctx, (int)numDisplays, displays);
+
+ ctx->mOverlay->configBegin();
+ ctx->mRotMgr->configBegin();
+ overlay::Writeback::configBegin();
+
+ for (int32_t dpy = ((int32_t)numDisplays-1); dpy >=0 ; dpy--) {
+ hwc_display_contents_1_t *list = displays[dpy];
+ resetROI(ctx, dpy);
+ switch(dpy) {
+ case HWC_DISPLAY_PRIMARY:
+ ret = hwc_prepare_primary(dev, list);
+ break;
+ case HWC_DISPLAY_EXTERNAL:
+ ret = hwc_prepare_external(dev, list);
+ break;
+ case HWC_DISPLAY_VIRTUAL:
+ if(ctx->mHWCVirtual)
+ ret = ctx->mHWCVirtual->prepare(dev, list);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ }
+
+ ctx->mOverlay->configDone();
+ ctx->mRotMgr->configDone();
+ overlay::Writeback::configDone();
+ // If VD list is deleted, mdp overlay pipe objects and writeback object
+ // are deleted as part of configDone functions.
+ // Proceed with HWCVirtualVDS object deletion.
+ if(ctx->mHWCVirtual)
+ ctx->mHWCVirtual->destroy(ctx, numDisplays, displays);
+
+ return ret;
+}
+
+static int hwc_eventControl(struct hwc_composer_device_1* dev, int dpy,
+ int event, int enable)
+{
+ ATRACE_CALL();
+ int ret = 0;
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+ if(!validDisplay(dpy)) {
+ return -EINVAL;
+ }
+
+ switch(event) {
+ case HWC_EVENT_VSYNC:
+ if (ctx->vstate.enable == enable)
+ break;
+ ret = hwc_vsync_control(ctx, dpy, enable);
+ if(ret == 0)
+ ctx->vstate.enable = !!enable;
+ ALOGD_IF (VSYNC_DEBUG, "VSYNC state changed to %s",
+ (enable)?"ENABLED":"DISABLED");
+ break;
+#ifdef QTI_BSP
+ case HWC_EVENT_ORIENTATION:
+ if(dpy == HWC_DISPLAY_PRIMARY) {
+ Locker::Autolock _l(ctx->mDrawLock);
+ // store the primary display orientation
+ ctx->deviceOrientation = enable;
+ }
+ break;
+#endif
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int hwc_setPowerMode(struct hwc_composer_device_1* dev, int dpy,
+ int mode)
+{
+ ATRACE_CALL();
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+ int ret = 0, value = 0;
+
+ Locker::Autolock _l(ctx->mDrawLock);
+
+ if(!validDisplay(dpy)) {
+ return -EINVAL;
+ }
+
+ ALOGD_IF(POWER_MODE_DEBUG, "%s: Setting mode %d on display: %d",
+ __FUNCTION__, mode, dpy);
+
+ switch(mode) {
+ case HWC_POWER_MODE_OFF:
+ // free up all the overlay pipes in use
+ // when we get a blank for either display
+ // makes sure that all pipes are freed
+ ctx->mOverlay->configBegin();
+ ctx->mOverlay->configDone();
+ ctx->mRotMgr->clear();
+ // If VDS is connected, do not clear WB object as it
+ // will end up detaching IOMMU. This is required
+ // to send black frame to WFD sink on power suspend.
+ // Note: With this change, we keep the WriteBack object
+ // alive on power suspend for AD use case.
+ value = FB_BLANK_POWERDOWN;
+ break;
+ case HWC_POWER_MODE_DOZE:
+ case HWC_POWER_MODE_DOZE_SUSPEND:
+ value = FB_BLANK_VSYNC_SUSPEND;
+ break;
+ case HWC_POWER_MODE_NORMAL:
+ value = FB_BLANK_UNBLANK;
+ break;
+ }
+
+ switch(dpy) {
+ case HWC_DISPLAY_PRIMARY:
+ if(ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) {
+ if(ctx->dpyAttr[dpy].connected) {
+ // When HDMI is connected as primary we clean up resources
+ // and call commit to generate a black frame on the interface.
+ // However, we do not call blank since we need the timing
+ // generator and HDMI core to remain turned on.
+ if((mode == HWC_POWER_MODE_OFF) &&
+ (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd))) {
+ ALOGE("%s: display commit fail for %d", __FUNCTION__, dpy);
+ ret = -1;
+ }
+ }
+ } else {
+ if(ioctl(ctx->dpyAttr[dpy].fd, FBIOBLANK, value) < 0 ) {
+ ALOGE("%s: ioctl FBIOBLANK failed for Primary with error %s"
+ " value %d", __FUNCTION__, strerror(errno), value);
+ return -errno;
+ }
+
+ if(mode == HWC_POWER_MODE_NORMAL) {
+ // Enable HPD here, as during bootup POWER_MODE_NORMAL is set
+ // when SF is completely initialized
+ ctx->mHDMIDisplay->setHPD(1);
+ }
+
+ ctx->dpyAttr[dpy].isActive = not(mode == HWC_POWER_MODE_OFF);
+ }
+ //Deliberate fall through since there is no explicit power mode for
+ //virtual displays.
+ case HWC_DISPLAY_VIRTUAL:
+ if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected) {
+ const int dpy = HWC_DISPLAY_VIRTUAL;
+ if(mode == HWC_POWER_MODE_OFF and
+ (not ctx->dpyAttr[dpy].isPause)) {
+ if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ ALOGE("%s: displayCommit failed for virtual", __FUNCTION__);
+ ret = -1;
+ }
+ }
+ ctx->dpyAttr[dpy].isActive = not(mode == HWC_POWER_MODE_OFF);
+ }
+ break;
+ case HWC_DISPLAY_EXTERNAL:
+ if(mode == HWC_POWER_MODE_OFF) {
+ if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ ALOGE("%s: displayCommit failed for external", __FUNCTION__);
+ ret = -1;
+ }
+ }
+ ctx->dpyAttr[dpy].isActive = not(mode == HWC_POWER_MODE_OFF);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ALOGD_IF(POWER_MODE_DEBUG, "%s: Done setting mode %d on display %d",
+ __FUNCTION__, mode, dpy);
+ return ret;
+}
+
+static void reset_panel(struct hwc_composer_device_1* dev)
+{
+ int ret = 0;
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+
+ if (!ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isActive) {
+ ALOGD ("%s : Display OFF - Skip BLANK & UNBLANK", __FUNCTION__);
+ ctx->mPanelResetStatus = false;
+ return;
+ }
+
+ ALOGD("%s: setting power mode off", __FUNCTION__);
+ ret = hwc_setPowerMode(dev, HWC_DISPLAY_PRIMARY, HWC_POWER_MODE_OFF);
+ if (ret < 0) {
+ ALOGE("%s: FBIOBLANK failed to BLANK: %s", __FUNCTION__,
+ strerror(errno));
+ }
+
+ ALOGD("%s: setting power mode normal and enabling vsync", __FUNCTION__);
+ ret = hwc_setPowerMode(dev, HWC_DISPLAY_PRIMARY, HWC_POWER_MODE_NORMAL);
+ if (ret < 0) {
+ ALOGE("%s: FBIOBLANK failed to UNBLANK : %s", __FUNCTION__,
+ strerror(errno));
+ }
+ hwc_vsync_control(ctx, HWC_DISPLAY_PRIMARY, 1);
+
+ ctx->mPanelResetStatus = false;
+}
+
+
+static int hwc_query(struct hwc_composer_device_1* dev,
+ int param, int* value)
+{
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+ int supported = HWC_DISPLAY_PRIMARY_BIT;
+
+ switch (param) {
+ case HWC_BACKGROUND_LAYER_SUPPORTED:
+ // Not supported for now
+ value[0] = 0;
+ break;
+ case HWC_DISPLAY_TYPES_SUPPORTED:
+ if(ctx->mMDP.hasOverlay) {
+ supported |= HWC_DISPLAY_VIRTUAL_BIT;
+ if(!(qdutils::MDPVersion::getInstance().is8x26() ||
+ qdutils::MDPVersion::getInstance().is8x16() ||
+ qdutils::MDPVersion::getInstance().is8x39()))
+ supported |= HWC_DISPLAY_EXTERNAL_BIT;
+ }
+ value[0] = supported;
+ break;
+ case HWC_FORMAT_RB_SWAP:
+ value[0] = 1;
+ break;
+ case HWC_COLOR_FILL:
+ value[0] = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+
+}
+
+
+static int hwc_set_primary(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+ ATRACE_CALL();
+ int ret = 0;
+ const int dpy = HWC_DISPLAY_PRIMARY;
+ if (LIKELY(list) && ctx->dpyAttr[dpy].isActive
+ && !ctx->dpyAttr[dpy].isPause) {
+ size_t last = list->numHwLayers - 1;
+ hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+ int fd = -1; //FenceFD from the Copybit(valid in async mode)
+ bool copybitDone = false;
+
+ if (ctx->mCopyBit[dpy]) {
+ if (ctx->mMDP.version < qdutils::MDP_V4_0)
+ copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
+ else
+ fd = ctx->mMDPComp[dpy]->drawOverlap(ctx, list);
+ }
+
+ if(list->numHwLayers > 1)
+ hwc_sync(ctx, list, dpy, fd);
+
+ // Dump the layers for primary
+ if(ctx->mHwcDebug[dpy])
+ ctx->mHwcDebug[dpy]->dumpLayers(list);
+
+ if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
+ ALOGE("%s: MDPComp draw failed", __FUNCTION__);
+ ret = -1;
+ }
+
+ //TODO We dont check for SKIP flag on this layer because we need PAN
+ //always. Last layer is always FB
+ private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
+ if(copybitDone && ((ctx->mMDP.version >= qdutils::MDP_V4_0)
+#ifdef SUPPORT_BLIT_TO_FB
+ || (ctx->mMDP.version == qdutils::MDP_V3_0_5)
+#endif
+ )) {
+ hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
+ }
+
+ if(isAbcInUse(ctx) == true) {
+ int index = ctx->listStats[dpy].renderBufIndexforABC;
+ hwc_layer_1_t *tempLayer = &list->hwLayers[index];
+ hnd = (private_handle_t *)tempLayer->handle;
+ }
+
+ if(hnd) {
+ if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
+ ALOGE("%s: FBUpdate draw failed", __FUNCTION__);
+ ret = -1;
+ }
+ }
+
+ int lSplit = getLeftSplit(ctx, dpy);
+ qhwc::ovutils::Dim lRoi = qhwc::ovutils::Dim(
+ ctx->listStats[dpy].lRoi.left,
+ ctx->listStats[dpy].lRoi.top,
+ ctx->listStats[dpy].lRoi.right - ctx->listStats[dpy].lRoi.left,
+ ctx->listStats[dpy].lRoi.bottom - ctx->listStats[dpy].lRoi.top);
+
+ qhwc::ovutils::Dim rRoi = qhwc::ovutils::Dim(
+ ctx->listStats[dpy].rRoi.left - lSplit,
+ ctx->listStats[dpy].rRoi.top,
+ ctx->listStats[dpy].rRoi.right - ctx->listStats[dpy].rRoi.left,
+ ctx->listStats[dpy].rRoi.bottom - ctx->listStats[dpy].rRoi.top);
+
+ if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd, lRoi, rRoi)) {
+ ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
+ ret = -1;
+ }
+
+ }
+
+ closeAcquireFds(list);
+ return ret;
+}
+
+static int hwc_set_external(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list)
+{
+ ATRACE_CALL();
+ int ret = 0;
+
+ const int dpy = HWC_DISPLAY_EXTERNAL;
+
+ if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
+ ctx->dpyAttr[dpy].connected &&
+ !ctx->dpyAttr[dpy].isPause) {
+ size_t last = list->numHwLayers - 1;
+ hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+ int fd = -1; //FenceFD from the Copybit(valid in async mode)
+ bool copybitDone = false;
+ if(ctx->mCopyBit[dpy])
+ copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
+
+ if(list->numHwLayers > 1)
+ hwc_sync(ctx, list, dpy, fd);
+
+ // Dump the layers for external
+ if(ctx->mHwcDebug[dpy])
+ ctx->mHwcDebug[dpy]->dumpLayers(list);
+
+ if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
+ ALOGE("%s: MDPComp draw failed", __FUNCTION__);
+ ret = -1;
+ }
+
+ private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
+ if(copybitDone) {
+ hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
+ }
+
+ if(hnd) {
+ if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
+ ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
+ ret = -1;
+ }
+ }
+
+ if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
+ ret = -1;
+ }
+ }
+
+ closeAcquireFds(list);
+ return ret;
+}
+
+static int hwc_set(hwc_composer_device_1 *dev,
+ size_t numDisplays,
+ hwc_display_contents_1_t** displays)
+{
+ int ret = 0;
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+ for (int dpy = 0; dpy < (int)numDisplays; dpy++) {
+ hwc_display_contents_1_t* list = displays[dpy];
+ switch(dpy) {
+ case HWC_DISPLAY_PRIMARY:
+ ret = hwc_set_primary(ctx, list);
+ break;
+ case HWC_DISPLAY_EXTERNAL:
+ ret = hwc_set_external(ctx, list);
+ break;
+ case HWC_DISPLAY_VIRTUAL:
+ if(ctx->mHWCVirtual)
+ ret = ctx->mHWCVirtual->set(ctx, list);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ }
+ // This is only indicative of how many times SurfaceFlinger posts
+ // frames to the display.
+ CALC_FPS();
+ MDPComp::resetIdleFallBack();
+ ctx->mVideoTransFlag = false;
+ //Was locked at the beginning of prepare
+ ctx->mDrawLock.unlock();
+ return ret;
+}
+
+int hwc_getDisplayConfigs(struct hwc_composer_device_1* dev, int disp,
+ uint32_t* configs, size_t* numConfigs) {
+ int ret = 0;
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+
+ Locker::Autolock _l(ctx->mDrawLock);
+
+ if(!validDisplay(disp)) {
+ return -EINVAL;
+ }
+ //Currently we allow only 1 config, reported as config id # 0
+ //This config is passed in to getDisplayAttributes. Ignored for now.
+
+ switch(disp) {
+ case HWC_DISPLAY_PRIMARY:
+ if(*numConfigs > 0) {
+ configs[0] = 0;
+ *numConfigs = 1;
+ }
+ ret = 0; //NO_ERROR
+ break;
+ case HWC_DISPLAY_EXTERNAL:
+ case HWC_DISPLAY_VIRTUAL:
+ ret = -1; //Not connected
+ if(ctx->dpyAttr[disp].connected) {
+ ret = 0; //NO_ERROR
+ if(*numConfigs > 0) {
+ configs[0] = 0;
+ *numConfigs = 1;
+ }
+ }
+ break;
+ }
+ return ret;
+}
+
+int hwc_getDisplayAttributes(struct hwc_composer_device_1* dev, int disp,
+ uint32_t /*config*/, const uint32_t* attributes, int32_t* values) {
+
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+
+ Locker::Autolock _l(ctx->mDrawLock);
+
+ if(!validDisplay(disp)) {
+ return -EINVAL;
+ }
+ //If hotpluggable displays(i.e, HDMI, WFD) are inactive return error
+ if( (disp != HWC_DISPLAY_PRIMARY) && !ctx->dpyAttr[disp].connected) {
+ return -1;
+ }
+
+ //From HWComposer
+ static const uint32_t DISPLAY_ATTRIBUTES[] = {
+ HWC_DISPLAY_VSYNC_PERIOD,
+ HWC_DISPLAY_WIDTH,
+ HWC_DISPLAY_HEIGHT,
+ HWC_DISPLAY_DPI_X,
+ HWC_DISPLAY_DPI_Y,
+#ifdef GET_FRAMEBUFFER_FORMAT_FROM_HWC
+ HWC_DISPLAY_FBFORMAT,
+#endif
+ HWC_DISPLAY_NO_ATTRIBUTE,
+ };
+
+ const size_t NUM_DISPLAY_ATTRIBUTES = (sizeof(DISPLAY_ATTRIBUTES) /
+ sizeof(DISPLAY_ATTRIBUTES)[0]);
+
+ for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) {
+ switch (attributes[i]) {
+ case HWC_DISPLAY_VSYNC_PERIOD:
+ values[i] = ctx->dpyAttr[disp].vsync_period;
+ break;
+ case HWC_DISPLAY_WIDTH:
+ if (ctx->dpyAttr[disp].customFBSize)
+ values[i] = ctx->dpyAttr[disp].xres_new;
+ else
+ values[i] = ctx->dpyAttr[disp].xres;
+
+ ALOGD("%s disp = %d, width = %d",__FUNCTION__, disp,
+ values[i]);
+ break;
+ case HWC_DISPLAY_HEIGHT:
+ if (ctx->dpyAttr[disp].customFBSize)
+ values[i] = ctx->dpyAttr[disp].yres_new;
+ else
+ values[i] = ctx->dpyAttr[disp].yres;
+ ALOGD("%s disp = %d, height = %d",__FUNCTION__, disp,
+ values[i]);
+ break;
+ case HWC_DISPLAY_DPI_X:
+ values[i] = (int32_t) (ctx->dpyAttr[disp].xdpi*1000.0);
+ break;
+ case HWC_DISPLAY_DPI_Y:
+ values[i] = (int32_t) (ctx->dpyAttr[disp].ydpi*1000.0);
+ break;
+#ifdef GET_FRAMEBUFFER_FORMAT_FROM_HWC
+ case HWC_DISPLAY_FBFORMAT:
+ values[i] = ctx->dpyAttr[disp].fbformat;
+ break;
+#endif
+ default:
+ ALOGE("Unknown display attribute %d",
+ attributes[i]);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+void hwc_dump(struct hwc_composer_device_1* dev, char *buff, int buff_len)
+{
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+ Locker::Autolock _l(ctx->mDrawLock);
+ android::String8 aBuf("");
+ dumpsys_log(aBuf, "Qualcomm HWC state:\n");
+ dumpsys_log(aBuf, " MDPVersion=%d\n", ctx->mMDP.version);
+ dumpsys_log(aBuf, " DisplayPanel=%c\n", ctx->mMDP.panel);
+ dumpsys_log(aBuf, " DynRefreshRate=%d\n",
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].dynRefreshRate);
+ for(int dpy = 0; dpy < HWC_NUM_DISPLAY_TYPES; dpy++) {
+ if(ctx->mMDPComp[dpy])
+ ctx->mMDPComp[dpy]->dump(aBuf, ctx);
+ }
+ char ovDump[2048] = {'\0'};
+ ctx->mOverlay->getDump(ovDump, 2048);
+ dumpsys_log(aBuf, ovDump);
+ ovDump[0] = '\0';
+ ctx->mRotMgr->getDump(ovDump, 1024);
+ dumpsys_log(aBuf, ovDump);
+ ovDump[0] = '\0';
+ if(Writeback::getDump(ovDump, 1024)) {
+ dumpsys_log(aBuf, ovDump);
+ ovDump[0] = '\0';
+ }
+ dumpsys_log(aBuf, "Copybit::isAbcInUse=%d\n\n",isAbcInUse(ctx) ? 1 : 0);
+ strlcpy(buff, aBuf.string(), buff_len);
+}
+
+int hwc_getActiveConfig(struct hwc_composer_device_1* dev, int disp) {
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+ Locker::Autolock _l(ctx->mDrawLock);
+ if(!validDisplay(disp)) {
+ return -EINVAL;
+ }
+
+ //Supports only the default config (0th index) for now
+ return 0;
+}
+
+int hwc_setActiveConfig(struct hwc_composer_device_1* dev, int disp,
+ int index) {
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+ Locker::Autolock _l(ctx->mDrawLock);
+ if(!validDisplay(disp)) {
+ return -EINVAL;
+ }
+
+ //Supports only the default config (0th index) for now
+ return (index == 0) ? index : -EINVAL;
+}
+
+static int hwc_device_close(struct hw_device_t *dev)
+{
+ if(!dev) {
+ ALOGE("%s: NULL device pointer", __FUNCTION__);
+ 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));
+ if(dev == NULL)
+ return status;
+ memset(dev, 0, sizeof(*dev));
+
+ //Initialize hwc context
+ initContext(dev);
+
+ //Setup HWC methods
+ dev->device.common.tag = HARDWARE_DEVICE_TAG;
+ dev->device.common.version = HWC_DEVICE_API_VERSION_1_5;
+ dev->device.common.module = const_cast<hw_module_t*>(module);
+ dev->device.common.close = hwc_device_close;
+ dev->device.prepare = hwc_prepare;
+ dev->device.set = hwc_set;
+ dev->device.eventControl = hwc_eventControl;
+ dev->device.setPowerMode = hwc_setPowerMode;
+ dev->device.query = hwc_query;
+ dev->device.registerProcs = hwc_registerProcs;
+ dev->device.dump = hwc_dump;
+ dev->device.getDisplayConfigs = hwc_getDisplayConfigs;
+ dev->device.getDisplayAttributes = hwc_getDisplayAttributes;
+ dev->device.getActiveConfig = hwc_getActiveConfig;
+ dev->device.setActiveConfig = hwc_setActiveConfig;
+ *device = &dev->device.common;
+ status = 0;
+ }
+ return status;
+}
diff --git a/msm8909/libhwcomposer/hwc_ad.cpp b/msm8909/libhwcomposer/hwc_ad.cpp
new file mode 100644
index 0000000..7e96d97
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_ad.cpp
@@ -0,0 +1,278 @@
+/*
+* Copyright (c) 2013-2014 The Linux Foundation. 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 The Linux Foundation. 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 <unistd.h>
+#include <overlay.h>
+#include <overlayUtils.h>
+#include <overlayWriteback.h>
+#include <mdp_version.h>
+#include "hwc_ad.h"
+#include "hwc_utils.h"
+
+#define DEBUG 0
+using namespace overlay;
+using namespace overlay::utils;
+namespace qhwc {
+
+//Helper to write data to ad node
+static void adWrite(const int& value) {
+ const int wbFbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
+ char wbFbPath[256];
+ snprintf (wbFbPath, sizeof(wbFbPath),
+ "/sys/class/graphics/fb%d/ad", wbFbNum);
+ int adFd = open(wbFbPath, O_WRONLY);
+ if(adFd >= 0) {
+ char opStr[4] = "";
+ snprintf(opStr, sizeof(opStr), "%d", value);
+ ssize_t ret = write(adFd, opStr, strlen(opStr));
+ if(ret < 0) {
+ ALOGE("%s: Failed to write %d with error %s",
+ __func__, value, strerror(errno));
+ } else if (ret == 0){
+ ALOGE("%s Nothing written to ad", __func__);
+ } else {
+ ALOGD_IF(DEBUG, "%s: Wrote %d to ad", __func__, value);
+ }
+ close(adFd);
+ } else {
+ ALOGE("%s: Failed to open /sys/class/graphics/fb%d/ad with error %s",
+ __func__, wbFbNum, strerror(errno));
+ }
+}
+
+//Helper to read data from ad node
+static int adRead() {
+ const int wbFbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
+ int ret = -1;
+ char wbFbPath[256];
+ snprintf (wbFbPath, sizeof(wbFbPath),
+ "/sys/class/graphics/fb%d/ad", wbFbNum);
+ int adFd = open(wbFbPath, O_RDONLY);
+ if(adFd >= 0) {
+ char opStr[4];
+ ssize_t bytesRead = read(adFd, opStr, sizeof(opStr) - 1);
+ if(bytesRead > 0) {
+ opStr[bytesRead] = '\0';
+ //Should return -1, 0 or 1
+ ret = atoi(opStr);
+ ALOGD_IF(DEBUG, "%s: Read %d from ad", __func__, ret);
+ } else if(bytesRead == 0) {
+ ALOGE("%s: ad node empty", __func__);
+ } else {
+ ALOGE("%s: Read from ad node failed with error %s", __func__,
+ strerror(errno));
+ }
+ close(adFd);
+ } else {
+ ALOGD("%s: /sys/class/graphics/fb%d/ad could not be opened : %s",
+ __func__, wbFbNum, strerror(errno));
+ }
+ return ret;
+}
+
+AssertiveDisplay::AssertiveDisplay(hwc_context_t *ctx) :
+ mTurnedOff(true), mFeatureEnabled(false),
+ mDest(overlay::utils::OV_INVALID)
+{
+ //Values in ad node:
+ //-1 means feature is disabled on device
+ // 0 means feature exists but turned off, will be turned on by hwc
+ // 1 means feature is turned on by hwc
+ // Plus, we do this feature only on split primary displays.
+ // Plus, we do this feature only if ro.qcom.ad=2
+
+ char property[PROPERTY_VALUE_MAX];
+ const int ENABLED = 2;
+ int val = 0;
+
+ if(property_get("ro.qcom.ad", property, "0") > 0) {
+ val = atoi(property);
+ }
+
+ if(adRead() >= 0 && isDisplaySplit(ctx, HWC_DISPLAY_PRIMARY) &&
+ val == ENABLED) {
+ ALOGD_IF(DEBUG, "Assertive display feature supported");
+ mFeatureEnabled = true;
+ // If feature exists but is turned off, set mTurnedOff to true
+ mTurnedOff = adRead() > 0 ? false : true;
+ }
+}
+
+void AssertiveDisplay::markDoable(hwc_context_t *ctx,
+ const hwc_display_contents_1_t* list) {
+ mDoable = false;
+ if(mFeatureEnabled &&
+ !isSecondaryConnected(ctx) &&
+ ctx->listStats[HWC_DISPLAY_PRIMARY].yuvCount == 1) {
+ int nYuvIndex = ctx->listStats[HWC_DISPLAY_PRIMARY].yuvIndices[0];
+ const hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance();
+ if(hnd && hnd->width <= (int) mdpHw.getMaxMixerWidth()) {
+ mDoable = true;
+ }
+ }
+}
+
+void AssertiveDisplay::turnOffAD() {
+ if(mFeatureEnabled) {
+ if(!mTurnedOff) {
+ const int off = 0;
+ adWrite(off);
+ mTurnedOff = true;
+ }
+ }
+ mDoable = false;
+}
+
+bool AssertiveDisplay::prepare(hwc_context_t *ctx,
+ const hwc_rect_t& crop,
+ const Whf& whf,
+ const private_handle_t *hnd) {
+ if(!isDoable()) {
+ //Cleanup one time during this switch
+ turnOffAD();
+ return false;
+ }
+
+ Overlay::PipeSpecs pipeSpecs;
+ pipeSpecs.formatClass = Overlay::FORMAT_YUV;
+ pipeSpecs.dpy = overlay::Overlay::DPY_WRITEBACK;
+ pipeSpecs.fb = false;
+
+ ovutils::eDest dest = ctx->mOverlay->getPipe(pipeSpecs);
+ if(dest == OV_INVALID) {
+ ALOGE("%s failed: No VG pipe available", __func__);
+ mDoable = false;
+ return false;
+ }
+
+ overlay::Writeback *wb = overlay::Writeback::getInstance();
+
+ //Set Security flag on writeback
+ if(isSecureBuffer(hnd)) {
+ if(!wb->setSecure(isSecureBuffer(hnd))) {
+ ALOGE("Failure in setting WB secure flag for ad");
+ return false;
+ }
+ }
+
+ if(!wb->configureDpyInfo(hnd->width, hnd->height)) {
+ ALOGE("%s: config display failed", __func__);
+ mDoable = false;
+ return false;
+ }
+
+ int tmpW, tmpH;
+ size_t size;
+ int format = ovutils::getHALFormat(wb->getOutputFormat());
+ if(format < 0) {
+ ALOGE("%s invalid format %d", __func__, format);
+ mDoable = false;
+ return false;
+ }
+
+ size = getBufferSizeAndDimensions(hnd->width, hnd->height,
+ format, tmpW, tmpH);
+
+ if(!wb->configureMemory((uint32_t)size)) {
+ ALOGE("%s: config memory failed", __func__);
+ mDoable = false;
+ return false;
+ }
+
+ eMdpFlags mdpFlags = OV_MDP_FLAGS_NONE;
+ if(isSecureBuffer(hnd)) {
+ ovutils::setMdpFlags(mdpFlags,
+ ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
+ }
+
+ PipeArgs parg(mdpFlags, whf, ZORDER_0,
+ ROT_FLAGS_NONE);
+ hwc_rect_t dst = crop; //input same as output
+
+ if(configMdp(ctx->mOverlay, parg, OVERLAY_TRANSFORM_0, crop, dst, NULL,
+ dest) < 0) {
+ ALOGE("%s: configMdp failed", __func__);
+ mDoable = false;
+ return false;
+ }
+
+ mDest = dest;
+ int wbFd = wb->getFbFd();
+ if(mFeatureEnabled && wbFd >= 0 &&
+ !ctx->mOverlay->validateAndSet(overlay::Overlay::DPY_WRITEBACK, wbFd))
+ {
+ ALOGE("%s: Failed to validate and set overlay for dpy %d"
+ ,__FUNCTION__, overlay::Overlay::DPY_WRITEBACK);
+ turnOffAD();
+ return false;
+ }
+
+ // Only turn on AD if there are no errors during configuration stage
+ // and if it was previously in OFF state.
+ if(mFeatureEnabled && mTurnedOff) {
+ //write to sysfs, one time during this switch
+ const int on = 1;
+ adWrite(on);
+ mTurnedOff = false;
+ }
+
+ return true;
+}
+
+bool AssertiveDisplay::draw(hwc_context_t *ctx, int fd, uint32_t offset) {
+ if(!isDoable()) {
+ return false;
+ }
+
+ if (!ctx->mOverlay->queueBuffer(fd, offset, mDest)) {
+ ALOGE("%s: queueBuffer failed", __func__);
+ return false;
+ }
+
+ overlay::Writeback *wb = overlay::Writeback::getInstance();
+ if(!wb->writeSync()) {
+ return false;
+ }
+
+ return true;
+}
+
+int AssertiveDisplay::getDstFd() const {
+ overlay::Writeback *wb = overlay::Writeback::getInstance();
+ return wb->getDstFd();
+}
+
+uint32_t AssertiveDisplay::getDstOffset() const {
+ overlay::Writeback *wb = overlay::Writeback::getInstance();
+ return wb->getOffset();
+}
+
+}
diff --git a/msm8909/libhwcomposer/hwc_ad.h b/msm8909/libhwcomposer/hwc_ad.h
new file mode 100644
index 0000000..0be5f5d
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_ad.h
@@ -0,0 +1,66 @@
+/*
+* Copyright (c) 2013 The Linux Foundation. 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 The Linux Foundation. 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 HWC_AD_H
+#define HWC_AD_H
+
+#include <overlayUtils.h>
+#include <hwc_utils.h>
+
+struct hwc_context_t;
+
+namespace qhwc {
+
+class AssertiveDisplay {
+public:
+ AssertiveDisplay(hwc_context_t *ctx);
+ void markDoable(hwc_context_t *ctx, const hwc_display_contents_1_t* list);
+ bool prepare(hwc_context_t *ctx, const hwc_rect_t& crop,
+ const overlay::utils::Whf& whf,
+ const private_handle_t *hnd);
+ bool draw(hwc_context_t *ctx, int fd, uint32_t offset);
+ //Resets a few members on each draw round
+ void reset() { mDoable = false;
+ mDest = overlay::utils::OV_INVALID;
+ }
+ bool isDoable() const { return mDoable; }
+ int getDstFd() const;
+ uint32_t getDstOffset() const;
+
+private:
+ bool mDoable;
+ bool mTurnedOff;
+ //State of feature existence on certain devices and configs.
+ bool mFeatureEnabled;
+ overlay::utils::eDest mDest;
+ void turnOffAD();
+};
+
+}
+#endif
diff --git a/msm8909/libhwcomposer/hwc_copybit.cpp b/msm8909/libhwcomposer/hwc_copybit.cpp
new file mode 100644
index 0000000..8c1914f
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_copybit.cpp
@@ -0,0 +1,1374 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2015, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution.
+ *
+ * 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 DEBUG_COPYBIT 0
+#include <copybit.h>
+#include <utils/Timers.h>
+#include <mdp_version.h>
+#include "hwc_copybit.h"
+#include "comptype.h"
+#include "gr.h"
+#include "cb_utils.h"
+#include "cb_swap_rect.h"
+#include "math.h"
+#include "sync/sync.h"
+
+using namespace qdutils;
+namespace qhwc {
+
+struct range {
+ int current;
+ int end;
+};
+struct region_iterator : public copybit_region_t {
+
+ region_iterator(hwc_region_t region) {
+ mRegion = region;
+ r.end = (int)region.numRects;
+ r.current = 0;
+ this->next = iterate;
+ }
+
+private:
+ static int iterate(copybit_region_t const * self, copybit_rect_t* rect){
+ if (!self || !rect) {
+ ALOGE("iterate invalid parameters");
+ return 0;
+ }
+
+ region_iterator const* me =
+ static_cast<region_iterator const*>(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;
+};
+
+void CopyBit::reset() {
+ mIsModeOn = false;
+ mCopyBitDraw = false;
+}
+
+bool CopyBit::canUseCopybitForYUV(hwc_context_t *ctx) {
+ // return true for non-overlay targets
+ if(ctx->mMDP.hasOverlay && ctx->mMDP.version >= qdutils::MDP_V4_0) {
+ return false;
+ }
+ return true;
+}
+
+bool CopyBit::isSmartBlitPossible(const hwc_display_contents_1_t *list){
+ if(list->numHwLayers > 2) {
+ hwc_rect_t displayFrame0 = {0, 0, 0, 0};
+ hwc_rect_t displayFrame1 = {0, 0, 0, 0};
+ int layer0_transform = 0;
+ int layer1_transform = 0;
+ int isYuvLayer0 = 0;
+ int isYuvLayer1 = 0;
+ for (unsigned int i=0; i<list->numHwLayers -1; i++) {
+ hwc_rect_t displayFrame = list->hwLayers[i].displayFrame;
+ if (mSwapRect)
+ displayFrame = getIntersection(mDirtyRect,
+ list->hwLayers[i].displayFrame);
+ if (isValidRect(displayFrame) && !isValidRect(displayFrame0)) {
+ displayFrame0 = displayFrame;
+ private_handle_t *hnd =(private_handle_t *)list->hwLayers[i].handle;
+ isYuvLayer0 = isYuvBuffer(hnd);
+ layer0_transform = list->hwLayers[i].transform;
+ } else if(isValidRect(displayFrame)) {
+ displayFrame1 = displayFrame;
+ layer1_transform = list->hwLayers[i].transform;
+ private_handle_t *hnd =(private_handle_t *)list->hwLayers[i].handle;
+ isYuvLayer1 = isYuvBuffer(hnd);
+ break;
+ }
+ }
+ /*
+ * smart blit enable only if
+ * 1. Both layers should have same ROI.
+ * 2. Both layers can't be video layer.
+ * 3. Should not be any rotation for base RGB layer.
+ * 4. In case of base layer as video, next above RGB layer
+ * should not contains any rotation.
+ */
+ if((displayFrame0 == displayFrame1) && not (isYuvLayer1 && isYuvLayer0)) {
+ if (isYuvLayer0) {
+ if (not layer1_transform) {
+ ALOGD_IF(DEBUG_COPYBIT,"%s:Smart Bilt Possible",__FUNCTION__);
+ return true;
+ }
+ } else if (not layer0_transform) {
+ ALOGD_IF(DEBUG_COPYBIT,"%s:Smart Bilt Possible",__FUNCTION__);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool CopyBit::canUseCopybitForRGB(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list,
+ int dpy) {
+ int compositionType = qdutils::QCCompositionType::
+ getInstance().getCompositionType();
+
+ if (compositionType & qdutils::COMPOSITION_TYPE_DYN) {
+ // DYN Composition:
+ // use copybit, if (TotalRGBRenderArea < threashold * FB Area)
+ // this is done based on perf inputs in ICS
+ // TODO: Above condition needs to be re-evaluated in JB
+ int fbWidth = ctx->dpyAttr[dpy].xres;
+ int fbHeight = ctx->dpyAttr[dpy].yres;
+ unsigned int fbArea = (fbWidth * fbHeight);
+ unsigned int renderArea = getRGBRenderingArea(ctx, list);
+ ALOGD_IF (DEBUG_COPYBIT, "%s:renderArea %u, fbArea %u",
+ __FUNCTION__, renderArea, fbArea);
+ double dynThreshold = mDynThreshold;
+ if(not isSmartBlitPossible(list))
+ dynThreshold -= 1;
+
+ if (renderArea < (dynThreshold * fbArea)) {
+ return true;
+ }
+ } else if ((compositionType & qdutils::COMPOSITION_TYPE_MDP)) {
+ // MDP composition, use COPYBIT always
+ return true;
+ } else if ((compositionType & qdutils::COMPOSITION_TYPE_C2D)) {
+ // C2D composition, use COPYBIT
+ return true;
+ }
+ return false;
+}
+
+unsigned int CopyBit::getRGBRenderingArea (const hwc_context_t *ctx,
+ const hwc_display_contents_1_t *list) {
+ //Calculates total rendering area for RGB layers
+ unsigned int renderArea = 0;
+ unsigned int w=0, h=0;
+ // Skipping last layer since FrameBuffer layer should not affect
+ // which composition to choose
+ for (unsigned int i=0; i<list->numHwLayers -1; i++) {
+ private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
+ if (hnd) {
+ if (BUFFER_TYPE_UI == hnd->bufferType && !ctx->copybitDrop[i]) {
+ getLayerResolution(&list->hwLayers[i], w, h);
+ renderArea += (w*h);
+ }
+ }
+ }
+ return renderArea;
+}
+
+bool CopyBit::isLayerChanging(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list, int k) {
+ if((mLayerCache.hnd[k] != list->hwLayers[k].handle) ||
+ (mLayerCache.drop[k] != ctx->copybitDrop[k]) ||
+ (mLayerCache.displayFrame[k].left !=
+ list->hwLayers[k].displayFrame.left) ||
+ (mLayerCache.displayFrame[k].top !=
+ list->hwLayers[k].displayFrame.top) ||
+ (mLayerCache.displayFrame[k].right !=
+ list->hwLayers[k].displayFrame.right) ||
+ (mLayerCache.displayFrame[k].bottom !=
+ list->hwLayers[k].displayFrame.bottom)) {
+ return 1;
+ }
+ return 0;
+}
+
+bool CopyBit::prepareSwapRect(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list,
+ int dpy) {
+ bool canUseSwapRect = 0;
+ hwc_rect_t dirtyRect = {0, 0, 0, 0};
+ hwc_rect_t displayRect = {0, 0, 0, 0};
+ hwc_rect fullFrame = (struct hwc_rect) {0, 0,(int)ctx->dpyAttr[dpy].xres,
+ (int)ctx->dpyAttr[dpy].yres};
+ if((mLayerCache.layerCount != ctx->listStats[dpy].numAppLayers) ||
+ list->flags & HWC_GEOMETRY_CHANGED || not mSwapRectEnable) {
+ mLayerCache.reset();
+ mFbCache.reset();
+ mLayerCache.updateCounts(ctx,list,dpy);
+ mDirtyRect = displayRect;
+ return 0;
+ }
+
+ int updatingLayerCount = 0;
+ for (int k = ctx->listStats[dpy].numAppLayers-1; k >= 0 ; k--){
+ //swap rect will kick in only for single updating layer
+ if(isLayerChanging(ctx, list, k)) {
+ updatingLayerCount ++;
+ hwc_layer_1_t layer = list->hwLayers[k];
+ canUseSwapRect = 1;
+#ifdef QTI_BSP
+ dirtyRect = getUnion(dirtyRect, calculateDirtyRect(&layer,fullFrame));
+#endif
+ displayRect = getUnion(displayRect, layer.displayFrame);
+ }
+ }
+ //since we are using more than one framebuffers,we have to
+ //kick in swap rect only if we are getting continuous same
+ //dirty rect for same layer at least equal of number of
+ //framebuffers
+
+ if (canUseSwapRect || updatingLayerCount == 0) {
+ if (updatingLayerCount == 0) {
+ dirtyRect.left = INVALID_DIMENSION;
+ dirtyRect.top = INVALID_DIMENSION;
+ dirtyRect.right = INVALID_DIMENSION;
+ dirtyRect.bottom = INVALID_DIMENSION;
+ canUseSwapRect = 1;
+ }
+
+ for (int k = ctx->listStats[dpy].numAppLayers-1; k >= 0 ; k--) {
+ //disable swap rect in case of scaling and video .
+ private_handle_t *hnd =(private_handle_t *)list->hwLayers[k].handle;
+ if(needsScaling(&list->hwLayers[k])||( hnd && isYuvBuffer(hnd)) ||
+ (list->hwLayers[k].transform & HAL_TRANSFORM_ROT_90)) {
+ mFbCache.reset();
+ displayRect.bottom = 0;
+ displayRect.top = 0;
+ displayRect.right = 0;
+ displayRect.bottom = 0;
+ mDirtyRect = displayRect;
+ return 0;
+ }
+ }
+
+ if(mFbCache.getUnchangedFbDRCount(dirtyRect, displayRect) <
+ NUM_RENDER_BUFFERS) {
+ mFbCache.insertAndUpdateFbCache(dirtyRect, displayRect);
+ canUseSwapRect = 0;
+ displayRect.bottom = 0;
+ displayRect.top = 0;
+ displayRect.right = 0;
+ displayRect.bottom = 0;
+ }
+ } else {
+ mFbCache.reset();
+ canUseSwapRect = 0;
+ displayRect.bottom = 0;
+ displayRect.top = 0;
+ displayRect.right = 0;
+ displayRect.bottom = 0;
+
+ }
+ mDirtyRect = displayRect;
+ mLayerCache.updateCounts(ctx,list,dpy);
+ return canUseSwapRect;
+}
+
+bool CopyBit::prepareOverlap(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list) {
+
+ if (ctx->mMDP.version < qdutils::MDP_V4_0) {
+ ALOGE("%s: Invalid request", __FUNCTION__);
+ return false;
+ }
+
+ if (mEngine == NULL || !(validateParams(ctx, list))) {
+ ALOGE("%s: Invalid Params", __FUNCTION__);
+ return false;
+ }
+ PtorInfo* ptorInfo = &(ctx->mPtorInfo);
+
+ // Allocate render buffers if they're not allocated
+ int alignW = 0, alignH = 0;
+ int finalW = 0, finalH = 0;
+ for (int i = 0; i < ptorInfo->count; i++) {
+ int ovlapIndex = ptorInfo->layerIndex[i];
+ hwc_rect_t overlap = list->hwLayers[ovlapIndex].displayFrame;
+ // render buffer width will be the max of two layers
+ // Align Widht and height to 32, Mdp would be configured
+ // with Aligned overlap w/h
+ finalW = max(finalW, ALIGN((overlap.right - overlap.left), 32));
+ finalH += ALIGN((overlap.bottom - overlap.top), 32);
+ if(finalH > ALIGN((overlap.bottom - overlap.top), 32)) {
+ // Calculate the dest top, left will always be zero
+ ptorInfo->displayFrame[i].top = (finalH -
+ (ALIGN((overlap.bottom - overlap.top), 32)));
+ }
+ // calculate the right and bottom values
+ ptorInfo->displayFrame[i].right = ptorInfo->displayFrame[i].left +
+ (overlap.right - overlap.left);
+ ptorInfo->displayFrame[i].bottom = ptorInfo->displayFrame[i].top +
+ (overlap.bottom - overlap.top);
+ }
+
+ getBufferSizeAndDimensions(finalW, finalH, HAL_PIXEL_FORMAT_RGBA_8888,
+ alignW, alignH);
+
+ if ((mAlignedWidth != alignW) || (mAlignedHeight != alignH)) {
+ // Overlap rect has changed, so free render buffers
+ freeRenderBuffers();
+ }
+
+ int ret = allocRenderBuffers(alignW, alignH, HAL_PIXEL_FORMAT_RGBA_8888);
+
+ if (ret < 0) {
+ ALOGE("%s: Render buffer allocation failed", __FUNCTION__);
+ return false;
+ }
+
+ mAlignedWidth = alignW;
+ mAlignedHeight = alignH;
+ mCurRenderBufferIndex = (mCurRenderBufferIndex + 1) % NUM_RENDER_BUFFERS;
+ return true;
+}
+
+bool CopyBit::prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list,
+ int dpy) {
+
+ if(mEngine == NULL) {
+ // No copybit device found - cannot use copybit
+ return false;
+ }
+
+ if(ctx->mThermalBurstMode) {
+ ALOGD_IF (DEBUG_COPYBIT, "%s:Copybit failed,"
+ "Running in Thermal Burst mode",__FUNCTION__);
+ return false;
+ }
+
+ int compositionType = qdutils::QCCompositionType::
+ getInstance().getCompositionType();
+
+ if ((compositionType == qdutils::COMPOSITION_TYPE_GPU) ||
+ (compositionType == qdutils::COMPOSITION_TYPE_CPU)) {
+ //GPU/CPU composition, don't change layer composition type
+ return true;
+ }
+
+ if(!(validateParams(ctx, list))) {
+ ALOGE("%s:Invalid Params", __FUNCTION__);
+ return false;
+ }
+
+ if(ctx->listStats[dpy].skipCount) {
+ //GPU will be anyways used
+ return false;
+ }
+
+ if (ctx->listStats[dpy].numAppLayers > MAX_NUM_APP_LAYERS) {
+ // Reached max layers supported by HWC.
+ return false;
+ }
+
+ int last = (uint32_t)list->numHwLayers - 1;
+ mDirtyRect = list->hwLayers[last].displayFrame;
+ mSwapRect = prepareSwapRect(ctx, list, dpy);
+ ALOGD_IF (DEBUG_COPYBIT, "%s: mSwapRect: %d mDirtyRect: [%d, %d, %d, %d]",
+ __FUNCTION__, mSwapRect, mDirtyRect.left,
+ mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom);
+
+ bool useCopybitForYUV = canUseCopybitForYUV(ctx);
+ bool useCopybitForRGB = canUseCopybitForRGB(ctx, list, dpy);
+ LayerProp *layerProp = ctx->layerProp[dpy];
+
+ // Following are MDP3 limitations for which we
+ // need to fallback to GPU composition:
+ // 1. Plane alpha is not supported by MDP3.
+ // 2. Scaling is within range
+ if (qdutils::MDPVersion::getInstance().getMDPVersion() < 400) {
+ for (int i = ctx->listStats[dpy].numAppLayers-1; i >= 0 ; i--) {
+ int dst_h, dst_w, src_h, src_w;
+ float dx, dy;
+ if(ctx->copybitDrop[i]) {
+ continue;
+ }
+ hwc_layer_1_t *layer = (hwc_layer_1_t *) &list->hwLayers[i];
+ if (layer->planeAlpha != 0xFF)
+ return true;
+ hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
+
+ if (has90Transform(layer)) {
+ src_h = sourceCrop.right - sourceCrop.left;
+ src_w = sourceCrop.bottom - sourceCrop.top;
+ } else {
+ src_h = sourceCrop.bottom - sourceCrop.top;
+ src_w = sourceCrop.right - sourceCrop.left;
+ }
+ dst_h = layer->displayFrame.bottom - layer->displayFrame.top;
+ dst_w = layer->displayFrame.right - layer->displayFrame.left;
+
+ if(src_w <=0 || src_h<=0 ||dst_w<=0 || dst_h<=0 ) {
+ ALOGE("%s: wrong params for display screen_w=%d \
+ src_crop_width=%d screen_h=%d src_crop_height=%d",
+ __FUNCTION__, dst_w,src_w,dst_h,src_h);
+ return false;
+ }
+ dx = (float)dst_w/(float)src_w;
+ dy = (float)dst_h/(float)src_h;
+
+ float scale_factor_max = MAX_SCALE_FACTOR;
+ float scale_factor_min = MIN_SCALE_FACTOR;
+
+ if (isAlphaPresent(layer)) {
+ scale_factor_max = MAX_SCALE_FACTOR/4;
+ scale_factor_min = MIN_SCALE_FACTOR*4;
+ }
+
+ if (dx > scale_factor_max || dx < scale_factor_min)
+ return false;
+
+ if (dy > scale_factor_max || dy < scale_factor_min)
+ return false;
+ }
+ }
+
+ //Allocate render buffers if they're not allocated
+ if ((ctx->mMDP.version != qdutils::MDP_V3_0_4 &&
+#ifdef SUPPORT_BLIT_TO_FB
+ ctx->mMDP.version == qdutils::MDP_V3_0_5
+#else
+ ctx->mMDP.version != qdutils::MDP_V3_0_5
+#endif
+ ) && (useCopybitForYUV || useCopybitForRGB)) {
+ int ret = allocRenderBuffers(mAlignedWidth,
+ mAlignedHeight,
+ HAL_PIXEL_FORMAT_RGBA_8888);
+ if (ret < 0) {
+ return false;
+ } else {
+ mCurRenderBufferIndex = (mCurRenderBufferIndex + 1) %
+ NUM_RENDER_BUFFERS;
+ }
+ }
+
+ // We cannot mix copybit layer with layers marked to be drawn on FB
+ if (!useCopybitForYUV && ctx->listStats[dpy].yuvCount)
+ return true;
+
+ mCopyBitDraw = false;
+ if (useCopybitForRGB &&
+ (useCopybitForYUV || !ctx->listStats[dpy].yuvCount)) {
+ mCopyBitDraw = true;
+ // numAppLayers-1, as we iterate till 0th layer index
+ // Mark all layers to be drawn by copybit
+ for (int i = ctx->listStats[dpy].numAppLayers-1; i >= 0 ; i--) {
+ layerProp[i].mFlags |= HWC_COPYBIT;
+#ifdef QTI_BSP
+ if (ctx->mMDP.version == qdutils::MDP_V3_0_4 ||
+ ctx->mMDP.version == qdutils::MDP_V3_0_5)
+ list->hwLayers[i].compositionType = HWC_BLIT;
+ else
+#endif
+ list->hwLayers[i].compositionType = HWC_OVERLAY;
+ }
+ }
+
+ return true;
+}
+
+int CopyBit::clear (private_handle_t* hnd, hwc_rect_t& rect)
+{
+ int ret = 0;
+ copybit_rect_t clear_rect = {rect.left, rect.top,
+ rect.right,
+ rect.bottom};
+
+ copybit_image_t buf;
+ buf.w = ALIGN(getWidth(hnd),32);
+ buf.h = getHeight(hnd);
+ buf.format = hnd->format;
+ buf.base = (void *)hnd->base;
+ buf.handle = (native_handle_t *)hnd;
+
+ copybit_device_t *copybit = mEngine;
+ ret = copybit->clear(copybit, &buf, &clear_rect);
+ return ret;
+}
+
+bool CopyBit::drawUsingAppBufferComposition(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list,
+ int dpy, int *copybitFd) {
+ int layerCount = 0;
+ uint32_t last = (uint32_t)list->numHwLayers - 1;
+ hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+ private_handle_t *fbhnd = (private_handle_t *)fbLayer->handle;
+
+ if(ctx->enableABC == false)
+ return false;
+
+ if(ctx->listStats[dpy].numAppLayers > MAX_LAYERS_FOR_ABC )
+ return false;
+
+ layerCount = ctx->listStats[dpy].numAppLayers;
+ //bottom most layer should
+ //equal to FB
+ hwc_layer_1_t *tmpLayer = &list->hwLayers[0];
+ private_handle_t *hnd = (private_handle_t *)tmpLayer->handle;
+ if(hnd && fbhnd && (hnd->size == fbhnd->size) &&
+ (hnd->width == fbhnd->width) && (hnd->height == fbhnd->height)){
+ if(tmpLayer->transform ||
+ (list->flags & HWC_GEOMETRY_CHANGED) ||
+ (!(hnd->format == HAL_PIXEL_FORMAT_RGBA_8888 ||
+ hnd->format == HAL_PIXEL_FORMAT_RGBX_8888)) ||
+ (needsScaling(tmpLayer) == true)) {
+ return false;
+ }else {
+ ctx->listStats[dpy].renderBufIndexforABC = 0;
+ }
+ }
+
+ if(ctx->listStats[dpy].renderBufIndexforABC == 0) {
+ if(layerCount == 1)
+ return true;
+
+ if(layerCount == MAX_LAYERS_FOR_ABC) {
+ int abcRenderBufIdx = ctx->listStats[dpy].renderBufIndexforABC;
+ //enable ABC only for non intersecting layers.
+ hwc_rect_t displayFrame =
+ list->hwLayers[abcRenderBufIdx].displayFrame;
+ for (int i = abcRenderBufIdx + 1; i < layerCount; i++) {
+ hwc_rect_t tmpDisplayFrame = list->hwLayers[i].displayFrame;
+ hwc_rect_t result = getIntersection(displayFrame,tmpDisplayFrame);
+ if (isValidRect(result)) {
+ ctx->listStats[dpy].renderBufIndexforABC = -1;
+ return false;
+ }
+ }
+ // Pass the Acquire Fence FD to driver for base layer
+ private_handle_t *renderBuffer =
+ (private_handle_t *)list->hwLayers[abcRenderBufIdx].handle;
+ copybit_device_t *copybit = getCopyBitDevice();
+ if(list->hwLayers[abcRenderBufIdx].acquireFenceFd >=0){
+ copybit->set_sync(copybit,
+ list->hwLayers[abcRenderBufIdx].acquireFenceFd);
+ }
+ for(int i = abcRenderBufIdx + 1; i < layerCount; i++){
+ mSwapRect = 0;
+ int retVal = drawLayerUsingCopybit(ctx,
+ &(list->hwLayers[i]),renderBuffer, 0);
+ if(retVal < 0) {
+ ALOGE("%s : Copybit failed", __FUNCTION__);
+ }
+ }
+ // Get Release Fence FD of copybit for the App layer(s)
+ copybit->flush_get_fence(copybit, copybitFd);
+ close(list->hwLayers[last].acquireFenceFd);
+ list->hwLayers[last].acquireFenceFd = -1;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CopyBit::draw(hwc_context_t *ctx, hwc_display_contents_1_t *list,
+ int dpy, int32_t *fd) {
+ // draw layers marked for COPYBIT
+ int retVal = true;
+ int copybitLayerCount = 0;
+ uint32_t last = 0;
+ LayerProp *layerProp = ctx->layerProp[dpy];
+ private_handle_t *renderBuffer;
+
+ if(mCopyBitDraw == false){
+ mFbCache.reset(); // there is no layer marked for copybit
+ return false ;
+ }
+
+ if(drawUsingAppBufferComposition(ctx, list, dpy, fd)) {
+ mFbCache.reset();
+ return true;
+ }
+ //render buffer
+ if (ctx->mMDP.version == qdutils::MDP_V3_0_4 ||
+#ifdef SUPPORT_BLIT_TO_FB
+ ctx->mMDP.version != qdutils::MDP_V3_0_5
+#else
+ ctx->mMDP.version == qdutils::MDP_V3_0_5
+#endif
+ ) {
+ last = (uint32_t)list->numHwLayers - 1;
+ renderBuffer = (private_handle_t *)list->hwLayers[last].handle;
+ } else {
+ renderBuffer = getCurrentRenderBuffer();
+ }
+ if (!renderBuffer) {
+ ALOGE("%s: Render buffer layer handle is NULL", __FUNCTION__);
+ return false;
+ }
+
+ if ((ctx->mMDP.version >= qdutils::MDP_V4_0)
+#ifdef SUPPORT_BLIT_TO_FB
+ || (ctx->mMDP.version == qdutils::MDP_V3_0_5)
+#endif
+ ) {
+ //Wait for the previous frame to complete before rendering onto it
+ if(mRelFd[mCurRenderBufferIndex] >=0) {
+ sync_wait(mRelFd[mCurRenderBufferIndex], 1000);
+ close(mRelFd[mCurRenderBufferIndex]);
+ mRelFd[mCurRenderBufferIndex] = -1;
+ }
+ } else {
+ if(list->hwLayers[last].acquireFenceFd >=0) {
+ copybit_device_t *copybit = getCopyBitDevice();
+ copybit->set_sync(copybit, list->hwLayers[last].acquireFenceFd);
+ }
+ }
+
+ //if swap rect on and not getting valid dirtyRect
+ //means calling only commit without any draw. Hence avoid
+ //clear call as well.
+ if (not mSwapRect || isValidRect(mDirtyRect)) {
+ if (not CBUtils::uiClearRegion(list, ctx->mMDP.version, layerProp,
+ mDirtyRect, mEngine, renderBuffer)){
+ mSwapRect = 0;
+ }
+ }
+
+ // numAppLayers-1, as we iterate from 0th layer index with HWC_COPYBIT flag
+ for (int i = 0; i <= (ctx->listStats[dpy].numAppLayers-1); i++) {
+ if(!(layerProp[i].mFlags & HWC_COPYBIT)) {
+ ALOGD_IF(DEBUG_COPYBIT, "%s: Not Marked for copybit", __FUNCTION__);
+ continue;
+ }
+ if(ctx->copybitDrop[i]) {
+ continue;
+ }
+ int ret = -1;
+ if (list->hwLayers[i].acquireFenceFd != -1
+ && ctx->mMDP.version >= qdutils::MDP_V4_0) {
+ // Wait for acquire Fence on the App buffers.
+ ret = sync_wait(list->hwLayers[i].acquireFenceFd, 1000);
+ if(ret < 0) {
+ ALOGE("%s: sync_wait error!! error no = %d err str = %s",
+ __FUNCTION__, errno, strerror(errno));
+ }
+ close(list->hwLayers[i].acquireFenceFd);
+ list->hwLayers[i].acquireFenceFd = -1;
+ }
+ retVal = drawLayerUsingCopybit(ctx, &(list->hwLayers[i]),
+ renderBuffer, !i);
+ copybitLayerCount++;
+ if(retVal < 0) {
+ ALOGE("%s : drawLayerUsingCopybit failed", __FUNCTION__);
+ }
+ }
+
+ if (copybitLayerCount) {
+ copybit_device_t *copybit = getCopyBitDevice();
+ // Async mode
+ copybit->flush_get_fence(copybit, fd);
+ if((ctx->mMDP.version == qdutils::MDP_V3_0_4 ||
+#ifdef SUPPORT_BLIT_TO_FB
+ ctx->mMDP.version != qdutils::MDP_V3_0_5
+#else
+ ctx->mMDP.version == qdutils::MDP_V3_0_5
+#endif
+ ) && list->hwLayers[last].acquireFenceFd >= 0) {
+ close(list->hwLayers[last].acquireFenceFd);
+ list->hwLayers[last].acquireFenceFd = -1;
+ }
+ }
+ return true;
+}
+
+int CopyBit::drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
+ int fd = -1;
+ PtorInfo* ptorInfo = &(ctx->mPtorInfo);
+
+ if (ctx->mMDP.version < qdutils::MDP_V4_0) {
+ ALOGE("%s: Invalid request", __FUNCTION__);
+ return fd;
+ }
+
+ private_handle_t *renderBuffer = getCurrentRenderBuffer();
+
+ if (!renderBuffer) {
+ ALOGE("%s: Render buffer layer handle is NULL", __FUNCTION__);
+ return fd;
+ }
+
+ //Clear the transparent or left out region on the render buffer
+ LayerProp *layerProp = ctx->layerProp[0];
+ hwc_rect_t clearRegion = {0, 0, 0, 0};
+ CBUtils::uiClearRegion(list, ctx->mMDP.version, layerProp, clearRegion,
+ mEngine, renderBuffer);
+
+ int copybitLayerCount = 0;
+ for(int j = 0; j < ptorInfo->count; j++) {
+ int ovlapIndex = ptorInfo->layerIndex[j];
+ hwc_rect_t overlap = list->hwLayers[ovlapIndex].displayFrame;
+ if(j) {
+ /**
+ * It's possible that 2 PTOR layers might have overlapping.
+ * In such case, remove the intersection(again if peripheral)
+ * from the lower PTOR layer to avoid overlapping.
+ * If intersection is not on peripheral then compromise
+ * by reducing number of PTOR layers.
+ **/
+ int prevOvlapIndex = ptorInfo->layerIndex[0];
+ hwc_rect_t prevOvlap = list->hwLayers[prevOvlapIndex].displayFrame;
+ hwc_rect_t commonRect = getIntersection(prevOvlap, overlap);
+ if(isValidRect(commonRect)) {
+ overlap = deductRect(overlap, commonRect);
+ }
+ }
+
+ // Draw overlapped content of layers on render buffer
+ for (int i = 0; i <= ovlapIndex; i++) {
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ if(!isValidRect(getIntersection(layer->displayFrame,
+ overlap))) {
+ continue;
+ }
+ if ((list->hwLayers[i].acquireFenceFd != -1)) {
+ // Wait for acquire fence on the App buffers.
+ if(sync_wait(list->hwLayers[i].acquireFenceFd, 1000) < 0) {
+ ALOGE("%s: sync_wait error!! error no = %d err str = %s",
+ __FUNCTION__, errno, strerror(errno));
+ }
+ close(list->hwLayers[i].acquireFenceFd);
+ list->hwLayers[i].acquireFenceFd = -1;
+ }
+ /*
+ * Find the intersection of layer display frame with PTOR layer
+ * with respect to screen co-ordinates
+ *
+ * Calculated the destination rect by transforming the overlapping
+ * region of layer display frame with respect to PTOR display frame
+ *
+ * Transform the destination rect on to render buffer
+ * */
+ hwc_rect_t destRect = getIntersection(overlap, layer->displayFrame);
+ destRect.left = destRect.left - overlap.left +
+ ptorInfo->displayFrame[j].left;
+ destRect.right = destRect.right- overlap.left +
+ ptorInfo->displayFrame[j].left;
+ destRect.top = destRect.top - overlap.top +
+ ptorInfo->displayFrame[j].top;
+ destRect.bottom = destRect.bottom - overlap.top +
+ ptorInfo->displayFrame[j].top;
+
+ int retVal = drawRectUsingCopybit(ctx, layer, renderBuffer,
+ overlap, destRect);
+ copybitLayerCount++;
+ if(retVal < 0) {
+ ALOGE("%s: drawRectUsingCopybit failed", __FUNCTION__);
+ copybitLayerCount = 0;
+ }
+ }
+ }
+
+ if (copybitLayerCount) {
+ copybit_device_t *copybit = getCopyBitDevice();
+ copybit->flush_get_fence(copybit, &fd);
+ }
+
+ ALOGD_IF(DEBUG_COPYBIT, "%s: done! copybitLayerCount = %d", __FUNCTION__,
+ copybitLayerCount);
+ return fd;
+}
+
+int CopyBit::drawRectUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer,
+ private_handle_t *renderBuffer, hwc_rect_t overlap,
+ hwc_rect_t destRect)
+{
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+ if (!ctx) {
+ ALOGE("%s: null context ", __FUNCTION__);
+ return -1;
+ }
+
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if (!hnd) {
+ ALOGE("%s: invalid handle", __FUNCTION__);
+ return -1;
+ }
+
+ private_handle_t *dstHandle = (private_handle_t *)renderBuffer;
+ if (!dstHandle) {
+ ALOGE("%s: RenderBuffer handle is NULL", __FUNCTION__);
+ return -1;
+ }
+
+ // Set the Copybit Source
+ copybit_image_t src;
+ src.handle = (native_handle_t *)layer->handle;
+ src.w = hnd->width;
+ src.h = hnd->height;
+ src.base = (void *)hnd->base;
+ src.format = hnd->format;
+ src.horiz_padding = 0;
+ src.vert_padding = 0;
+
+
+ hwc_rect_t dispFrame = layer->displayFrame;
+ hwc_rect_t iRect = getIntersection(dispFrame, overlap);
+ hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+ qhwc::calculate_crop_rects(crop, dispFrame, iRect,
+ layer->transform);
+
+ // Copybit source rect
+ copybit_rect_t srcRect = {crop.left, crop.top, crop.right,
+ crop.bottom};
+
+ // Copybit destination rect
+ copybit_rect_t dstRect = {destRect.left, destRect.top, destRect.right,
+ destRect.bottom};
+
+ // Copybit dst
+ copybit_image_t dst;
+ dst.handle = (native_handle_t *)dstHandle;
+ dst.w = ALIGN(dstHandle->width, 32);
+ dst.h = dstHandle->height;
+ dst.base = (void *)dstHandle->base;
+ dst.format = dstHandle->format;
+
+ copybit_device_t *copybit = mEngine;
+
+ // Copybit region is the destRect
+ hwc_rect_t regRect = {dstRect.l,dstRect.t, dstRect.r, dstRect.b};
+ hwc_region_t region;
+ region.numRects = 1;
+ region.rects = ®Rect;
+ region_iterator copybitRegion(region);
+ int acquireFd = layer->acquireFenceFd;
+
+ 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->planeAlpha);
+ copybit->set_parameter(copybit, COPYBIT_BLEND_MODE, layer->blending);
+ copybit->set_parameter(copybit, COPYBIT_DITHER,
+ (dst.format == HAL_PIXEL_FORMAT_RGB_565) ? COPYBIT_ENABLE :
+ COPYBIT_DISABLE);
+ copybit->set_sync(copybit, acquireFd);
+ int err = copybit->stretch(copybit, &dst, &src, &dstRect, &srcRect,
+ ©bitRegion);
+
+ if (err < 0)
+ ALOGE("%s: copybit stretch failed",__FUNCTION__);
+
+ return err;
+}
+
+int CopyBit::drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer,
+ private_handle_t *renderBuffer, bool isFG)
+{
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+ int err = 0, acquireFd;
+ if(!ctx) {
+ ALOGE("%s: null context ", __FUNCTION__);
+ return -1;
+ }
+
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(!hnd) {
+ if (layer->flags & HWC_COLOR_FILL) { // Color layer
+ return fillColorUsingCopybit(layer, renderBuffer);
+ }
+ ALOGE("%s: invalid handle", __FUNCTION__);
+ return -1;
+ }
+
+ private_handle_t *fbHandle = (private_handle_t *)renderBuffer;
+ if(!fbHandle) {
+ ALOGE("%s: Framebuffer handle is NULL", __FUNCTION__);
+ return -1;
+ }
+ uint32_t dynamic_fps = 0;
+#ifdef DYNAMIC_FPS
+ MetaData_t *mdata = hnd ? (MetaData_t *)hnd->base_metadata : NULL;
+ if (mdata && (mdata->operation & UPDATE_REFRESH_RATE)) {
+ dynamic_fps = roundOff(mdata->refreshrate);
+ }
+#endif
+ // Set the copybit source:
+ copybit_image_t src;
+ src.w = getWidth(hnd);
+ src.h = getHeight(hnd);
+ src.format = hnd->format;
+
+ // Handle R/B swap
+ if ((layer->flags & HWC_FORMAT_RB_SWAP)) {
+ if (src.format == HAL_PIXEL_FORMAT_RGBA_8888) {
+ src.format = HAL_PIXEL_FORMAT_BGRA_8888;
+ } else if (src.format == HAL_PIXEL_FORMAT_RGBX_8888) {
+ src.format = HAL_PIXEL_FORMAT_BGRX_8888;
+ }
+ }
+
+ src.base = (void *)hnd->base;
+ src.handle = (native_handle_t *)layer->handle;
+ src.horiz_padding = src.w - getWidth(hnd);
+ // Initialize vertical padding to zero for now,
+ // this needs to change to accomodate vertical stride
+ // if needed in the future
+ src.vert_padding = 0;
+
+ int layerTransform = layer->transform ;
+ // When flip and rotation(90) are present alter the flip,
+ // as GPU is doing the flip and rotation in opposite order
+ // to that of MDP3.0
+ // For 270 degrees, we get 90 + (H+V) which is same as doing
+ // flip first and then rotation (H+V) + 90
+ if (qdutils::MDPVersion::getInstance().getMDPVersion() < 400) {
+ if (((layer->transform& HAL_TRANSFORM_FLIP_H) ||
+ (layer->transform & HAL_TRANSFORM_FLIP_V)) &&
+ (layer->transform & HAL_TRANSFORM_ROT_90) &&
+ !(layer->transform == HAL_TRANSFORM_ROT_270)){
+ if(layer->transform & HAL_TRANSFORM_FLIP_H){
+ layerTransform ^= HAL_TRANSFORM_FLIP_H;
+ layerTransform |= HAL_TRANSFORM_FLIP_V;
+ }
+ if(layer->transform & HAL_TRANSFORM_FLIP_V){
+ layerTransform ^= HAL_TRANSFORM_FLIP_V;
+ layerTransform |= HAL_TRANSFORM_FLIP_H;
+ }
+ }
+ }
+ // Copybit source rect
+ hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
+ 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};
+#ifdef QTI_BSP
+ //change src and dst with dirtyRect
+ if(mSwapRect) {
+ hwc_rect_t result = getIntersection(displayFrame, mDirtyRect);
+ if(!isValidRect(result))
+ return true;
+ dstRect.l = result.left;
+ dstRect.t = result.top;
+ dstRect.r = result.right;
+ dstRect.b = result.bottom;
+
+ srcRect.l += (result.left - displayFrame.left);
+ srcRect.t += (result.top - displayFrame.top);
+ srcRect.r -= (displayFrame.right - result.right);
+ srcRect.b -= (displayFrame.bottom - result.bottom);
+ }
+#endif
+ // Copybit dst
+ copybit_image_t dst;
+ dst.w = ALIGN(fbHandle->width,32);
+ dst.h = fbHandle->height;
+ dst.format = fbHandle->format;
+ dst.base = (void *)fbHandle->base;
+ dst.handle = (native_handle_t *)fbHandle;
+
+ copybit_device_t *copybit = mEngine;
+
+ 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;
+
+ // Copybit dst
+ 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) {
+ //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 ) {
+ ALOGE("%s: wrong params for display screen_w=%d src_crop_width=%d \
+ screen_h=%d src_crop_height=%d", __FUNCTION__, screen_w,
+ src_crop_width,screen_h,src_crop_height);
+ return -1;
+ }
+
+ float dsdx = (float)screen_w/(float)src_crop_width;
+ float dtdy = (float)screen_h/(float)src_crop_height;
+
+ float scaleLimitMax = copybitsMaxScale * copybitsMaxScale;
+ float scaleLimitMin = copybitsMinScale * copybitsMinScale;
+ if(dsdx > scaleLimitMax ||
+ dtdy > scaleLimitMax ||
+ dsdx < 1/scaleLimitMin ||
+ dtdy < 1/scaleLimitMin) {
+ ALOGW("%s: greater than max supported size dsdx=%f dtdy=%f \
+ scaleLimitMax=%f scaleLimitMin=%f", __FUNCTION__,dsdx,dtdy,
+ scaleLimitMax,1/scaleLimitMin);
+ return -1;
+ }
+ acquireFd = layer->acquireFenceFd;
+ if(dsdx > copybitsMaxScale ||
+ dtdy > copybitsMaxScale ||
+ dsdx < 1/copybitsMinScale ||
+ dtdy < 1/copybitsMinScale){
+ // The requested scale is out of the range the hardware
+ // can support.
+ ALOGD("%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);
+
+
+ int tmp_w = src_crop_width;
+ int tmp_h = src_crop_height;
+
+ if (dsdx > copybitsMaxScale)
+ tmp_w = (int)((float)src_crop_width*copybitsMaxScale);
+ if (dtdy > copybitsMaxScale)
+ tmp_h = (int)((float)src_crop_height*copybitsMaxScale);
+ // ceil the tmp_w and tmp_h value to maintain proper ratio
+ // b/w src and dst (should not cross the desired scale limit
+ // due to float -> int )
+ if (dsdx < 1/copybitsMinScale)
+ tmp_w = (int)ceil((float)src_crop_width/copybitsMinScale);
+ if (dtdy < 1/copybitsMinScale)
+ tmp_h = (int)ceil((float)src_crop_height/copybitsMinScale);
+
+ ALOGD("%s:%d::tmp_w = %d,tmp_h = %d",__FUNCTION__,__LINE__,tmp_w,tmp_h);
+
+ int usage = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP;
+ int format = fbHandle->format;
+
+ // We do not want copybit to generate alpha values from nothing
+ if (format == HAL_PIXEL_FORMAT_RGBA_8888 &&
+ src.format != HAL_PIXEL_FORMAT_RGBA_8888) {
+ format = HAL_PIXEL_FORMAT_RGBX_8888;
+ }
+ if (0 == alloc_buffer(&tmpHnd, tmp_w, tmp_h, format, usage) && tmpHnd) {
+ 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);
+ //TODO: once, we are able to read layer alpha, update this
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255);
+ copybit->set_sync(copybit, acquireFd);
+ err = copybit->stretch(copybit,&tmp_dst, &src, &tmp_rect,
+ &srcRect, &tmp_it);
+ if(err < 0){
+ ALOGE("%s:%d::tmp copybit stretch failed",__FUNCTION__,
+ __LINE__);
+ if(tmpHnd)
+ free_buffer(tmpHnd);
+ return err;
+ }
+ // use release fence as aquire fd for next stretch
+ if (ctx->mMDP.version < qdutils::MDP_V4_0) {
+ copybit->flush_get_fence(copybit, &acquireFd);
+ close(acquireFd);
+ acquireFd = -1;
+ }
+ // copy new src and src rect crop
+ src = tmp_dst;
+ srcRect = tmp_rect;
+ }
+ }
+ // Copybit region
+ hwc_region_t region = layer->visibleRegionScreen;
+ //Do not use visible regions in case of scaling
+ if (region.numRects > 1) {
+ if (needsScaling(layer)) {
+ region.numRects = 1;
+ region.rects = &layer->displayFrame;
+ }
+ }
+
+ 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,
+ layerTransform);
+ //TODO: once, we are able to read layer alpha, update this
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255);
+ copybit->set_parameter(copybit, COPYBIT_DYNAMIC_FPS, dynamic_fps);
+ copybit->set_parameter(copybit, COPYBIT_BLEND_MODE,
+ layer->blending);
+ copybit->set_parameter(copybit, COPYBIT_DITHER,
+ (dst.format == HAL_PIXEL_FORMAT_RGB_565)?
+ COPYBIT_ENABLE : COPYBIT_DISABLE);
+ copybit->set_parameter(copybit, COPYBIT_FG_LAYER,
+ (layer->blending == HWC_BLENDING_NONE || isFG ) ?
+ COPYBIT_ENABLE : COPYBIT_DISABLE);
+
+ copybit->set_parameter(copybit, COPYBIT_BLIT_TO_FRAMEBUFFER,
+ COPYBIT_ENABLE);
+ copybit->set_sync(copybit, acquireFd);
+ err = copybit->stretch(copybit, &dst, &src, &dstRect, &srcRect,
+ ©bitRegion);
+ copybit->set_parameter(copybit, COPYBIT_BLIT_TO_FRAMEBUFFER,
+ COPYBIT_DISABLE);
+
+ if(tmpHnd) {
+ if (ctx->mMDP.version < qdutils::MDP_V4_0){
+ int ret = -1, releaseFd;
+ // we need to wait for the buffer before freeing
+ copybit->flush_get_fence(copybit, &releaseFd);
+ ret = sync_wait(releaseFd, 1000);
+ if(ret < 0) {
+ ALOGE("%s: sync_wait error!! error no = %d err str = %s",
+ __FUNCTION__, errno, strerror(errno));
+ }
+ close(releaseFd);
+ }
+ free_buffer(tmpHnd);
+ }
+
+ if(err < 0)
+ ALOGE("%s: copybit stretch failed",__FUNCTION__);
+ return err;
+}
+
+int CopyBit::fillColorUsingCopybit(hwc_layer_1_t *layer,
+ private_handle_t *renderBuffer)
+{
+ if (!renderBuffer) {
+ ALOGE("%s: Render Buffer is NULL", __FUNCTION__);
+ return -1;
+ }
+
+ // Copybit dst
+ copybit_image_t dst;
+ dst.w = ALIGN(renderBuffer->width, 32);
+ dst.h = renderBuffer->height;
+ dst.format = renderBuffer->format;
+ dst.base = (void *)renderBuffer->base;
+ dst.handle = (native_handle_t *)renderBuffer;
+
+ // Copybit dst rect
+ hwc_rect_t displayFrame = layer->displayFrame;
+ copybit_rect_t dstRect = {displayFrame.left, displayFrame.top,
+ displayFrame.right, displayFrame.bottom};
+
+ uint32_t color = layer->transform;
+ copybit_device_t *copybit = mEngine;
+ copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_WIDTH,
+ renderBuffer->width);
+ copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_HEIGHT,
+ renderBuffer->height);
+ copybit->set_parameter(copybit, COPYBIT_DITHER,
+ (dst.format == HAL_PIXEL_FORMAT_RGB_565) ?
+ COPYBIT_ENABLE : COPYBIT_DISABLE);
+ copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+ copybit->set_parameter(copybit, COPYBIT_BLEND_MODE, layer->blending);
+ copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, layer->planeAlpha);
+ copybit->set_parameter(copybit, COPYBIT_BLIT_TO_FRAMEBUFFER,COPYBIT_ENABLE);
+ int res = copybit->fill_color(copybit, &dst, &dstRect, color);
+ copybit->set_parameter(copybit,COPYBIT_BLIT_TO_FRAMEBUFFER,COPYBIT_DISABLE);
+ return res;
+}
+
+void CopyBit::getLayerResolution(const hwc_layer_1_t* layer,
+ unsigned int& width, unsigned int& height)
+{
+ hwc_rect_t result = layer->displayFrame;
+ if (mSwapRect)
+ result = getIntersection(mDirtyRect, result);
+
+ width = result.right - result.left;
+ height = result.bottom - result.top;
+}
+
+bool CopyBit::validateParams(hwc_context_t *ctx,
+ const hwc_display_contents_1_t *list) {
+ //Validate parameters
+ if (!ctx) {
+ ALOGE("%s:Invalid HWC context", __FUNCTION__);
+ return false;
+ } else if (!list) {
+ ALOGE("%s:Invalid HWC layer list", __FUNCTION__);
+ return false;
+ }
+ return true;
+}
+
+
+int CopyBit::allocRenderBuffers(int w, int h, int f)
+{
+ int ret = 0;
+ for (int i = 0; i < NUM_RENDER_BUFFERS; i++) {
+ if (mRenderBuffer[i] == NULL) {
+ ret = alloc_buffer(&mRenderBuffer[i],
+ w, h, f,
+ GRALLOC_USAGE_PRIVATE_IOMMU_HEAP);
+ }
+ if(ret < 0) {
+ freeRenderBuffers();
+ break;
+ }
+ }
+ return ret;
+}
+
+void CopyBit::freeRenderBuffers()
+{
+ for (int i = 0; i < NUM_RENDER_BUFFERS; i++) {
+ if(mRenderBuffer[i]) {
+ //Since we are freeing buffer close the fence if it has a valid one.
+ if(mRelFd[i] >= 0) {
+ close(mRelFd[i]);
+ mRelFd[i] = -1;
+ }
+ free_buffer(mRenderBuffer[i]);
+ mRenderBuffer[i] = NULL;
+ }
+ }
+}
+
+private_handle_t * CopyBit::getCurrentRenderBuffer() {
+ return mRenderBuffer[mCurRenderBufferIndex];
+}
+
+void CopyBit::setReleaseFd(int fd) {
+ if(mRelFd[mCurRenderBufferIndex] >=0)
+ close(mRelFd[mCurRenderBufferIndex]);
+ mRelFd[mCurRenderBufferIndex] = dup(fd);
+}
+
+void CopyBit::setReleaseFdSync(int fd) {
+ if (mRelFd[mCurRenderBufferIndex] >=0) {
+ int ret = -1;
+ ret = sync_wait(mRelFd[mCurRenderBufferIndex], 1000);
+ if (ret < 0)
+ ALOGE("%s: sync_wait error! errno = %d, err str = %s",
+ __FUNCTION__, errno, strerror(errno));
+ close(mRelFd[mCurRenderBufferIndex]);
+ }
+ mRelFd[mCurRenderBufferIndex] = dup(fd);
+}
+
+struct copybit_device_t* CopyBit::getCopyBitDevice() {
+ return mEngine;
+}
+
+CopyBit::CopyBit(hwc_context_t *ctx, const int& dpy) : mEngine(0),
+ mIsModeOn(false), mCopyBitDraw(false), mCurRenderBufferIndex(0) {
+
+ getBufferSizeAndDimensions(ctx->dpyAttr[dpy].xres,
+ ctx->dpyAttr[dpy].yres,
+ HAL_PIXEL_FORMAT_RGBA_8888,
+ mAlignedWidth,
+ mAlignedHeight);
+
+ hw_module_t const *module;
+ for (int i = 0; i < NUM_RENDER_BUFFERS; i++) {
+ mRenderBuffer[i] = NULL;
+ mRelFd[i] = -1;
+ }
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.hwc.dynThreshold", value, "2");
+ mDynThreshold = atof(value);
+
+ property_get("debug.sf.swaprect", value, "0");
+ mSwapRectEnable = atoi(value) ? true:false ;
+ mSwapRect = 0;
+ if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
+ if(copybit_open(module, &mEngine) < 0) {
+ ALOGE("FATAL ERROR: copybit open failed.");
+ }
+ } else {
+ ALOGE("FATAL ERROR: copybit hw module not found");
+ }
+}
+
+CopyBit::~CopyBit()
+{
+ freeRenderBuffers();
+ if(mEngine)
+ {
+ copybit_close(mEngine);
+ mEngine = NULL;
+ }
+}
+CopyBit::LayerCache::LayerCache() {
+ reset();
+}
+void CopyBit::LayerCache::reset() {
+ memset(&hnd, 0, sizeof(hnd));
+ layerCount = 0;
+}
+void CopyBit::LayerCache::updateCounts(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list, int dpy)
+{
+ layerCount = ctx->listStats[dpy].numAppLayers;
+ for (int i=0; i<ctx->listStats[dpy].numAppLayers; i++){
+ hnd[i] = list->hwLayers[i].handle;
+ displayFrame[i] = list->hwLayers[i].displayFrame;
+ drop[i] = ctx->copybitDrop[i];
+ }
+}
+
+CopyBit::FbCache::FbCache() {
+ reset();
+}
+void CopyBit::FbCache::reset() {
+ memset(&FbdirtyRect, 0, sizeof(FbdirtyRect));
+ memset(&FbdisplayRect, 0, sizeof(FbdisplayRect));
+ FbIndex =0;
+}
+
+void CopyBit::FbCache::insertAndUpdateFbCache(hwc_rect_t dirtyRect,
+ hwc_rect_t displayRect) {
+ FbIndex = FbIndex % NUM_RENDER_BUFFERS;
+ FbdirtyRect[FbIndex] = dirtyRect;
+ FbdisplayRect[FbIndex] = displayRect;
+ FbIndex++;
+}
+
+int CopyBit::FbCache::getUnchangedFbDRCount(hwc_rect_t dirtyRect,
+ hwc_rect_t displayRect){
+ int sameDirtyCount = 0;
+ for (int i = 0 ; i < NUM_RENDER_BUFFERS ; i++ ){
+ if( FbdirtyRect[i] == dirtyRect &&
+ FbdisplayRect[i] == displayRect)
+ sameDirtyCount++;
+ }
+ return sameDirtyCount;
+}
+
+}; //namespace qhwc
diff --git a/msm8909/libhwcomposer/hwc_copybit.h b/msm8909/libhwcomposer/hwc_copybit.h
new file mode 100644
index 0000000..c527a4e
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_copybit.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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_COPYBIT_H
+#define HWC_COPYBIT_H
+#include "hwc_utils.h"
+
+#define NUM_RENDER_BUFFERS 3
+//These scaling factors are specific for MDP3. Normally scaling factor
+//is only 4, but copybit will create temp buffer to let it run through
+//twice
+#define MAX_SCALE_FACTOR 16
+#define MIN_SCALE_FACTOR 0.0625
+#define MAX_LAYERS_FOR_ABC 2
+#define INVALID_DIMENSION -1
+#define NO_UPDATING_LAYER -2
+namespace qhwc {
+
+class CopyBit {
+public:
+ CopyBit(hwc_context_t *ctx, const int& dpy);
+ ~CopyBit();
+ // API to get copybit engine(non static)
+ struct copybit_device_t *getCopyBitDevice();
+ //Sets up members and prepares copybit if conditions are met
+ bool prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list,
+ int dpy);
+ //Draws layer if the layer is set for copybit in prepare
+ bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list,
+ int dpy, int* fd);
+ // resets the values
+ void reset();
+
+ private_handle_t * getCurrentRenderBuffer();
+
+ void setReleaseFd(int fd);
+
+ void setReleaseFdSync(int fd);
+
+ bool prepareOverlap(hwc_context_t *ctx, hwc_display_contents_1_t *list);
+
+ int drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t *list);
+
+private:
+ /* cached data */
+ struct LayerCache {
+ int layerCount;
+ buffer_handle_t hnd[MAX_NUM_APP_LAYERS];
+ hwc_rect_t displayFrame[MAX_NUM_APP_LAYERS];
+ bool drop[MAX_NUM_APP_LAYERS];
+ /* c'tor */
+ LayerCache();
+ /* clear caching info*/
+ void reset();
+ void updateCounts(hwc_context_t *ctx, hwc_display_contents_1_t *list,
+ int dpy);
+ };
+ /* framebuffer cache*/
+ struct FbCache {
+ hwc_rect_t FbdirtyRect[NUM_RENDER_BUFFERS];
+ hwc_rect_t FbdisplayRect[NUM_RENDER_BUFFERS];
+ int FbIndex;
+ FbCache();
+ void reset();
+ void insertAndUpdateFbCache(hwc_rect_t dirtyRect,
+ hwc_rect_t displayRect);
+ int getUnchangedFbDRCount(hwc_rect_t dirtyRect,
+ hwc_rect_t displayRect);
+ };
+
+ // holds the copybit device
+ struct copybit_device_t *mEngine;
+ bool drawUsingAppBufferComposition(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list,
+ int dpy, int *fd);
+ // Helper functions for copybit composition
+ int drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer,
+ private_handle_t *renderBuffer, bool isFG);
+ // Helper function to draw copybit layer for PTOR comp
+ int drawRectUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer,
+ private_handle_t *renderBuffer, hwc_rect_t overlap,
+ hwc_rect_t destRect);
+ int fillColorUsingCopybit(hwc_layer_1_t *layer,
+ private_handle_t *renderBuffer);
+ bool canUseCopybitForYUV (hwc_context_t *ctx);
+ bool canUseCopybitForRGB (hwc_context_t *ctx,
+ hwc_display_contents_1_t *list, int dpy);
+ bool validateParams (hwc_context_t *ctx,
+ const hwc_display_contents_1_t *list);
+ //Flags if this feature is on.
+ bool mIsModeOn;
+ // flag that indicates whether CopyBit composition is enabled for this cycle
+ bool mCopyBitDraw;
+
+ unsigned int getRGBRenderingArea (const hwc_context_t *ctx,
+ const hwc_display_contents_1_t *list);
+
+ void getLayerResolution(const hwc_layer_1_t* layer,
+ unsigned int &width, unsigned int& height);
+
+ int allocRenderBuffers(int w, int h, int f);
+
+ void freeRenderBuffers();
+
+ int clear (private_handle_t* hnd, hwc_rect_t& rect);
+
+ private_handle_t* mRenderBuffer[NUM_RENDER_BUFFERS];
+
+ // Index of the current intermediate render buffer
+ int mCurRenderBufferIndex;
+
+ // Release FDs of the intermediate render buffer
+ int mRelFd[NUM_RENDER_BUFFERS];
+
+ //Dynamic composition threshold for deciding copybit usage.
+ double mDynThreshold;
+ bool mSwapRectEnable;
+ int mAlignedWidth;
+ int mAlignedHeight;
+ int mSwapRect;
+ LayerCache mLayerCache;
+ FbCache mFbCache;
+ hwc_rect_t mDirtyRect;
+ bool prepareSwapRect(hwc_context_t *ctx, hwc_display_contents_1_t *list,
+ int dpy);
+ bool isLayerChanging(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list, int k);
+ bool isSmartBlitPossible(const hwc_display_contents_1_t *list);
+};
+
+}; //namespace qhwc
+
+#endif //HWC_COPYBIT_H
diff --git a/msm8909/libhwcomposer/hwc_dump_layers.cpp b/msm8909/libhwcomposer/hwc_dump_layers.cpp
new file mode 100644
index 0000000..8ebd23c
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_dump_layers.cpp
@@ -0,0 +1,452 @@
+/*
+ * Copyright (c) 2012-2014, Linux Foundation. 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 Linux Foundation 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 LOG_TAG
+#define LOG_TAG "qsfdump"
+#endif
+#define LOG_NDEBUG 0
+#include <hwc_utils.h>
+#include <hwc_dump_layers.h>
+#include <cutils/log.h>
+#include <sys/stat.h>
+#include <comptype.h>
+#ifdef QTI_BSP
+// Ignore W(float)conversion errors for external headers
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wconversion"
+#pragma GCC diagnostic ignored "-Wfloat-conversion"
+#include <SkBitmap.h>
+#include <SkImageEncoder.h>
+#pragma GCC diagnostic pop
+#endif
+#ifdef STDC_FORMAT_MACROS
+#include <inttypes.h>
+#endif
+
+namespace qhwc {
+
+// MAX_ALLOWED_FRAMEDUMPS must be capped to (LONG_MAX - 1)
+// 60fps => 216000 frames per hour
+// Below setting of 216000 * 24 * 7 => 1 week or 168 hours of capture.
+ enum {
+ MAX_ALLOWED_FRAMEDUMPS = (216000 * 24 * 7)
+ };
+
+bool HwcDebug::sDumpEnable = false;
+
+HwcDebug::HwcDebug(uint32_t dpy):
+ mDumpCntLimRaw(0),
+ mDumpCntrRaw(1),
+ mDumpCntLimPng(0),
+ mDumpCntrPng(1),
+ mDpy(dpy) {
+ char dumpPropStr[PROPERTY_VALUE_MAX];
+ if(mDpy) {
+ strlcpy(mDisplayName, "external", sizeof(mDisplayName));
+ } else {
+ strlcpy(mDisplayName, "primary", sizeof(mDisplayName));
+ }
+ snprintf(mDumpPropKeyDisplayType, sizeof(mDumpPropKeyDisplayType),
+ "debug.sf.dump.%s", (char *)mDisplayName);
+
+ if ((property_get("debug.sf.dump.enable", dumpPropStr, NULL) > 0)) {
+ if(!strncmp(dumpPropStr, "true", strlen("true"))) {
+ sDumpEnable = true;
+ }
+ }
+}
+
+void HwcDebug::dumpLayers(hwc_display_contents_1_t* list)
+{
+ // Check need for dumping layers for debugging.
+ if (UNLIKELY(sDumpEnable) && UNLIKELY(needToDumpLayers()) && LIKELY(list)) {
+ logHwcProps(list->flags);
+ for (size_t i = 0; i < list->numHwLayers; i++) {
+ logLayer(i, list->hwLayers);
+ dumpLayer(i, list->hwLayers);
+ }
+ }
+}
+
+bool HwcDebug::needToDumpLayers()
+{
+ bool bDumpLayer = false;
+ char dumpPropStr[PROPERTY_VALUE_MAX];
+ // Enable primary dump and disable external dump by default.
+ bool bDumpEnable = !mDpy;
+ time_t timeNow;
+ tm dumpTime;
+
+ // Override the bDumpEnable based on the property value, if the property
+ // is present in the build.prop file.
+ if ((property_get(mDumpPropKeyDisplayType, dumpPropStr, NULL) > 0)) {
+ if(!strncmp(dumpPropStr, "true", strlen("true")))
+ bDumpEnable = true;
+ else
+ bDumpEnable = false;
+ }
+
+ if (false == bDumpEnable)
+ return false;
+
+ time(&timeNow);
+ localtime_r(&timeNow, &dumpTime);
+
+ if ((property_get("debug.sf.dump.png", dumpPropStr, NULL) > 0) &&
+ (strncmp(dumpPropStr, mDumpPropStrPng, PROPERTY_VALUE_MAX - 1))) {
+ // Strings exist & not equal implies it has changed, so trigger a dump
+ strlcpy(mDumpPropStrPng, dumpPropStr, sizeof(mDumpPropStrPng));
+ mDumpCntLimPng = atoi(dumpPropStr);
+ if (mDumpCntLimPng > MAX_ALLOWED_FRAMEDUMPS) {
+ ALOGW("Warning: Using debug.sf.dump.png %d (= max)",
+ MAX_ALLOWED_FRAMEDUMPS);
+ mDumpCntLimPng = MAX_ALLOWED_FRAMEDUMPS;
+ }
+ mDumpCntLimPng = (mDumpCntLimPng < 0) ? 0: mDumpCntLimPng;
+ if (mDumpCntLimPng) {
+ snprintf(mDumpDirPng, sizeof(mDumpDirPng),
+ "/data/sfdump.png.%04d.%02d.%02d.%02d.%02d.%02d",
+ dumpTime.tm_year + 1900, dumpTime.tm_mon + 1,
+ dumpTime.tm_mday, dumpTime.tm_hour,
+ dumpTime.tm_min, dumpTime.tm_sec);
+ if (0 == mkdir(mDumpDirPng, 0777))
+ mDumpCntrPng = 0;
+ else {
+ ALOGE("Error: %s. Failed to create sfdump directory: %s",
+ strerror(errno), mDumpDirPng);
+ mDumpCntrPng = mDumpCntLimPng + 1;
+ }
+ }
+ }
+
+ if (mDumpCntrPng <= mDumpCntLimPng)
+ mDumpCntrPng++;
+
+ if ((property_get("debug.sf.dump", dumpPropStr, NULL) > 0) &&
+ (strncmp(dumpPropStr, mDumpPropStrRaw, PROPERTY_VALUE_MAX - 1))) {
+ // Strings exist & not equal implies it has changed, so trigger a dump
+ strlcpy(mDumpPropStrRaw, dumpPropStr, sizeof(mDumpPropStrRaw));
+ mDumpCntLimRaw = atoi(dumpPropStr);
+ if (mDumpCntLimRaw > MAX_ALLOWED_FRAMEDUMPS) {
+ ALOGW("Warning: Using debug.sf.dump %d (= max)",
+ MAX_ALLOWED_FRAMEDUMPS);
+ mDumpCntLimRaw = MAX_ALLOWED_FRAMEDUMPS;
+ }
+ mDumpCntLimRaw = (mDumpCntLimRaw < 0) ? 0: mDumpCntLimRaw;
+ if (mDumpCntLimRaw) {
+ snprintf(mDumpDirRaw, sizeof(mDumpDirRaw),
+ "/data/sfdump.raw.%04d.%02d.%02d.%02d.%02d.%02d",
+ dumpTime.tm_year + 1900, dumpTime.tm_mon + 1,
+ dumpTime.tm_mday, dumpTime.tm_hour,
+ dumpTime.tm_min, dumpTime.tm_sec);
+ if (0 == mkdir(mDumpDirRaw, 0777))
+ mDumpCntrRaw = 0;
+ else {
+ ALOGE("Error: %s. Failed to create sfdump directory: %s",
+ strerror(errno), mDumpDirRaw);
+ mDumpCntrRaw = mDumpCntLimRaw + 1;
+ }
+ }
+ }
+
+ if (mDumpCntrRaw <= mDumpCntLimRaw)
+ mDumpCntrRaw++;
+
+ bDumpLayer = (mDumpCntLimPng || mDumpCntLimRaw)? true : false;
+ return bDumpLayer;
+}
+
+void HwcDebug::logHwcProps(uint32_t listFlags)
+{
+ static int hwcModuleCompType = -1;
+ static int sMdpCompMaxLayers = 0;
+ static String8 hwcModuleCompTypeLog("");
+ if (-1 == hwcModuleCompType) {
+ // One time stuff
+ char mdpCompPropStr[PROPERTY_VALUE_MAX];
+ if (property_get("debug.mdpcomp.maxlayer", mdpCompPropStr, NULL) > 0) {
+ sMdpCompMaxLayers = atoi(mdpCompPropStr);
+ }
+ hwcModuleCompType =
+ qdutils::QCCompositionType::getInstance().getCompositionType();
+ hwcModuleCompTypeLog.appendFormat("%s%s%s%s%s%s",
+ // Is hwc module composition type now a bit-field?!
+ (hwcModuleCompType == qdutils::COMPOSITION_TYPE_GPU)?
+ "[GPU]": "",
+ (hwcModuleCompType & qdutils::COMPOSITION_TYPE_MDP)?
+ "[MDP]": "",
+ (hwcModuleCompType & qdutils::COMPOSITION_TYPE_C2D)?
+ "[C2D]": "",
+ (hwcModuleCompType & qdutils::COMPOSITION_TYPE_CPU)?
+ "[CPU]": "",
+ (hwcModuleCompType & qdutils::COMPOSITION_TYPE_DYN)?
+ "[DYN]": "",
+ (hwcModuleCompType >= (qdutils::COMPOSITION_TYPE_DYN << 1))?
+ "[???]": "");
+ }
+ ALOGI("Display[%s] Layer[*] %s-HwcModuleCompType, %d-layer MdpComp %s",
+ mDisplayName, hwcModuleCompTypeLog.string(), sMdpCompMaxLayers,
+ (listFlags & HWC_GEOMETRY_CHANGED)? "[HwcList Geometry Changed]": "");
+}
+
+void HwcDebug::logLayer(size_t layerIndex, hwc_layer_1_t hwLayers[])
+{
+ if (NULL == hwLayers) {
+ ALOGE("Display[%s] Layer[%zu] Error. No hwc layers to log.",
+ mDisplayName, layerIndex);
+ return;
+ }
+
+ hwc_layer_1_t *layer = &hwLayers[layerIndex];
+ hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
+ hwc_rect_t displayFrame = layer->displayFrame;
+ size_t numHwcRects = layer->visibleRegionScreen.numRects;
+ hwc_rect_t const *hwcRects = layer->visibleRegionScreen.rects;
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+
+ char pixFormatStr[32] = "None";
+ String8 hwcVisRegsScrLog("[None]");
+
+ for (size_t i = 0 ; (hwcRects && (i < numHwcRects)); i++) {
+ if (0 == i)
+ hwcVisRegsScrLog.clear();
+ hwcVisRegsScrLog.appendFormat("[%dl, %dt, %dr, %db]",
+ hwcRects[i].left, hwcRects[i].top,
+ hwcRects[i].right, hwcRects[i].bottom);
+ }
+
+ if (hnd)
+ getHalPixelFormatStr(hnd->format, pixFormatStr);
+
+ // Log Line 1
+ ALOGI("Display[%s] Layer[%zu] SrcBuff[%dx%d] SrcCrop[%dl, %dt, %dr, %db] "
+ "DispFrame[%dl, %dt, %dr, %db] VisRegsScr%s", mDisplayName, layerIndex,
+ (hnd)? getWidth(hnd) : -1, (hnd)? getHeight(hnd) : -1,
+ sourceCrop.left, sourceCrop.top,
+ sourceCrop.right, sourceCrop.bottom,
+ displayFrame.left, displayFrame.top,
+ displayFrame.right, displayFrame.bottom,
+ hwcVisRegsScrLog.string());
+ // Log Line 2
+ ALOGI("Display[%s] Layer[%zu] LayerCompType = %s, Format = %s, "
+ "Orientation = %s, Flags = %s%s%s, Hints = %s%s%s, "
+ "Blending = %s%s%s", mDisplayName, layerIndex,
+ (layer->compositionType == HWC_FRAMEBUFFER)? "Framebuffer(GPU)":
+ (layer->compositionType == HWC_OVERLAY)? "Overlay":
+ (layer->compositionType == HWC_BACKGROUND)? "Background":"???",
+ pixFormatStr,
+ (layer->transform == 0)? "ROT_0":
+ (layer->transform == HWC_TRANSFORM_FLIP_H)? "FLIP_H":
+ (layer->transform == HWC_TRANSFORM_FLIP_V)? "FLIP_V":
+ (layer->transform == HWC_TRANSFORM_ROT_90)? "ROT_90":
+ "ROT_INVALID",
+ (layer->flags)? "": "[None]",
+ (layer->flags & HWC_SKIP_LAYER)? "[Skip layer]":"",
+ (layer->flags & qhwc::HWC_MDPCOMP)? "[MDP Comp]":"",
+ (layer->hints)? "":"[None]",
+ (layer->hints & HWC_HINT_TRIPLE_BUFFER)? "[Triple Buffer]":"",
+ (layer->hints & HWC_HINT_CLEAR_FB)? "[Clear FB]":"",
+ (layer->blending == HWC_BLENDING_NONE)? "[None]":"",
+ (layer->blending == HWC_BLENDING_PREMULT)? "[PreMult]":"",
+ (layer->blending == HWC_BLENDING_COVERAGE)? "[Coverage]":"");
+}
+
+void HwcDebug::dumpLayer(size_t layerIndex, hwc_layer_1_t hwLayers[])
+{
+ char dumpLogStrPng[128] = "";
+ char dumpLogStrRaw[128] = "";
+ bool needDumpPng = (mDumpCntrPng <= mDumpCntLimPng)? true:false;
+ bool needDumpRaw = (mDumpCntrRaw <= mDumpCntLimRaw)? true:false;
+
+ if (needDumpPng) {
+ snprintf(dumpLogStrPng, sizeof(dumpLogStrPng),
+ "[png-dump-frame: %03d of %03d]", mDumpCntrPng,
+ mDumpCntLimPng);
+ }
+ if (needDumpRaw) {
+ snprintf(dumpLogStrRaw, sizeof(dumpLogStrRaw),
+ "[raw-dump-frame: %03d of %03d]", mDumpCntrRaw,
+ mDumpCntLimRaw);
+ }
+
+ if (!(needDumpPng || needDumpRaw))
+ return;
+
+ if (NULL == hwLayers) {
+ ALOGE("Display[%s] Layer[%zu] %s%s Error: No hwc layers to dump.",
+ mDisplayName, layerIndex, dumpLogStrRaw, dumpLogStrPng);
+ return;
+ }
+
+ hwc_layer_1_t *layer = &hwLayers[layerIndex];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ char pixFormatStr[32] = "None";
+
+ if (NULL == hnd) {
+ ALOGI("Display[%s] Layer[%zu] %s%s Skipping dump: Bufferless layer.",
+ mDisplayName, layerIndex, dumpLogStrRaw, dumpLogStrPng);
+ return;
+ }
+
+ getHalPixelFormatStr(hnd->format, pixFormatStr);
+#ifdef QTI_BSP
+ if (needDumpPng && hnd->base) {
+ bool bResult = false;
+ char dumpFilename[PATH_MAX];
+ SkBitmap *tempSkBmp = new SkBitmap();
+ SkColorType tempSkBmpColor = kUnknown_SkColorType;
+ snprintf(dumpFilename, sizeof(dumpFilename),
+ "%s/sfdump%03d.layer%zu.%s.png", mDumpDirPng,
+ mDumpCntrPng, layerIndex, mDisplayName);
+
+ switch (hnd->format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ tempSkBmpColor = kRGBA_8888_SkColorType;
+ break;
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ tempSkBmpColor = kBGRA_8888_SkColorType;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ tempSkBmpColor = kRGB_565_SkColorType;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_888:
+ default:
+ tempSkBmpColor = kUnknown_SkColorType;
+ break;
+ }
+ if (kUnknown_SkColorType != tempSkBmpColor) {
+ tempSkBmp->setInfo(SkImageInfo::Make(getWidth(hnd), getHeight(hnd),
+ tempSkBmpColor, kUnknown_SkAlphaType), 0);
+ tempSkBmp->setPixels((void*)hnd->base);
+ bResult = SkImageEncoder::EncodeFile(dumpFilename,
+ *tempSkBmp, SkImageEncoder::kPNG_Type, 100);
+ ALOGI("Display[%s] Layer[%zu] %s Dump to %s: %s",
+ mDisplayName, layerIndex, dumpLogStrPng,
+ dumpFilename, bResult ? "Success" : "Fail");
+ } else {
+ ALOGI("Display[%s] Layer[%zu] %s Skipping dump: Unsupported layer"
+ " format %s for png encoder",
+ mDisplayName, layerIndex, dumpLogStrPng, pixFormatStr);
+ }
+ delete tempSkBmp; // Calls SkBitmap::freePixels() internally.
+ }
+#endif
+ if (needDumpRaw && hnd->base) {
+ char dumpFilename[PATH_MAX];
+ bool bResult = false;
+ snprintf(dumpFilename, sizeof(dumpFilename),
+ "%s/sfdump%03d.layer%zu.%dx%d.%s.%s.raw",
+ mDumpDirRaw, mDumpCntrRaw,
+ layerIndex, getWidth(hnd), getHeight(hnd),
+ pixFormatStr, mDisplayName);
+ FILE* fp = fopen(dumpFilename, "w+");
+ if (NULL != fp) {
+ bResult = (bool) fwrite((void*)hnd->base, hnd->size, 1, fp);
+ fclose(fp);
+ }
+ ALOGI("Display[%s] Layer[%zu] %s Dump to %s: %s",
+ mDisplayName, layerIndex, dumpLogStrRaw,
+ dumpFilename, bResult ? "Success" : "Fail");
+ }
+}
+
+void HwcDebug::getHalPixelFormatStr(int format, char pixFormatStr[])
+{
+ if (!pixFormatStr)
+ return;
+
+ switch(format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ strlcpy(pixFormatStr, "RGBA_8888", sizeof(pixFormatStr));
+ break;
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ strlcpy(pixFormatStr, "RGBX_8888", sizeof(pixFormatStr));
+ break;
+ case HAL_PIXEL_FORMAT_RGB_888:
+ strlcpy(pixFormatStr, "RGB_888", sizeof(pixFormatStr));
+ break;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ strlcpy(pixFormatStr, "RGB_565", sizeof(pixFormatStr));
+ break;
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ strlcpy(pixFormatStr, "BGRA_8888", sizeof(pixFormatStr));
+ break;
+ case HAL_PIXEL_FORMAT_YV12:
+ strlcpy(pixFormatStr, "YV12", sizeof(pixFormatStr));
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ strlcpy(pixFormatStr, "YCbCr_422_SP_NV16", sizeof(pixFormatStr));
+ break;
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ strlcpy(pixFormatStr, "YCrCb_420_SP_NV21", sizeof(pixFormatStr));
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ strlcpy(pixFormatStr, "YCbCr_422_I_YUY2", sizeof(pixFormatStr));
+ break;
+ case HAL_PIXEL_FORMAT_YCrCb_422_I:
+ strlcpy(pixFormatStr, "YCrCb_422_I_YVYU", sizeof(pixFormatStr));
+ break;
+ case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
+ strlcpy(pixFormatStr, "NV12_ENCODEABLE", sizeof(pixFormatStr));
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
+ strlcpy(pixFormatStr, "YCbCr_420_SP_TILED_TILE_4x2",
+ sizeof(pixFormatStr));
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP:
+ strlcpy(pixFormatStr, "YCbCr_420_SP", sizeof(pixFormatStr));
+ break;
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
+ strlcpy(pixFormatStr, "YCrCb_420_SP_ADRENO", sizeof(pixFormatStr));
+ break;
+ case HAL_PIXEL_FORMAT_YCrCb_422_SP:
+ strlcpy(pixFormatStr, "YCrCb_422_SP", sizeof(pixFormatStr));
+ break;
+ case HAL_PIXEL_FORMAT_R_8:
+ strlcpy(pixFormatStr, "R_8", sizeof(pixFormatStr));
+ break;
+ case HAL_PIXEL_FORMAT_RG_88:
+ strlcpy(pixFormatStr, "RG_88", sizeof(pixFormatStr));
+ break;
+ case HAL_PIXEL_FORMAT_INTERLACE:
+ strlcpy(pixFormatStr, "INTERLACE", sizeof(pixFormatStr));
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+ strlcpy(pixFormatStr, "YCbCr_420_SP_VENUS", sizeof(pixFormatStr));
+ break;
+ default:
+ size_t len = sizeof(pixFormatStr);
+ snprintf(pixFormatStr, len, "Unknown0x%X", format);
+ break;
+ }
+}
+
+} // namespace qhwc
+
diff --git a/msm8909/libhwcomposer/hwc_dump_layers.h b/msm8909/libhwcomposer/hwc_dump_layers.h
new file mode 100644
index 0000000..f0d654f
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_dump_layers.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2012-2013, Linux Foundation. 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 Linux Foundation 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 HWC_DUMP_LAYERS_H
+#define HWC_DUMP_LAYERS_H
+
+#include <gralloc_priv.h>
+#include <comptype.h>
+#include <ui/Region.h>
+#include <hardware/hwcomposer.h>
+#include <utils/String8.h>
+
+namespace qhwc {
+
+class HwcDebug {
+private:
+
+// Using static variables for layer dumping since "property_set("debug.sf.dump",
+// property)" does not work.
+ int mDumpCntLimRaw;
+ int mDumpCntrRaw;
+ char mDumpPropStrRaw[PROPERTY_VALUE_MAX];
+ char mDumpDirRaw[PATH_MAX];
+ int mDumpCntLimPng;
+ int mDumpCntrPng;
+ char mDumpPropStrPng[PROPERTY_VALUE_MAX];
+ char mDumpDirPng[PATH_MAX];
+ uint32_t mDpy;
+ char mDisplayName[PROPERTY_VALUE_MAX];
+ char mDumpPropKeyDisplayType[PROPERTY_KEY_MAX];
+ static bool sDumpEnable;
+
+public:
+ HwcDebug(uint32_t dpy);
+ ~HwcDebug() {};
+
+ /*
+ * Dump layers for debugging based on "debug.sf.dump*" system property.
+ * See needToDumpLayers() for usage.
+ *
+ * @param: list - The HWC layer-list to dump.
+ *
+ */
+ void dumpLayers(hwc_display_contents_1_t* list);
+
+/*
+ * 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.
+ *
+ * Note: Set "debug.sf.dump.primary" or "debug.sf.dump.external" as true
+ * in the device's /system/build.prop file to enable layer logging/capturing
+ * feature for primary or external respectively. The feature is disabled by
+ * default to avoid per-frame property_get() calls.
+ *
+ * To turn on layer dump, set "debug.sf.dump.enable" to true in build.prop.
+ * By default debug.sf.dump.primary will be set to true for user convenience.
+ *
+ * To turn on layer dump for primary, do,
+ * adb shell setprop debug.sf.dump.primary true
+ *
+ * To turn on layer dump for external, do,
+ * adb shell setprop debug.sf.dump.external true
+ *
+ * For example, to dump 25 frames in raw format, do,
+ * adb shell setprop debug.sf.dump 25
+ * Layers are dumped in a time-stamped location: /data/sfdump*.
+ *
+ * To dump 10 frames in png format, do,
+ * adb shell setprop debug.sf.dump.png 10
+ * To dump another 25 or so frames in raw format, do,
+ * adb shell setprop debug.sf.dump 26
+ *
+ * To turn off logcat logging of layer-info, set both properties to 0,
+ * adb shell setprop debug.sf.dump.png 0
+ * adb shell setprop debug.sf.dump 0
+ *
+ * @return: true if layers need to be dumped (or logcat-ed).
+ */
+bool needToDumpLayers();
+
+/*
+ * Log a few per-frame hwc properties into logcat.
+ *
+ * @param: listFlags - Flags used in hwcomposer's list.
+ *
+ */
+void logHwcProps(uint32_t listFlags);
+
+/*
+ * Log a layer's info into logcat.
+ *
+ * @param: layerIndex - Index of layer being dumped.
+ * @param: hwLayers - Address of hwc_layer_1_t to log and dump.
+ *
+ */
+void logLayer(size_t layerIndex, hwc_layer_1_t hwLayers[]);
+
+/*
+ * Dumps a layer buffer into raw/png files.
+ *
+ * @param: layerIndex - Index of layer being dumped.
+ * @param: hwLayers - Address of hwc_layer_1_t to log and dump.
+ *
+ */
+void dumpLayer(size_t layerIndex, hwc_layer_1_t hwLayers[]);
+
+void getHalPixelFormatStr(int format, char pixelformatstr[]);
+};
+
+} // namespace qhwc
+
+#endif /* HWC_DUMP_LAYERS_H */
diff --git a/msm8909/libhwcomposer/hwc_fbupdate.cpp b/msm8909/libhwcomposer/hwc_fbupdate.cpp
new file mode 100644
index 0000000..b003266
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_fbupdate.cpp
@@ -0,0 +1,565 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are
+ * retained for attribution purposes only.
+ *
+ * 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 DEBUG_FBUPDATE 0
+#include <cutils/properties.h>
+#include <gralloc_priv.h>
+#include <overlay.h>
+#include <overlayRotator.h>
+#include "hwc_fbupdate.h"
+#include "mdp_version.h"
+
+using namespace qdutils;
+using namespace overlay;
+using overlay::Rotator;
+using namespace overlay::utils;
+
+namespace qhwc {
+
+namespace ovutils = overlay::utils;
+
+IFBUpdate* IFBUpdate::getObject(hwc_context_t *ctx, const int& dpy) {
+ if(qdutils::MDPVersion::getInstance().isSrcSplit()) {
+ return new FBSrcSplit(ctx, dpy);
+ } else if(isDisplaySplit(ctx, dpy)) {
+ return new FBUpdateSplit(ctx, dpy);
+ }
+ return new FBUpdateNonSplit(ctx, dpy);
+}
+
+IFBUpdate::IFBUpdate(hwc_context_t *ctx, const int& dpy) : mDpy(dpy) {
+ unsigned int size = 0;
+ uint32_t xres = ctx->dpyAttr[mDpy].xres;
+ uint32_t yres = ctx->dpyAttr[mDpy].yres;
+ if (ctx->dpyAttr[dpy].customFBSize) {
+ //GPU will render and compose at new resolution
+ //So need to have FB at new resolution
+ xres = ctx->dpyAttr[mDpy].xres_new;
+ yres = ctx->dpyAttr[mDpy].yres_new;
+ }
+ getBufferAttributes((int)xres, (int)yres,
+ ctx->dpyAttr[mDpy].fbformat,
+ 0,
+ mAlignedFBWidth,
+ mAlignedFBHeight,
+ mTileEnabled, size);
+}
+
+void IFBUpdate::reset() {
+ mModeOn = false;
+ mRot = NULL;
+}
+
+bool IFBUpdate::prepareAndValidate(hwc_context_t *ctx,
+ hwc_display_contents_1 *list, int fbZorder) {
+ hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
+ mModeOn = prepare(ctx, list, layer->displayFrame, fbZorder) &&
+ ctx->mOverlay->validateAndSet(mDpy, ctx->dpyAttr[mDpy].fd);
+ return mModeOn;
+}
+
+//================= Low res====================================
+FBUpdateNonSplit::FBUpdateNonSplit(hwc_context_t *ctx, const int& dpy):
+ IFBUpdate(ctx, dpy) {}
+
+void FBUpdateNonSplit::reset() {
+ IFBUpdate::reset();
+ mDest = ovutils::OV_INVALID;
+}
+
+bool FBUpdateNonSplit::preRotateExtDisplay(hwc_context_t *ctx,
+ hwc_layer_1_t *layer,
+ ovutils::Whf &info,
+ hwc_rect_t& sourceCrop,
+ ovutils::eMdpFlags& mdpFlags,
+ int& rotFlags)
+{
+ int extOrient = getExtOrientation(ctx);
+ ovutils::eTransform orient = static_cast<ovutils::eTransform >(extOrient);
+ if(mDpy && (extOrient & HWC_TRANSFORM_ROT_90)) {
+ mRot = ctx->mRotMgr->getNext();
+ if(mRot == NULL) return false;
+ ctx->mLayerRotMap[mDpy]->add(layer, mRot);
+ // Composed FB content will have black bars, if the viewFrame of the
+ // external is different from {0, 0, fbWidth, fbHeight}, so intersect
+ // viewFrame with sourceCrop to avoid those black bars
+ sourceCrop = getIntersection(sourceCrop, ctx->mViewFrame[mDpy]);
+ //Configure rotator for pre-rotation
+ if(configRotator(mRot, info, sourceCrop, mdpFlags, orient, 0) < 0) {
+ ALOGE("%s: configRotator Failed!", __FUNCTION__);
+ mRot = NULL;
+ return false;
+ }
+ updateSource(orient, info, sourceCrop, mRot);
+ rotFlags |= ovutils::ROT_PREROTATED;
+ }
+ return true;
+}
+
+bool FBUpdateNonSplit::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
+ hwc_rect_t fbUpdatingRect, int fbZorder) {
+ if(!ctx->mMDP.hasOverlay) {
+ ALOGD_IF(DEBUG_FBUPDATE, "%s, this hw doesnt support overlays",
+ __FUNCTION__);
+ return false;
+ }
+ mModeOn = configure(ctx, list, fbUpdatingRect, fbZorder);
+ return mModeOn;
+}
+
+// Configure
+bool FBUpdateNonSplit::configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
+ hwc_rect_t fbUpdatingRect, int fbZorder) {
+ bool ret = false;
+ hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
+ if (LIKELY(ctx->mOverlay)) {
+ overlay::Overlay& ov = *(ctx->mOverlay);
+
+ ovutils::Whf info(mAlignedFBWidth, mAlignedFBHeight,
+ ovutils::getMdpFormat(ctx->dpyAttr[mDpy].fbformat,
+ mTileEnabled));
+
+ Overlay::PipeSpecs pipeSpecs;
+ pipeSpecs.formatClass = Overlay::FORMAT_RGB;
+ pipeSpecs.needsScaling = qhwc::needsScaling(layer);
+ pipeSpecs.dpy = mDpy;
+ pipeSpecs.mixer = Overlay::MIXER_DEFAULT;
+ pipeSpecs.fb = true;
+
+ ovutils::eDest dest = ov.getPipe(pipeSpecs);
+ if(dest == ovutils::OV_INVALID) { //None available
+ ALOGE("%s: No pipes available to configure fb for dpy %d",
+ __FUNCTION__, mDpy);
+ return false;
+ }
+ mDest = dest;
+
+ if((mDpy && ctx->deviceOrientation) &&
+ ctx->listStats[mDpy].isDisplayAnimating) {
+ fbZorder = 0;
+ }
+
+ ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_BLEND_FG_PREMULT;
+ ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
+
+ hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
+ hwc_rect_t displayFrame = layer->displayFrame;
+
+ // No FB update optimization on (1) Custom FB resolution,
+ // (2) External Mirror mode, (3) External orientation
+ if(!ctx->dpyAttr[mDpy].customFBSize && !ctx->mBufferMirrorMode
+ && !ctx->mExtOrientation) {
+ sourceCrop = fbUpdatingRect;
+ displayFrame = fbUpdatingRect;
+ }
+
+ int transform = layer->transform;
+ int rotFlags = ovutils::ROT_FLAGS_NONE;
+
+ ovutils::eTransform orient =
+ static_cast<ovutils::eTransform>(transform);
+ // use ext orientation if any
+ int extOrient = getExtOrientation(ctx);
+
+ // Do not use getNonWormholeRegion() function to calculate the
+ // sourceCrop during animation on external display and
+ // Dont do wormhole calculation when extorientation is set on External
+ // Dont do wormhole calculation when scaling mode is set on External
+ if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
+ sourceCrop = layer->displayFrame;
+ } else if((mDpy && !extOrient
+ && !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
+ if(ctx->mOverlay->isUIScalingOnExternalSupported() &&
+ !ctx->dpyAttr[mDpy].customFBSize) {
+ getNonWormholeRegion(list, sourceCrop);
+ displayFrame = sourceCrop;
+ }
+ }
+ calcExtDisplayPosition(ctx, NULL, mDpy, sourceCrop, displayFrame,
+ transform, orient);
+ //Store the displayFrame, will be used in getDisplayViewFrame
+ ctx->dpyAttr[mDpy].mDstRect = displayFrame;
+ setMdpFlags(ctx, layer, mdpFlags, 0, transform);
+ // For External use rotator if there is a rotation value set
+ ret = preRotateExtDisplay(ctx, layer, info,
+ sourceCrop, mdpFlags, rotFlags);
+ if(!ret) {
+ ALOGE("%s: preRotate for external Failed!", __FUNCTION__);
+ return false;
+ }
+ //For the mdp, since either we are pre-rotating or MDP does flips
+ orient = ovutils::OVERLAY_TRANSFORM_0;
+ transform = 0;
+ ovutils::PipeArgs parg(mdpFlags, info, zOrder,
+ static_cast<ovutils::eRotFlags>(rotFlags),
+ ovutils::DEFAULT_PLANE_ALPHA,
+ (ovutils::eBlending)
+ getBlending(layer->blending));
+ ret = true;
+ if(configMdp(ctx->mOverlay, parg, orient, sourceCrop, displayFrame,
+ NULL, mDest) < 0) {
+ ALOGE("%s: configMdp failed for dpy %d", __FUNCTION__, mDpy);
+ ret = false;
+ }
+ }
+ return ret;
+}
+
+bool FBUpdateNonSplit::draw(hwc_context_t *ctx, private_handle_t *hnd)
+{
+ if(!mModeOn) {
+ return true;
+ }
+ bool ret = true;
+ overlay::Overlay& ov = *(ctx->mOverlay);
+ ovutils::eDest dest = mDest;
+ int fd = hnd->fd;
+ uint32_t offset = (uint32_t)hnd->offset;
+ if(mRot) {
+ if(!mRot->queueBuffer(fd, offset))
+ return false;
+ fd = mRot->getDstMemId();
+ offset = mRot->getDstOffset();
+ }
+ if (!ov.queueBuffer(fd, offset, dest)) {
+ ALOGE("%s: queueBuffer failed for FBUpdate", __FUNCTION__);
+ ret = false;
+ }
+ return ret;
+}
+
+//================= High res====================================
+FBUpdateSplit::FBUpdateSplit(hwc_context_t *ctx, const int& dpy):
+ IFBUpdate(ctx, dpy) {}
+
+void FBUpdateSplit::reset() {
+ IFBUpdate::reset();
+ mDestLeft = ovutils::OV_INVALID;
+ mDestRight = ovutils::OV_INVALID;
+ mRot = NULL;
+}
+
+bool FBUpdateSplit::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
+ hwc_rect_t fbUpdatingRect, int fbZorder) {
+ if(!ctx->mMDP.hasOverlay) {
+ ALOGD_IF(DEBUG_FBUPDATE, "%s, this hw doesnt support overlays",
+ __FUNCTION__);
+ return false;
+ }
+ mModeOn = configure(ctx, list, fbUpdatingRect, fbZorder);
+ ALOGD_IF(DEBUG_FBUPDATE, "%s, mModeOn = %d", __FUNCTION__, mModeOn);
+ return mModeOn;
+}
+
+// Configure
+bool FBUpdateSplit::configure(hwc_context_t *ctx,
+ hwc_display_contents_1 *list, hwc_rect_t fbUpdatingRect, int fbZorder) {
+ bool ret = false;
+ hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
+ if (LIKELY(ctx->mOverlay)) {
+ ovutils::Whf info(mAlignedFBWidth, mAlignedFBHeight,
+ ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888,
+ mTileEnabled));
+
+ overlay::Overlay& ov = *(ctx->mOverlay);
+ ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_BLEND_FG_PREMULT;
+ ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
+ ovutils::eTransform orient =
+ static_cast<ovutils::eTransform>(layer->transform);
+ const int hw_w = ctx->dpyAttr[mDpy].xres;
+ const int hw_h = ctx->dpyAttr[mDpy].yres;
+ const int lSplit = getLeftSplit(ctx, mDpy);
+ mDestLeft = ovutils::OV_INVALID;
+ mDestRight = ovutils::OV_INVALID;
+ hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
+ hwc_rect_t displayFrame = layer->displayFrame;
+
+ // No FB update optimization on (1) Custom FB resolution,
+ // (2) External Mirror mode, (3) External orientation
+ if(!ctx->dpyAttr[mDpy].customFBSize && !ctx->mBufferMirrorMode
+ && !ctx->mExtOrientation) {
+ sourceCrop = fbUpdatingRect;
+ displayFrame = fbUpdatingRect;
+ }
+
+ int transform = layer->transform;
+ // use ext orientation if any
+ int extOrient = getExtOrientation(ctx);
+
+ // Do not use getNonWormholeRegion() function to calculate the
+ // sourceCrop during animation on external display and
+ // Dont do wormhole calculation when extorientation is set on External
+ // Dont do wormhole calculation when scaling mode is set on External
+ if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
+ sourceCrop = layer->displayFrame;
+ } else if((mDpy && !extOrient
+ && !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
+ if(!qdutils::MDPVersion::getInstance().is8x26() &&
+ !ctx->dpyAttr[mDpy].customFBSize) {
+ getNonWormholeRegion(list, sourceCrop);
+ displayFrame = sourceCrop;
+ }
+ }
+
+ calcExtDisplayPosition(ctx, NULL, mDpy, sourceCrop, displayFrame,
+ transform, orient);
+
+ ret = true;
+ Overlay::PipeSpecs pipeSpecs;
+ pipeSpecs.formatClass = Overlay::FORMAT_RGB;
+ pipeSpecs.needsScaling = qhwc::needsScaling(layer);
+ pipeSpecs.dpy = mDpy;
+ pipeSpecs.fb = true;
+
+ /* Configure left pipe */
+ if(displayFrame.left < lSplit) {
+ pipeSpecs.mixer = Overlay::MIXER_LEFT;
+ ovutils::eDest destL = ov.getPipe(pipeSpecs);
+ if(destL == ovutils::OV_INVALID) { //None available
+ ALOGE("%s: No pipes available to configure fb for dpy %d's left"
+ " mixer", __FUNCTION__, mDpy);
+ return false;
+ }
+
+ mDestLeft = destL;
+
+ //XXX: FB layer plane alpha is currently sent as zero from
+ //surfaceflinger
+ ovutils::PipeArgs pargL(mdpFlags,
+ info,
+ zOrder,
+ ovutils::ROT_FLAGS_NONE,
+ ovutils::DEFAULT_PLANE_ALPHA,
+ (ovutils::eBlending)
+ getBlending(layer->blending));
+ hwc_rect_t cropL = sourceCrop;
+ hwc_rect_t dstL = displayFrame;
+ hwc_rect_t scissorL = {0, 0, lSplit, hw_h };
+ qhwc::calculate_crop_rects(cropL, dstL, scissorL, 0);
+
+ if (configMdp(ctx->mOverlay, pargL, orient, cropL,
+ dstL, NULL, destL)< 0) {
+ ALOGE("%s: configMdp fails for left FB", __FUNCTION__);
+ ret = false;
+ }
+ }
+
+ /* Configure right pipe */
+ if(displayFrame.right > lSplit) {
+ pipeSpecs.mixer = Overlay::MIXER_RIGHT;
+ ovutils::eDest destR = ov.getPipe(pipeSpecs);
+ if(destR == ovutils::OV_INVALID) { //None available
+ ALOGE("%s: No pipes available to configure fb for dpy %d's"
+ " right mixer", __FUNCTION__, mDpy);
+ return false;
+ }
+
+ mDestRight = destR;
+ ovutils::eMdpFlags mdpFlagsR = mdpFlags;
+ ovutils::setMdpFlags(mdpFlagsR, ovutils::OV_MDSS_MDP_RIGHT_MIXER);
+
+ //XXX: FB layer plane alpha is currently sent as zero from
+ //surfaceflinger
+ ovutils::PipeArgs pargR(mdpFlagsR,
+ info,
+ zOrder,
+ ovutils::ROT_FLAGS_NONE,
+ ovutils::DEFAULT_PLANE_ALPHA,
+ (ovutils::eBlending)
+ getBlending(layer->blending));
+
+ hwc_rect_t cropR = sourceCrop;
+ hwc_rect_t dstR = displayFrame;
+ hwc_rect_t scissorR = {lSplit, 0, hw_w, hw_h };
+ qhwc::calculate_crop_rects(cropR, dstR, scissorR, 0);
+
+ dstR.left -= lSplit;
+ dstR.right -= lSplit;
+
+ if (configMdp(ctx->mOverlay, pargR, orient, cropR,
+ dstR, NULL, destR) < 0) {
+ ALOGE("%s: configMdp fails for right FB", __FUNCTION__);
+ ret = false;
+ }
+ }
+ }
+ return ret;
+}
+
+bool FBUpdateSplit::draw(hwc_context_t *ctx, private_handle_t *hnd)
+{
+ if(!mModeOn) {
+ return true;
+ }
+ bool ret = true;
+ overlay::Overlay& ov = *(ctx->mOverlay);
+ if(mDestLeft != ovutils::OV_INVALID) {
+ if (!ov.queueBuffer(hnd->fd, (uint32_t)hnd->offset, mDestLeft)) {
+ ALOGE("%s: queue failed for left of dpy = %d",
+ __FUNCTION__, mDpy);
+ ret = false;
+ }
+ }
+ if(mDestRight != ovutils::OV_INVALID) {
+ if (!ov.queueBuffer(hnd->fd, (uint32_t)hnd->offset, mDestRight)) {
+ ALOGE("%s: queue failed for right of dpy = %d",
+ __FUNCTION__, mDpy);
+ ret = false;
+ }
+ }
+ return ret;
+}
+
+//=================FBSrcSplit====================================
+FBSrcSplit::FBSrcSplit(hwc_context_t *ctx, const int& dpy):
+ FBUpdateSplit(ctx, dpy) {}
+
+bool FBSrcSplit::configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
+ hwc_rect_t fbUpdatingRect, int fbZorder) {
+ hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
+ overlay::Overlay& ov = *(ctx->mOverlay);
+
+ ovutils::Whf info(mAlignedFBWidth,
+ mAlignedFBHeight,
+ ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888,
+ mTileEnabled));
+
+ ovutils::eMdpFlags mdpFlags = OV_MDP_BLEND_FG_PREMULT;
+ ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
+
+ ovutils::PipeArgs parg(mdpFlags,
+ info,
+ zOrder,
+ ovutils::ROT_FLAGS_NONE,
+ ovutils::DEFAULT_PLANE_ALPHA,
+ (ovutils::eBlending)
+ getBlending(layer->blending));
+
+ hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
+ hwc_rect_t displayFrame = layer->displayFrame;
+
+ // No FB update optimization on (1) Custom FB resolution,
+ // (2) External Mirror mode, (3) External orientation
+ if(!ctx->dpyAttr[mDpy].customFBSize && !ctx->mBufferMirrorMode
+ && !ctx->mExtOrientation) {
+ sourceCrop = fbUpdatingRect;
+ displayFrame = fbUpdatingRect;
+ }
+ int transform = layer->transform;
+ ovutils::eTransform orient =
+ static_cast<ovutils::eTransform>(transform);
+
+ // use ext orientation if any
+ int extOrient = getExtOrientation(ctx);
+
+ // Do not use getNonWormholeRegion() function to calculate the
+ // sourceCrop during animation on external display and
+ // Dont do wormhole calculation when extorientation is set on External
+ // Dont do wormhole calculation when scaling mode is set on External
+ if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
+ sourceCrop = layer->displayFrame;
+ } else if((mDpy && !extOrient
+ && !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
+ if(!qdutils::MDPVersion::getInstance().is8x26() &&
+ !ctx->dpyAttr[mDpy].customFBSize) {
+ getNonWormholeRegion(list, sourceCrop);
+ displayFrame = sourceCrop;
+ }
+ }
+
+ calcExtDisplayPosition(ctx, NULL, mDpy, sourceCrop, displayFrame,
+ transform, orient);
+ hwc_rect_t cropL = sourceCrop;
+ hwc_rect_t cropR = sourceCrop;
+ hwc_rect_t dstL = displayFrame;
+ hwc_rect_t dstR = displayFrame;
+
+ //Request left pipe (or 1 by default)
+ Overlay::PipeSpecs pipeSpecs;
+ pipeSpecs.formatClass = Overlay::FORMAT_RGB;
+ pipeSpecs.needsScaling = qhwc::needsScaling(layer);
+ pipeSpecs.dpy = mDpy;
+ pipeSpecs.mixer = Overlay::MIXER_DEFAULT;
+ pipeSpecs.fb = true;
+ ovutils::eDest destL = ov.getPipe(pipeSpecs);
+ if(destL == ovutils::OV_INVALID) {
+ ALOGE("%s: No pipes available to configure fb for dpy %d's left"
+ " mixer", __FUNCTION__, mDpy);
+ return false;
+ }
+
+ ovutils::eDest destR = ovutils::OV_INVALID;
+
+ /* Use 2 pipes IF
+ a) FB's width is > Mixer width or
+ b) On primary, driver has indicated with caps to split always. This is
+ based on an empirically derived value of panel height.
+ */
+
+ const bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and
+ qdutils::MDPVersion::getInstance().isSrcSplitAlways();
+ const uint32_t lSplit = getLeftSplit(ctx, mDpy);
+ const uint32_t cropWidth = sourceCrop.right - sourceCrop.left;
+
+ if((cropWidth > qdutils::MDPVersion::getInstance().getMaxMixerWidth()) or
+ (primarySplitAlways and cropWidth > lSplit)) {
+ destR = ov.getPipe(pipeSpecs);
+ if(destR == ovutils::OV_INVALID) {
+ ALOGE("%s: No pipes available to configure fb for dpy %d's right"
+ " mixer", __FUNCTION__, mDpy);
+ return false;
+ }
+
+ if(ctx->mOverlay->comparePipePriority(destL, destR) == -1) {
+ qhwc::swap(destL, destR);
+ }
+
+ //Split crop equally when using 2 pipes
+ cropL.right = (sourceCrop.right + sourceCrop.left) / 2;
+ cropR.left = cropL.right;
+ dstL.right = (displayFrame.right + displayFrame.left) / 2;
+ dstR.left = dstL.right;
+ }
+
+ mDestLeft = destL;
+ mDestRight = destR;
+
+ if(destL != OV_INVALID) {
+ if(configMdp(ctx->mOverlay, parg, orient,
+ cropL, dstL, NULL /*metadata*/, destL) < 0) {
+ ALOGE("%s: commit failed for left mixer config", __FUNCTION__);
+ return false;
+ }
+ }
+
+ //configure right pipe
+ if(destR != OV_INVALID) {
+ if(configMdp(ctx->mOverlay, parg, orient,
+ cropR, dstR, NULL /*metadata*/, destR) < 0) {
+ ALOGE("%s: commit failed for right mixer config", __FUNCTION__);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+//---------------------------------------------------------------------
+}; //namespace qhwc
diff --git a/msm8909/libhwcomposer/hwc_fbupdate.h b/msm8909/libhwcomposer/hwc_fbupdate.h
new file mode 100644
index 0000000..545f5bd
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_fbupdate.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are
+ * retained for attribution purposes only.
+ *
+ * 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_FBUPDATE_H
+#define HWC_FBUPDATE_H
+#include "hwc_utils.h"
+#include "overlay.h"
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+namespace overlay {
+ class Rotator;
+}
+
+namespace qhwc {
+namespace ovutils = overlay::utils;
+
+//Framebuffer update Interface
+class IFBUpdate {
+public:
+ explicit IFBUpdate(hwc_context_t *ctx, const int& dpy);
+ virtual ~IFBUpdate() {};
+ // Sets up members and prepares overlay if conditions are met
+ virtual bool prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
+ hwc_rect_t fbUpdatingRect, int fbZorder) = 0;
+ virtual bool prepareAndValidate(hwc_context_t *ctx,
+ hwc_display_contents_1 *list, int fbZorder);
+ // Draws layer
+ virtual bool draw(hwc_context_t *ctx, private_handle_t *hnd) = 0;
+ //Reset values
+ virtual void reset();
+ //Factory method that returns a low-res or high-res version
+ static IFBUpdate *getObject(hwc_context_t *ctx, const int& dpy);
+
+protected:
+ const int mDpy; // display to update
+ bool mModeOn; // if prepare happened
+ overlay::Rotator *mRot;
+ int mAlignedFBWidth;
+ int mAlignedFBHeight;
+ int mTileEnabled;
+};
+
+//Non-Split panel handler.
+class FBUpdateNonSplit : public IFBUpdate {
+public:
+ explicit FBUpdateNonSplit(hwc_context_t *ctx, const int& dpy);
+ virtual ~FBUpdateNonSplit() {};
+ bool prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
+ hwc_rect_t fbUpdatingRect, int fbZorder);
+ bool draw(hwc_context_t *ctx, private_handle_t *hnd);
+ void reset();
+private:
+ bool configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
+ hwc_rect_t fbUpdatingRect, int fbZorder);
+ bool preRotateExtDisplay(hwc_context_t *ctx,
+ hwc_layer_1_t *layer,
+ ovutils::Whf &info,
+ hwc_rect_t& sourceCrop,
+ ovutils::eMdpFlags& mdpFlags,
+ int& rotFlags);
+ ovutils::eDest mDest; //pipe to draw on
+};
+
+//Split panel handler.
+class FBUpdateSplit : public IFBUpdate {
+public:
+ explicit FBUpdateSplit(hwc_context_t *ctx, const int& dpy);
+ virtual ~FBUpdateSplit() {};
+ bool prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
+ hwc_rect_t fbUpdatingRect, int fbZorder);
+ bool draw(hwc_context_t *ctx, private_handle_t *hnd);
+ void reset();
+
+protected:
+ virtual bool configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
+ hwc_rect_t fbUpdatingRect, int fbZorder);
+ ovutils::eDest mDestLeft; //left pipe to draw on
+ ovutils::eDest mDestRight; //right pipe to draw on
+};
+
+//Source Split Handler
+class FBSrcSplit : public FBUpdateSplit {
+public:
+ explicit FBSrcSplit(hwc_context_t *ctx, const int& dpy);
+ virtual ~FBSrcSplit() {};
+private:
+ bool configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
+ hwc_rect_t fbUpdatingRect, int fbZorder);
+};
+
+}; //namespace qhwc
+
+#endif //HWC_FBUPDATE_H
diff --git a/msm8909/libhwcomposer/hwc_mdpcomp.cpp b/msm8909/libhwcomposer/hwc_mdpcomp.cpp
new file mode 100644
index 0000000..9f44f32
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_mdpcomp.cpp
@@ -0,0 +1,2830 @@
+/*
+ * Copyright (C) 2012-2015, The Linux Foundation. All rights reserved.
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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 <math.h>
+#include "hwc_mdpcomp.h"
+#include <sys/ioctl.h>
+#include "hdmi.h"
+#include "qdMetaData.h"
+#include "mdp_version.h"
+#include "hwc_fbupdate.h"
+#include "hwc_ad.h"
+#include <overlayRotator.h>
+#include "hwc_copybit.h"
+#include "qd_utils.h"
+
+using namespace overlay;
+using namespace qdutils;
+using namespace overlay::utils;
+namespace ovutils = overlay::utils;
+
+namespace qhwc {
+
+//==============MDPComp========================================================
+
+IdleInvalidator *MDPComp::sIdleInvalidator = NULL;
+bool MDPComp::sIdleFallBack = false;
+bool MDPComp::sDebugLogs = false;
+bool MDPComp::sEnabled = false;
+bool MDPComp::sEnableMixedMode = true;
+int MDPComp::sSimulationFlags = 0;
+int MDPComp::sMaxPipesPerMixer = MAX_PIPES_PER_MIXER;
+bool MDPComp::sEnableYUVsplit = false;
+bool MDPComp::sSrcSplitEnabled = false;
+bool MDPComp::enablePartialUpdateForMDP3 = false;
+bool MDPComp::sIsPartialUpdateActive = true;
+MDPComp* MDPComp::getObject(hwc_context_t *ctx, const int& dpy) {
+ if(qdutils::MDPVersion::getInstance().isSrcSplit()) {
+ sSrcSplitEnabled = true;
+ return new MDPCompSrcSplit(dpy);
+ } else if(isDisplaySplit(ctx, dpy)) {
+ return new MDPCompSplit(dpy);
+ }
+ return new MDPCompNonSplit(dpy);
+}
+
+MDPComp::MDPComp(int dpy) : mDpy(dpy), mModeOn(false), mPrevModeOn(false) {
+};
+
+void MDPComp::dump(android::String8& buf, hwc_context_t *ctx)
+{
+ if(mCurrentFrame.layerCount > MAX_NUM_APP_LAYERS)
+ return;
+
+ dumpsys_log(buf,"HWC Map for Dpy: %s \n",
+ (mDpy == 0) ? "\"PRIMARY\"" :
+ (mDpy == 1) ? "\"EXTERNAL\"" : "\"VIRTUAL\"");
+ dumpsys_log(buf,"CURR_FRAME: layerCount:%2d mdpCount:%2d "
+ "fbCount:%2d \n", mCurrentFrame.layerCount,
+ mCurrentFrame.mdpCount, mCurrentFrame.fbCount);
+ dumpsys_log(buf,"needsFBRedraw:%3s pipesUsed:%2d MaxPipesPerMixer: %d \n",
+ (mCurrentFrame.needsRedraw? "YES" : "NO"),
+ mCurrentFrame.mdpCount, sMaxPipesPerMixer);
+ if(isDisplaySplit(ctx, mDpy)) {
+ dumpsys_log(buf, "Programmed ROI's: Left: [%d, %d, %d, %d] "
+ "Right: [%d, %d, %d, %d] \n",
+ ctx->listStats[mDpy].lRoi.left, ctx->listStats[mDpy].lRoi.top,
+ ctx->listStats[mDpy].lRoi.right,
+ ctx->listStats[mDpy].lRoi.bottom,
+ ctx->listStats[mDpy].rRoi.left,ctx->listStats[mDpy].rRoi.top,
+ ctx->listStats[mDpy].rRoi.right,
+ ctx->listStats[mDpy].rRoi.bottom);
+ } else {
+ dumpsys_log(buf, "Programmed ROI: [%d, %d, %d, %d] \n",
+ ctx->listStats[mDpy].lRoi.left,ctx->listStats[mDpy].lRoi.top,
+ ctx->listStats[mDpy].lRoi.right,
+ ctx->listStats[mDpy].lRoi.bottom);
+ }
+ dumpsys_log(buf," --------------------------------------------- \n");
+ dumpsys_log(buf," listIdx | cached? | mdpIndex | comptype | Z \n");
+ dumpsys_log(buf," --------------------------------------------- \n");
+ for(int index = 0; index < mCurrentFrame.layerCount; index++ )
+ dumpsys_log(buf," %7d | %7s | %8d | %9s | %2d \n",
+ index,
+ (mCurrentFrame.isFBComposed[index] ? "YES" : "NO"),
+ mCurrentFrame.layerToMDP[index],
+ (mCurrentFrame.isFBComposed[index] ?
+ (mCurrentFrame.drop[index] ? "DROP" :
+ (mCurrentFrame.needsRedraw ? "GLES" : "CACHE")) : "MDP"),
+ (mCurrentFrame.isFBComposed[index] ? mCurrentFrame.fbZ :
+ mCurrentFrame.mdpToLayer[mCurrentFrame.layerToMDP[index]].pipeInfo->zOrder));
+ dumpsys_log(buf,"\n");
+}
+
+bool MDPComp::init(hwc_context_t *ctx) {
+
+ if(!ctx) {
+ ALOGE("%s: Invalid hwc context!!",__FUNCTION__);
+ return false;
+ }
+
+ char property[PROPERTY_VALUE_MAX] = {0};
+
+ sEnabled = false;
+ if((ctx->mMDP.version >= qdutils::MDP_V4_0) &&
+ (property_get("persist.hwc.mdpcomp.enable", property, NULL) > 0) &&
+ (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+ (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+ sEnabled = true;
+ }
+
+ sEnableMixedMode = true;
+ if((property_get("debug.mdpcomp.mixedmode.disable", property, NULL) > 0) &&
+ (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+ (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+ sEnableMixedMode = false;
+ }
+
+ sMaxPipesPerMixer = MAX_PIPES_PER_MIXER;
+ if(property_get("debug.mdpcomp.maxpermixer", property, "-1") > 0) {
+ int val = atoi(property);
+ if(val >= 0)
+ sMaxPipesPerMixer = min(val, MAX_PIPES_PER_MIXER);
+ }
+
+ if(ctx->mMDP.panel != MIPI_CMD_PANEL &&
+ (ctx->mMDP.version >= qdutils::MDP_V4_0)) {
+ sIdleInvalidator = IdleInvalidator::getInstance();
+ if(sIdleInvalidator->init(timeout_handler, ctx) < 0) {
+ delete sIdleInvalidator;
+ sIdleInvalidator = NULL;
+ }
+ }
+
+ if(!qdutils::MDPVersion::getInstance().isSrcSplit() &&
+ !qdutils::MDPVersion::getInstance().isRotDownscaleEnabled() &&
+ property_get("persist.mdpcomp.4k2kSplit", property, "0") > 0 &&
+ (!strncmp(property, "1", PROPERTY_VALUE_MAX) ||
+ !strncasecmp(property,"true", PROPERTY_VALUE_MAX))) {
+ sEnableYUVsplit = true;
+ }
+
+ bool defaultPTOR = false;
+ //Enable PTOR when "persist.hwc.ptor.enable" is not defined for
+ //8x16 and 8x39 targets by default
+ if((property_get("persist.hwc.ptor.enable", property, NULL) <= 0) &&
+ (qdutils::MDPVersion::getInstance().is8x16() ||
+ qdutils::MDPVersion::getInstance().is8x39())) {
+ defaultPTOR = true;
+ }
+
+ if (defaultPTOR || (!strncasecmp(property, "true", PROPERTY_VALUE_MAX)) ||
+ (!strncmp(property, "1", PROPERTY_VALUE_MAX ))) {
+ ctx->mCopyBit[HWC_DISPLAY_PRIMARY] = new CopyBit(ctx,
+ HWC_DISPLAY_PRIMARY);
+ }
+
+ if((property_get("persist.mdp3.partialUpdate", property, NULL) <= 0) &&
+ (ctx->mMDP.version == qdutils::MDP_V3_0_5)) {
+ enablePartialUpdateForMDP3 = true;
+ }
+
+ if(!enablePartialUpdateForMDP3 &&
+ (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+ (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+ enablePartialUpdateForMDP3 = true;
+ }
+
+ int retPartialUpdatePref = getPartialUpdatePref(ctx);
+ if(retPartialUpdatePref >= 0)
+ sIsPartialUpdateActive = (retPartialUpdatePref != 0);
+
+ return true;
+}
+
+void MDPComp::reset(hwc_context_t *ctx) {
+ const int numLayers = ctx->listStats[mDpy].numAppLayers;
+ mCurrentFrame.reset(numLayers);
+ ctx->mOverlay->clear(mDpy);
+ ctx->mLayerRotMap[mDpy]->clear();
+ resetROI(ctx, mDpy);
+ memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
+ mCurrentFrame.dropCount = 0;
+}
+
+void MDPComp::reset() {
+ mPrevModeOn = mModeOn;
+ mModeOn = false;
+}
+
+void MDPComp::timeout_handler(void *udata) {
+ struct hwc_context_t* ctx = (struct hwc_context_t*)(udata);
+ bool handleTimeout = false;
+
+ if(!ctx) {
+ ALOGE("%s: received empty data in timer callback", __FUNCTION__);
+ return;
+ }
+
+ ctx->mDrawLock.lock();
+
+ /* Handle timeout event only if the previous composition
+ on any display is MDP or MIXED*/
+ for(int i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
+ if(ctx->mMDPComp[i])
+ handleTimeout =
+ ctx->mMDPComp[i]->isMDPComp() || handleTimeout;
+ }
+
+ if(!handleTimeout) {
+ ALOGD_IF(isDebug(), "%s:Do not handle this timeout", __FUNCTION__);
+ ctx->mDrawLock.unlock();
+ return;
+ }
+ if(!ctx->proc) {
+ ALOGE("%s: HWC proc not registered", __FUNCTION__);
+ ctx->mDrawLock.unlock();
+ return;
+ }
+ sIdleFallBack = true;
+ ctx->mDrawLock.unlock();
+ /* Trigger SF to redraw the current frame */
+ ctx->proc->invalidate(ctx->proc);
+}
+
+void MDPComp::setIdleTimeout(const uint32_t& timeout) {
+ enum { ONE_REFRESH_PERIOD_MS = 17, ONE_BILLION_MS = 1000000000 };
+
+ if(sIdleInvalidator) {
+ if(timeout <= ONE_REFRESH_PERIOD_MS) {
+ //If the specified timeout is < 1 draw cycle worth, "virtually"
+ //disable idle timeout. The ideal way for clients to disable
+ //timeout is to set it to 0
+ sIdleInvalidator->setIdleTimeout(ONE_BILLION_MS);
+ ALOGI("Disabled idle timeout");
+ return;
+ }
+ sIdleInvalidator->setIdleTimeout(timeout);
+ ALOGI("Idle timeout set to %u", timeout);
+ } else {
+ ALOGW("Cannot set idle timeout, IdleInvalidator not enabled");
+ }
+}
+
+void MDPComp::setMDPCompLayerFlags(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+ LayerProp *layerProp = ctx->layerProp[mDpy];
+
+ for(int index = 0; index < ctx->listStats[mDpy].numAppLayers; index++) {
+ hwc_layer_1_t* layer = &(list->hwLayers[index]);
+ if(!mCurrentFrame.isFBComposed[index]) {
+ layerProp[index].mFlags |= HWC_MDPCOMP;
+ layer->compositionType = HWC_OVERLAY;
+ layer->hints |= HWC_HINT_CLEAR_FB;
+ } else {
+ /* Drop the layer when its already present in FB OR when it lies
+ * outside frame's ROI */
+ if(!mCurrentFrame.needsRedraw || mCurrentFrame.drop[index]) {
+ layer->compositionType = HWC_OVERLAY;
+ }
+ }
+ }
+}
+
+void MDPComp::setRedraw(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+ mCurrentFrame.needsRedraw = false;
+ if(!mCachedFrame.isSameFrame(mCurrentFrame, list) ||
+ (list->flags & HWC_GEOMETRY_CHANGED) ||
+ isSkipPresent(ctx, mDpy)) {
+ mCurrentFrame.needsRedraw = true;
+ }
+}
+
+MDPComp::FrameInfo::FrameInfo() {
+ memset(&mdpToLayer, 0, sizeof(mdpToLayer));
+ reset(0);
+}
+
+void MDPComp::FrameInfo::reset(const int& numLayers) {
+ for(int i = 0; i < MAX_PIPES_PER_MIXER; i++) {
+ if(mdpToLayer[i].pipeInfo) {
+ delete mdpToLayer[i].pipeInfo;
+ mdpToLayer[i].pipeInfo = NULL;
+ //We dont own the rotator
+ mdpToLayer[i].rot = NULL;
+ }
+ }
+
+ memset(&mdpToLayer, 0, sizeof(mdpToLayer));
+ memset(&layerToMDP, -1, sizeof(layerToMDP));
+ memset(&isFBComposed, 1, sizeof(isFBComposed));
+
+ layerCount = numLayers;
+ fbCount = numLayers;
+ mdpCount = 0;
+ needsRedraw = true;
+ fbZ = -1;
+}
+
+void MDPComp::FrameInfo::map() {
+ // populate layer and MDP maps
+ int mdpIdx = 0;
+ for(int idx = 0; idx < layerCount; idx++) {
+ if(!isFBComposed[idx]) {
+ mdpToLayer[mdpIdx].listIndex = idx;
+ layerToMDP[idx] = mdpIdx++;
+ }
+ }
+}
+
+MDPComp::LayerCache::LayerCache() {
+ reset();
+}
+
+void MDPComp::LayerCache::reset() {
+ memset(&isFBComposed, true, sizeof(isFBComposed));
+ memset(&drop, false, sizeof(drop));
+ layerCount = 0;
+}
+
+void MDPComp::LayerCache::updateCounts(const FrameInfo& curFrame) {
+ layerCount = curFrame.layerCount;
+ memcpy(&isFBComposed, &curFrame.isFBComposed, sizeof(isFBComposed));
+ memcpy(&drop, &curFrame.drop, sizeof(drop));
+}
+
+bool MDPComp::LayerCache::isSameFrame(const FrameInfo& curFrame,
+ hwc_display_contents_1_t* list) {
+ if(layerCount != curFrame.layerCount)
+ return false;
+ for(int i = 0; i < curFrame.layerCount; i++) {
+ if((curFrame.isFBComposed[i] != isFBComposed[i]) ||
+ (curFrame.drop[i] != drop[i])) {
+ return false;
+ }
+ hwc_layer_1_t const* layer = &list->hwLayers[i];
+ if(curFrame.isFBComposed[i] && layerUpdating(layer)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool MDPComp::LayerCache::isSameFrame(hwc_context_t *ctx, int dpy,
+ hwc_display_contents_1_t* list) {
+
+ if(layerCount != ctx->listStats[dpy].numAppLayers)
+ return false;
+
+ if((list->flags & HWC_GEOMETRY_CHANGED) ||
+ isSkipPresent(ctx, dpy)) {
+ return false;
+ }
+
+ for(int i = 0; i < layerCount; i++) {
+ hwc_layer_1_t const* layer = &list->hwLayers[i];
+ if(layerUpdating(layer))
+ return false;
+ }
+
+ return true;
+}
+
+bool MDPComp::isSupportedForMDPComp(hwc_context_t *ctx, hwc_layer_1_t* layer) {
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if((has90Transform(layer) and (not isRotationDoable(ctx, hnd))) ||
+ (not isValidDimension(ctx,layer)) ||
+ isSkipLayer(layer)) {
+ //More conditions here, sRGB+Blend etc
+ return false;
+ }
+ return true;
+}
+
+bool MDPComp::isValidDimension(hwc_context_t *ctx, hwc_layer_1_t *layer) {
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+
+ if(!hnd) {
+ if (layer->flags & HWC_COLOR_FILL) {
+ // Color layer
+ return true;
+ }
+ ALOGD_IF(isDebug(), "%s: layer handle is NULL", __FUNCTION__);
+ return false;
+ }
+
+ //XXX: Investigate doing this with pixel phase on MDSS
+ if(!isSecureBuffer(hnd) && isNonIntegralSourceCrop(layer->sourceCropf))
+ return false;
+
+ hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+ hwc_rect_t dst = layer->displayFrame;
+ bool rotated90 = (bool)(layer->transform & HAL_TRANSFORM_ROT_90);
+ int crop_w = rotated90 ? crop.bottom - crop.top : crop.right - crop.left;
+ int crop_h = rotated90 ? crop.right - crop.left : crop.bottom - crop.top;
+ int dst_w = dst.right - dst.left;
+ int dst_h = dst.bottom - dst.top;
+ float w_scale = ((float)crop_w / (float)dst_w);
+ float h_scale = ((float)crop_h / (float)dst_h);
+ MDPVersion& mdpHw = MDPVersion::getInstance();
+
+ /* Workaround for MDP HW limitation in DSI command mode panels where
+ * FPS will not go beyond 30 if buffers on RGB pipes are of width or height
+ * less than 5 pixels
+ * There also is a HW limilation in MDP, minimum block size is 2x2
+ * Fallback to GPU if height is less than 2.
+ */
+ if(mdpHw.hasMinCropWidthLimitation() and (crop_w < 5 or crop_h < 5))
+ return false;
+
+ if((w_scale > 1.0f) || (h_scale > 1.0f)) {
+ const uint32_t maxMDPDownscale = mdpHw.getMaxMDPDownscale();
+ const float w_dscale = w_scale;
+ const float h_dscale = h_scale;
+
+ if(ctx->mMDP.version >= qdutils::MDSS_V5) {
+
+ if(!mdpHw.supportsDecimation()) {
+ /* On targets that doesnt support Decimation (eg.,8x26)
+ * maximum downscale support is overlay pipe downscale.
+ */
+ if(crop_w > (int) mdpHw.getMaxMixerWidth() ||
+ w_dscale > maxMDPDownscale ||
+ h_dscale > maxMDPDownscale)
+ return false;
+ } else {
+ // Decimation on macrotile format layers is not supported.
+ if(isTileRendered(hnd)) {
+ /* Bail out if
+ * 1. Src crop > Mixer limit on nonsplit MDPComp
+ * 2. exceeds maximum downscale limit
+ */
+ if(((crop_w > (int) mdpHw.getMaxMixerWidth()) &&
+ !sSrcSplitEnabled) ||
+ w_dscale > maxMDPDownscale ||
+ h_dscale > maxMDPDownscale) {
+ return false;
+ }
+ } else if(w_dscale > 64 || h_dscale > 64)
+ return false;
+ }
+ } else { //A-family
+ if(w_dscale > maxMDPDownscale || h_dscale > maxMDPDownscale)
+ return false;
+ }
+ }
+
+ if((w_scale < 1.0f) || (h_scale < 1.0f)) {
+ const uint32_t upscale = mdpHw.getMaxMDPUpscale();
+ const float w_uscale = 1.0f / w_scale;
+ const float h_uscale = 1.0f / h_scale;
+
+ if(w_uscale > upscale || h_uscale > upscale)
+ return false;
+ }
+
+ return true;
+}
+
+bool MDPComp::isFrameDoable(hwc_context_t *ctx) {
+ bool ret = true;
+
+ if(!isEnabled()) {
+ ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled.", __FUNCTION__);
+ ret = false;
+ } else if((qdutils::MDPVersion::getInstance().is8x26() ||
+ qdutils::MDPVersion::getInstance().is8x16() ||
+ qdutils::MDPVersion::getInstance().is8x39()) &&
+ ctx->mVideoTransFlag &&
+ isSecondaryConnected(ctx)) {
+ //1 Padding round to shift pipes across mixers
+ ALOGD_IF(isDebug(),"%s: MDP Comp. video transition padding round",
+ __FUNCTION__);
+ ret = false;
+ } else if((qdutils::MDPVersion::getInstance().is8x26() ||
+ qdutils::MDPVersion::getInstance().is8x16() ||
+ qdutils::MDPVersion::getInstance().is8x39()) &&
+ !mDpy && isSecondaryAnimating(ctx) &&
+ isYuvPresent(ctx,HWC_DISPLAY_VIRTUAL)) {
+ ALOGD_IF(isDebug(),"%s: Display animation in progress",
+ __FUNCTION__);
+ ret = false;
+ } else if(qdutils::MDPVersion::getInstance().getTotalPipes() < 8) {
+ /* TODO: freeing up all the resources only for the targets having total
+ number of pipes < 8. Need to analyze number of VIG pipes used
+ for primary in previous draw cycle and accordingly decide
+ whether to fall back to full GPU comp or video only comp
+ */
+ if(isSecondaryConfiguring(ctx)) {
+ ALOGD_IF( isDebug(),"%s: External Display connection is pending",
+ __FUNCTION__);
+ ret = false;
+ } else if(ctx->isPaddingRound) {
+ ALOGD_IF(isDebug(), "%s: padding round invoked for dpy %d",
+ __FUNCTION__,mDpy);
+ ret = false;
+ }
+ }
+ return ret;
+}
+
+void MDPCompNonSplit::trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect) {
+ hwc_rect_t roi = ctx->listStats[mDpy].lRoi;
+ fbRect = getIntersection(fbRect, roi);
+}
+
+/* 1) Identify layers that are not visible or lying outside the updating ROI and
+ * drop them from composition.
+ * 2) If we have a scaling layer which needs cropping against generated
+ * ROI, reset ROI to full resolution. */
+bool MDPCompNonSplit::validateAndApplyROI(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+ int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+ hwc_rect_t visibleRect = ctx->listStats[mDpy].lRoi;
+
+ for(int i = numAppLayers - 1; i >= 0; i--){
+ if(!isValidRect(visibleRect)) {
+ mCurrentFrame.drop[i] = true;
+ mCurrentFrame.dropCount++;
+ continue;
+ }
+
+ const hwc_layer_1_t* layer = &list->hwLayers[i];
+ hwc_rect_t dstRect = layer->displayFrame;
+ hwc_rect_t res = getIntersection(visibleRect, dstRect);
+
+ if(!isValidRect(res)) {
+ mCurrentFrame.drop[i] = true;
+ mCurrentFrame.dropCount++;
+ } else {
+ /* Reset frame ROI when any layer which needs scaling also needs ROI
+ * cropping */
+ if(!isSameRect(res, dstRect) && needsScaling (layer)) {
+ ALOGI("%s: Resetting ROI due to scaling", __FUNCTION__);
+ memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
+ mCurrentFrame.dropCount = 0;
+ return false;
+ }
+
+ /* deduct any opaque region from visibleRect */
+ if (layer->blending == HWC_BLENDING_NONE &&
+ layer->planeAlpha == 0xFF)
+ visibleRect = deductRect(visibleRect, res);
+ }
+ }
+ return true;
+}
+
+/* Calculate ROI for the frame by accounting all the layer's dispalyFrame which
+ * are updating. If DirtyRegion is applicable, calculate it by accounting all
+ * the changing layer's dirtyRegion. */
+void MDPCompNonSplit::generateROI(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+ int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+ if(!canPartialUpdate(ctx, list))
+ return;
+
+ struct hwc_rect roi = (struct hwc_rect){0, 0, 0, 0};
+ hwc_rect fullFrame = (struct hwc_rect) {0, 0,(int)ctx->dpyAttr[mDpy].xres,
+ (int)ctx->dpyAttr[mDpy].yres};
+
+ for(int index = 0; index < numAppLayers; index++ ) {
+ hwc_layer_1_t* layer = &list->hwLayers[index];
+ if (layerUpdating(layer) ||
+ isYuvBuffer((private_handle_t *)layer->handle)) {
+ hwc_rect_t dirtyRect = (struct hwc_rect){0, 0, 0, 0};;
+ if(!needsScaling(layer) && !layer->transform &&
+ (!isYuvBuffer((private_handle_t *)layer->handle)))
+ {
+ dirtyRect = calculateDirtyRect(layer, fullFrame);
+ }
+
+ roi = getUnion(roi, dirtyRect);
+ }
+ }
+
+ /* No layer is updating. Still SF wants a refresh.*/
+ if(!isValidRect(roi))
+ return;
+
+ // Align ROI coordinates to panel restrictions
+ roi = getSanitizeROI(roi, fullFrame);
+
+ ctx->listStats[mDpy].lRoi = roi;
+ if(!validateAndApplyROI(ctx, list))
+ resetROI(ctx, mDpy);
+
+ ALOGD_IF(isDebug(),"%s: generated ROI: [%d, %d, %d, %d]", __FUNCTION__,
+ ctx->listStats[mDpy].lRoi.left, ctx->listStats[mDpy].lRoi.top,
+ ctx->listStats[mDpy].lRoi.right, ctx->listStats[mDpy].lRoi.bottom);
+}
+
+void MDPCompSplit::trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect) {
+ hwc_rect l_roi = ctx->listStats[mDpy].lRoi;
+ hwc_rect r_roi = ctx->listStats[mDpy].rRoi;
+
+ hwc_rect_t l_fbRect = getIntersection(fbRect, l_roi);
+ hwc_rect_t r_fbRect = getIntersection(fbRect, r_roi);
+ fbRect = getUnion(l_fbRect, r_fbRect);
+}
+/* 1) Identify layers that are not visible or lying outside BOTH the updating
+ * ROI's and drop them from composition. If a layer is spanning across both
+ * the halves of the screen but needed by only ROI, the non-contributing
+ * half will not be programmed for MDP.
+ * 2) If we have a scaling layer which needs cropping against generated
+ * ROI, reset ROI to full resolution. */
+bool MDPCompSplit::validateAndApplyROI(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+
+ int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+
+ hwc_rect_t visibleRectL = ctx->listStats[mDpy].lRoi;
+ hwc_rect_t visibleRectR = ctx->listStats[mDpy].rRoi;
+
+ for(int i = numAppLayers - 1; i >= 0; i--){
+ if(!isValidRect(visibleRectL) && !isValidRect(visibleRectR))
+ {
+ mCurrentFrame.drop[i] = true;
+ mCurrentFrame.dropCount++;
+ continue;
+ }
+
+ const hwc_layer_1_t* layer = &list->hwLayers[i];
+ hwc_rect_t dstRect = layer->displayFrame;
+
+ hwc_rect_t l_res = getIntersection(visibleRectL, dstRect);
+ hwc_rect_t r_res = getIntersection(visibleRectR, dstRect);
+ hwc_rect_t res = getUnion(l_res, r_res);
+
+ if(!isValidRect(l_res) && !isValidRect(r_res)) {
+ mCurrentFrame.drop[i] = true;
+ mCurrentFrame.dropCount++;
+ } else {
+ /* Reset frame ROI when any layer which needs scaling also needs ROI
+ * cropping */
+ if(!isSameRect(res, dstRect) && needsScaling (layer)) {
+ memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
+ mCurrentFrame.dropCount = 0;
+ return false;
+ }
+
+ if (layer->blending == HWC_BLENDING_NONE &&
+ layer->planeAlpha == 0xFF) {
+ visibleRectL = deductRect(visibleRectL, l_res);
+ visibleRectR = deductRect(visibleRectR, r_res);
+ }
+ }
+ }
+ return true;
+}
+/* Calculate ROI for the frame by accounting all the layer's dispalyFrame which
+ * are updating. If DirtyRegion is applicable, calculate it by accounting all
+ * the changing layer's dirtyRegion. */
+void MDPCompSplit::generateROI(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+ if(!canPartialUpdate(ctx, list))
+ return;
+
+ int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+ int lSplit = getLeftSplit(ctx, mDpy);
+
+ int hw_h = (int)ctx->dpyAttr[mDpy].yres;
+ int hw_w = (int)ctx->dpyAttr[mDpy].xres;
+
+ struct hwc_rect l_frame = (struct hwc_rect){0, 0, lSplit, hw_h};
+ struct hwc_rect r_frame = (struct hwc_rect){lSplit, 0, hw_w, hw_h};
+
+ struct hwc_rect l_roi = (struct hwc_rect){0, 0, 0, 0};
+ struct hwc_rect r_roi = (struct hwc_rect){0, 0, 0, 0};
+
+ for(int index = 0; index < numAppLayers; index++ ) {
+ hwc_layer_1_t* layer = &list->hwLayers[index];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if (layerUpdating(layer) || isYuvBuffer(hnd)) {
+ hwc_rect_t l_dirtyRect = (struct hwc_rect){0, 0, 0, 0};
+ hwc_rect_t r_dirtyRect = (struct hwc_rect){0, 0, 0, 0};
+ if(!needsScaling(layer) && !layer->transform)
+ {
+ l_dirtyRect = calculateDirtyRect(layer, l_frame);
+ r_dirtyRect = calculateDirtyRect(layer, r_frame);
+ }
+ if(isValidRect(l_dirtyRect))
+ l_roi = getUnion(l_roi, l_dirtyRect);
+
+ if(isValidRect(r_dirtyRect))
+ r_roi = getUnion(r_roi, r_dirtyRect);
+ }
+ }
+
+ /* For panels that cannot accept commands in both the interfaces, we cannot
+ * send two ROI's (for each half). We merge them into single ROI and split
+ * them across lSplit for MDP mixer use. The ROI's will be merged again
+ * finally before udpating the panel in the driver. */
+ if(qdutils::MDPVersion::getInstance().needsROIMerge()) {
+ hwc_rect_t temp_roi = getUnion(l_roi, r_roi);
+ l_roi = getIntersection(temp_roi, l_frame);
+ r_roi = getIntersection(temp_roi, r_frame);
+ }
+
+ /* No layer is updating. Still SF wants a refresh. */
+ if(!isValidRect(l_roi) && !isValidRect(r_roi))
+ return;
+
+ l_roi = getSanitizeROI(l_roi, l_frame);
+ r_roi = getSanitizeROI(r_roi, r_frame);
+
+ ctx->listStats[mDpy].lRoi = l_roi;
+ ctx->listStats[mDpy].rRoi = r_roi;
+
+ if(!validateAndApplyROI(ctx, list))
+ resetROI(ctx, mDpy);
+
+ ALOGD_IF(isDebug(),"%s: generated L_ROI: [%d, %d, %d, %d]"
+ "R_ROI: [%d, %d, %d, %d]", __FUNCTION__,
+ ctx->listStats[mDpy].lRoi.left, ctx->listStats[mDpy].lRoi.top,
+ ctx->listStats[mDpy].lRoi.right, ctx->listStats[mDpy].lRoi.bottom,
+ ctx->listStats[mDpy].rRoi.left, ctx->listStats[mDpy].rRoi.top,
+ ctx->listStats[mDpy].rRoi.right, ctx->listStats[mDpy].rRoi.bottom);
+}
+
+/* Checks for conditions where all the layers marked for MDP comp cannot be
+ * bypassed. On such conditions we try to bypass atleast YUV layers */
+bool MDPComp::tryFullFrame(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list){
+
+ const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+ int priDispW = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
+
+ // Fall back to video only composition, if AIV video mode is enabled
+ if(ctx->listStats[mDpy].mAIVVideoMode) {
+ ALOGD_IF(isDebug(), "%s: AIV Video Mode enabled dpy %d",
+ __FUNCTION__, mDpy);
+ return false;
+ }
+
+ // No Idle fall back, if secure display or secure RGB layers are present or
+ // if there's only a single layer being composed
+ if(sIdleFallBack && (!ctx->listStats[mDpy].secureUI &&
+ !ctx->listStats[mDpy].secureRGBCount) &&
+ (ctx->listStats[mDpy].numAppLayers != 1)) {
+ ALOGD_IF(isDebug(), "%s: Idle fallback dpy %d",__FUNCTION__, mDpy);
+ return false;
+ }
+
+ if(!mDpy && isSecondaryAnimating(ctx) &&
+ (isYuvPresent(ctx,HWC_DISPLAY_EXTERNAL) ||
+ isYuvPresent(ctx,HWC_DISPLAY_VIRTUAL)) ) {
+ ALOGD_IF(isDebug(),"%s: Display animation in progress",
+ __FUNCTION__);
+ return false;
+ }
+
+ // if secondary is configuring or Padding round, fall back to video only
+ // composition and release all assigned non VIG pipes from primary.
+ if(isSecondaryConfiguring(ctx)) {
+ ALOGD_IF( isDebug(),"%s: External Display connection is pending",
+ __FUNCTION__);
+ return false;
+ } else if(ctx->isPaddingRound) {
+ ALOGD_IF(isDebug(), "%s: padding round invoked for dpy %d",
+ __FUNCTION__,mDpy);
+ return false;
+ }
+
+ MDPVersion& mdpHw = MDPVersion::getInstance();
+ if(mDpy > HWC_DISPLAY_PRIMARY &&
+ (priDispW > (int) mdpHw.getMaxMixerWidth()) &&
+ (ctx->dpyAttr[mDpy].xres < mdpHw.getMaxMixerWidth())) {
+ // Disable MDP comp on Secondary when the primary is highres panel and
+ // the secondary is a normal 1080p, because, MDP comp on secondary under
+ // in such usecase, decimation gets used for downscale and there will be
+ // a quality mismatch when there will be a fallback to GPU comp
+ ALOGD_IF(isDebug(), "%s: Disable MDP Compositon for Secondary Disp",
+ __FUNCTION__);
+ return false;
+ }
+
+ // check for action safe flag and MDP scaling mode which requires scaling.
+ if(ctx->dpyAttr[mDpy].mActionSafePresent
+ || ctx->dpyAttr[mDpy].mMDPScalingMode) {
+ ALOGD_IF(isDebug(), "%s: Scaling needed for this frame",__FUNCTION__);
+ return false;
+ }
+
+ for(int i = 0; i < numAppLayers; ++i) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+
+ if(has90Transform(layer) && isRotationDoable(ctx, hnd)) {
+ if(!canUseRotator(ctx, mDpy)) {
+ ALOGD_IF(isDebug(), "%s: Can't use rotator for dpy %d",
+ __FUNCTION__, mDpy);
+ return false;
+ }
+ }
+
+ //For 8x26 with panel width>1k, if RGB layer needs HFLIP fail mdp comp
+ // may not need it if Gfx pre-rotation can handle all flips & rotations
+ int transform = (layer->flags & HWC_COLOR_FILL) ? 0 : layer->transform;
+ if( mdpHw.is8x26() && (ctx->dpyAttr[mDpy].xres > 1024) &&
+ (transform & HWC_TRANSFORM_FLIP_H) && (!isYuvBuffer(hnd)))
+ return false;
+ }
+
+ if(ctx->mAD->isDoable()) {
+ return false;
+ }
+
+ //If all above hard conditions are met we can do full or partial MDP comp.
+ bool ret = false;
+ if(fullMDPComp(ctx, list)) {
+ ret = true;
+ } else if(fullMDPCompWithPTOR(ctx, list)) {
+ ret = true;
+ } else if(partialMDPComp(ctx, list)) {
+ ret = true;
+ }
+
+ return ret;
+}
+
+bool MDPComp::fullMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+
+ if(sSimulationFlags & MDPCOMP_AVOID_FULL_MDP)
+ return false;
+
+ //Will benefit presentation / secondary-only layer.
+ if((mDpy > HWC_DISPLAY_PRIMARY) &&
+ (list->numHwLayers - 1) > MAX_SEC_LAYERS) {
+ ALOGD_IF(isDebug(), "%s: Exceeds max secondary pipes",__FUNCTION__);
+ return false;
+ }
+
+ const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+ for(int i = 0; i < numAppLayers; i++) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ if(not mCurrentFrame.drop[i] and
+ not isSupportedForMDPComp(ctx, layer)) {
+ ALOGD_IF(isDebug(), "%s: Unsupported layer in list",__FUNCTION__);
+ return false;
+ }
+ }
+
+ if(!mDpy && isSecondaryConnected(ctx) &&
+ (qdutils::MDPVersion::getInstance().is8x16() ||
+ qdutils::MDPVersion::getInstance().is8x26() ||
+ qdutils::MDPVersion::getInstance().is8x39()) &&
+ isYuvPresent(ctx, HWC_DISPLAY_VIRTUAL)) {
+ ALOGD_IF(isDebug(), "%s: YUV layer present on secondary", __FUNCTION__);
+ return false;
+ }
+
+ mCurrentFrame.fbCount = 0;
+ memcpy(&mCurrentFrame.isFBComposed, &mCurrentFrame.drop,
+ sizeof(mCurrentFrame.isFBComposed));
+ mCurrentFrame.mdpCount = mCurrentFrame.layerCount - mCurrentFrame.fbCount -
+ mCurrentFrame.dropCount;
+
+ if(sEnableYUVsplit){
+ adjustForSourceSplit(ctx, list);
+ }
+
+ if(!postHeuristicsHandling(ctx, list)) {
+ ALOGD_IF(isDebug(), "post heuristic handling failed");
+ reset(ctx);
+ return false;
+ }
+ ALOGD_IF(sSimulationFlags,"%s: FULL_MDP_COMP SUCCEEDED",
+ __FUNCTION__);
+ return true;
+}
+
+/* Full MDP Composition with Peripheral Tiny Overlap Removal.
+ * MDP bandwidth limitations can be avoided, if the overlap region
+ * covered by the smallest layer at a higher z-order, gets composed
+ * by Copybit on a render buffer, which can be queued to MDP.
+ */
+bool MDPComp::fullMDPCompWithPTOR(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+
+ const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+ const int stagesForMDP = min(sMaxPipesPerMixer,
+ ctx->mOverlay->availablePipes(mDpy, Overlay::MIXER_DEFAULT));
+
+ // Hard checks where we cannot use this mode
+ if (mDpy || !ctx->mCopyBit[mDpy]) {
+ ALOGD_IF(isDebug(), "%s: Feature not supported!", __FUNCTION__);
+ return false;
+ }
+
+ // Frame level checks
+ if ((numAppLayers > stagesForMDP) || isSkipPresent(ctx, mDpy) ||
+ isYuvPresent(ctx, mDpy) || mCurrentFrame.dropCount ||
+ isSecurePresent(ctx, mDpy)) {
+ ALOGD_IF(isDebug(), "%s: Frame not supported!", __FUNCTION__);
+ return false;
+ }
+ // MDP comp checks
+ for(int i = 0; i < numAppLayers; i++) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ if(not isSupportedForMDPComp(ctx, layer)) {
+ ALOGD_IF(isDebug(), "%s: Unsupported layer in list",__FUNCTION__);
+ return false;
+ }
+ }
+
+ if(!mDpy && isSecondaryConnected(ctx) &&
+ (qdutils::MDPVersion::getInstance().is8x16() ||
+ qdutils::MDPVersion::getInstance().is8x26() ||
+ qdutils::MDPVersion::getInstance().is8x39()) &&
+ isYuvPresent(ctx, HWC_DISPLAY_VIRTUAL)) {
+ ALOGD_IF(isDebug(), "%s: YUV layer present on secondary", __FUNCTION__);
+ return false;
+ }
+
+ /* We cannot use this composition mode, if:
+ 1. A below layer needs scaling.
+ 2. Overlap is not peripheral to display.
+ 3. Overlap or a below layer has 90 degree transform.
+ 4. Overlap area > (1/3 * FrameBuffer) area, based on Perf inputs.
+ */
+
+ int minLayerIndex[MAX_PTOR_LAYERS] = { -1, -1};
+ hwc_rect_t overlapRect[MAX_PTOR_LAYERS];
+ memset(overlapRect, 0, sizeof(overlapRect));
+ int layerPixelCount, minPixelCount = 0;
+ int numPTORLayersFound = 0;
+ for (int i = numAppLayers-1; (i >= 0 &&
+ numPTORLayersFound < MAX_PTOR_LAYERS); i--) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+ hwc_rect_t dispFrame = layer->displayFrame;
+ layerPixelCount = (crop.right - crop.left) * (crop.bottom - crop.top);
+ // PTOR layer should be peripheral and cannot have transform
+ if (!isPeripheral(dispFrame, ctx->mViewFrame[mDpy]) ||
+ has90Transform(layer)) {
+ continue;
+ }
+ if((3 * (layerPixelCount + minPixelCount)) >
+ ((int)ctx->dpyAttr[mDpy].xres * (int)ctx->dpyAttr[mDpy].yres)) {
+ // Overlap area > (1/3 * FrameBuffer) area, based on Perf inputs.
+ continue;
+ }
+ bool found = false;
+ for (int j = i-1; j >= 0; j--) {
+ // Check if the layers below this layer qualifies for PTOR comp
+ hwc_layer_1_t* layer = &list->hwLayers[j];
+ hwc_rect_t disFrame = layer->displayFrame;
+ // Layer below PTOR is intersecting and has 90 degree transform or
+ // needs scaling cannot be supported.
+ if (isValidRect(getIntersection(dispFrame, disFrame))) {
+ if (has90Transform(layer) || needsScaling(layer)) {
+ found = false;
+ break;
+ }
+ found = true;
+ }
+ }
+ // Store the minLayer Index
+ if(found) {
+ minLayerIndex[numPTORLayersFound] = i;
+ overlapRect[numPTORLayersFound] = list->hwLayers[i].displayFrame;
+ minPixelCount += layerPixelCount;
+ numPTORLayersFound++;
+ }
+ }
+
+ // No overlap layers
+ if (!numPTORLayersFound)
+ return false;
+
+ // Store the displayFrame and the sourceCrops of the layers
+ hwc_rect_t displayFrame[numAppLayers];
+ hwc_rect_t sourceCrop[numAppLayers];
+ for(int i = 0; i < numAppLayers; i++) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ displayFrame[i] = layer->displayFrame;
+ sourceCrop[i] = integerizeSourceCrop(layer->sourceCropf);
+ }
+
+ /**
+ * It's possible that 2 PTOR layers might have overlapping.
+ * In such case, remove the intersection(again if peripheral)
+ * from the lower PTOR layer to avoid overlapping.
+ * If intersection is not on peripheral then compromise
+ * by reducing number of PTOR layers.
+ **/
+ hwc_rect_t commonRect = getIntersection(overlapRect[0], overlapRect[1]);
+ if(isValidRect(commonRect)) {
+ overlapRect[1] = deductRect(overlapRect[1], commonRect);
+ list->hwLayers[minLayerIndex[1]].displayFrame = overlapRect[1];
+ }
+
+ ctx->mPtorInfo.count = numPTORLayersFound;
+ for(int i = 0; i < MAX_PTOR_LAYERS; i++) {
+ ctx->mPtorInfo.layerIndex[i] = minLayerIndex[i];
+ }
+
+ if (!ctx->mCopyBit[mDpy]->prepareOverlap(ctx, list)) {
+ // reset PTOR
+ ctx->mPtorInfo.count = 0;
+ if(isValidRect(commonRect)) {
+ // If PTORs are intersecting restore displayframe of PTOR[1]
+ // before returning, as we have modified it above.
+ list->hwLayers[minLayerIndex[1]].displayFrame =
+ displayFrame[minLayerIndex[1]];
+ }
+ return false;
+ }
+ private_handle_t *renderBuf = ctx->mCopyBit[mDpy]->getCurrentRenderBuffer();
+ Whf layerWhf[numPTORLayersFound]; // To store w,h,f of PTOR layers
+
+ // Store the blending mode, planeAlpha, and transform of PTOR layers
+ int32_t blending[numPTORLayersFound];
+ uint8_t planeAlpha[numPTORLayersFound];
+ uint32_t transform[numPTORLayersFound];
+
+ for(int j = 0; j < numPTORLayersFound; j++) {
+ int index = ctx->mPtorInfo.layerIndex[j];
+
+ // Update src crop of PTOR layer
+ hwc_layer_1_t* layer = &list->hwLayers[index];
+ layer->sourceCropf.left = (float)ctx->mPtorInfo.displayFrame[j].left;
+ layer->sourceCropf.top = (float)ctx->mPtorInfo.displayFrame[j].top;
+ layer->sourceCropf.right = (float)ctx->mPtorInfo.displayFrame[j].right;
+ layer->sourceCropf.bottom =(float)ctx->mPtorInfo.displayFrame[j].bottom;
+
+ // Store & update w, h, format of PTOR layer
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ Whf whf(hnd->width, hnd->height, hnd->format, hnd->size);
+ layerWhf[j] = whf;
+ hnd->width = renderBuf->width;
+ hnd->height = renderBuf->height;
+ hnd->format = renderBuf->format;
+
+ // Store & update blending mode, planeAlpha and transform of PTOR layer
+ blending[j] = layer->blending;
+ planeAlpha[j] = layer->planeAlpha;
+ transform[j] = layer->transform;
+ layer->blending = HWC_BLENDING_NONE;
+ layer->planeAlpha = 0xFF;
+ layer->transform = 0;
+
+ // Remove overlap from crop & displayFrame of below layers
+ for (int i = 0; i < index && index !=-1; i++) {
+ layer = &list->hwLayers[i];
+ if(!isValidRect(getIntersection(layer->displayFrame,
+ overlapRect[j]))) {
+ continue;
+ }
+ // Update layer attributes
+ hwc_rect_t srcCrop = integerizeSourceCrop(layer->sourceCropf);
+ hwc_rect_t destRect = deductRect(layer->displayFrame,
+ getIntersection(layer->displayFrame, overlapRect[j]));
+ qhwc::calculate_crop_rects(srcCrop, layer->displayFrame, destRect,
+ layer->transform);
+ layer->sourceCropf.left = (float)srcCrop.left;
+ layer->sourceCropf.top = (float)srcCrop.top;
+ layer->sourceCropf.right = (float)srcCrop.right;
+ layer->sourceCropf.bottom = (float)srcCrop.bottom;
+ }
+ }
+
+ mCurrentFrame.mdpCount = numAppLayers;
+ mCurrentFrame.fbCount = 0;
+ mCurrentFrame.fbZ = -1;
+
+ for (int j = 0; j < numAppLayers; j++) {
+ if(isValidRect(list->hwLayers[j].displayFrame)) {
+ mCurrentFrame.isFBComposed[j] = false;
+ } else {
+ mCurrentFrame.mdpCount--;
+ mCurrentFrame.drop[j] = true;
+ }
+ }
+
+ bool result = postHeuristicsHandling(ctx, list);
+
+ // Restore layer attributes
+ for(int i = 0; i < numAppLayers; i++) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ layer->displayFrame = displayFrame[i];
+ layer->sourceCropf.left = (float)sourceCrop[i].left;
+ layer->sourceCropf.top = (float)sourceCrop[i].top;
+ layer->sourceCropf.right = (float)sourceCrop[i].right;
+ layer->sourceCropf.bottom = (float)sourceCrop[i].bottom;
+ }
+
+ // Restore w,h,f, blending attributes, and transform of PTOR layers
+ for (int i = 0; i < numPTORLayersFound; i++) {
+ int idx = ctx->mPtorInfo.layerIndex[i];
+ hwc_layer_1_t* layer = &list->hwLayers[idx];
+ private_handle_t *hnd = (private_handle_t *)list->hwLayers[idx].handle;
+ hnd->width = layerWhf[i].w;
+ hnd->height = layerWhf[i].h;
+ hnd->format = layerWhf[i].format;
+ layer->blending = blending[i];
+ layer->planeAlpha = planeAlpha[i];
+ layer->transform = transform[i];
+ }
+
+ if (!result) {
+ // reset PTOR
+ ctx->mPtorInfo.count = 0;
+ reset(ctx);
+ } else {
+ ALOGD_IF(isDebug(), "%s: PTOR Indexes: %d and %d", __FUNCTION__,
+ ctx->mPtorInfo.layerIndex[0], ctx->mPtorInfo.layerIndex[1]);
+ }
+
+ ALOGD_IF(isDebug(), "%s: Postheuristics %s!", __FUNCTION__,
+ (result ? "successful" : "failed"));
+ return result;
+}
+
+bool MDPComp::partialMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list)
+{
+ if(!sEnableMixedMode || !isAlphaPresentinFB(ctx, mDpy)) {
+ //Mixed mode is disabled/can't be used. No need to even try caching.
+ return false;
+ }
+
+ bool ret = false;
+ if(isSkipPresent(ctx, mDpy) or list->flags & HWC_GEOMETRY_CHANGED) {
+ //Try load based first
+ ret = loadBasedComp(ctx, list) or
+ cacheBasedComp(ctx, list);
+ } else {
+ ret = cacheBasedComp(ctx, list) or
+ loadBasedComp(ctx, list);
+ }
+
+ return ret;
+}
+
+bool MDPComp::cacheBasedComp(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+ if(sSimulationFlags & MDPCOMP_AVOID_CACHE_MDP)
+ return false;
+
+ int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+ mCurrentFrame.reset(numAppLayers);
+ updateLayerCache(ctx, list, mCurrentFrame);
+
+ //If an MDP marked layer is unsupported cannot do partial MDP Comp
+ for(int i = 0; i < numAppLayers; i++) {
+ if(!mCurrentFrame.isFBComposed[i]) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ if(not isSupportedForMDPComp(ctx, layer)) {
+ ALOGD_IF(isDebug(), "%s: Unsupported layer in list",
+ __FUNCTION__);
+ reset(ctx);
+ return false;
+ }
+ }
+ }
+
+ updateYUV(ctx, list, false /*secure only*/, mCurrentFrame);
+ /* mark secure RGB layers for MDP comp */
+ updateSecureRGB(ctx, list);
+ bool ret = markLayersForCaching(ctx, list); //sets up fbZ also
+ if(!ret) {
+ ALOGD_IF(isDebug(),"%s: batching failed, dpy %d",__FUNCTION__, mDpy);
+ reset(ctx);
+ return false;
+ }
+
+ int mdpCount = mCurrentFrame.mdpCount;
+
+ if(sEnableYUVsplit){
+ adjustForSourceSplit(ctx, list);
+ }
+
+ //Will benefit cases where a video has non-updating background.
+ if((mDpy > HWC_DISPLAY_PRIMARY) and
+ (mdpCount > MAX_SEC_LAYERS)) {
+ ALOGD_IF(isDebug(), "%s: Exceeds max secondary pipes",__FUNCTION__);
+ reset(ctx);
+ return false;
+ }
+
+ if(!postHeuristicsHandling(ctx, list)) {
+ ALOGD_IF(isDebug(), "post heuristic handling failed");
+ reset(ctx);
+ return false;
+ }
+ ALOGD_IF(sSimulationFlags,"%s: CACHE_MDP_COMP SUCCEEDED",
+ __FUNCTION__);
+
+ return true;
+}
+
+bool MDPComp::loadBasedComp(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+ if(sSimulationFlags & MDPCOMP_AVOID_LOAD_MDP)
+ return false;
+
+ if(not isLoadBasedCompDoable(ctx)) {
+ return false;
+ }
+
+ const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+ const int numNonDroppedLayers = numAppLayers - mCurrentFrame.dropCount;
+ const int stagesForMDP = min(sMaxPipesPerMixer,
+ ctx->mOverlay->availablePipes(mDpy, Overlay::MIXER_DEFAULT));
+
+ int mdpBatchSize = stagesForMDP - 1; //1 stage for FB
+ int fbBatchSize = numNonDroppedLayers - mdpBatchSize;
+ int lastMDPSupportedIndex = numAppLayers;
+ int dropCount = 0;
+
+ //Find the minimum MDP batch size
+ for(int i = 0; i < numAppLayers;i++) {
+ if(mCurrentFrame.drop[i]) {
+ dropCount++;
+ continue;
+ }
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ if(not isSupportedForMDPComp(ctx, layer)) {
+ lastMDPSupportedIndex = i;
+ mdpBatchSize = min(i - dropCount, stagesForMDP - 1);
+ fbBatchSize = numNonDroppedLayers - mdpBatchSize;
+ break;
+ }
+ }
+
+ ALOGD_IF(isDebug(), "%s:Before optimizing fbBatch, mdpbatch %d, fbbatch %d "
+ "dropped %d", __FUNCTION__, mdpBatchSize, fbBatchSize,
+ mCurrentFrame.dropCount);
+
+ //Start at a point where the fb batch should at least have 2 layers, for
+ //this mode to be justified.
+ while(fbBatchSize < 2) {
+ ++fbBatchSize;
+ --mdpBatchSize;
+ }
+
+ //If there are no layers for MDP, this mode doesnt make sense.
+ if(mdpBatchSize < 1) {
+ ALOGD_IF(isDebug(), "%s: No MDP layers after optimizing for fbBatch",
+ __FUNCTION__);
+ return false;
+ }
+
+ mCurrentFrame.reset(numAppLayers);
+
+ //Try with successively smaller mdp batch sizes until we succeed or reach 1
+ while(mdpBatchSize > 0) {
+ //Mark layers for MDP comp
+ int mdpBatchLeft = mdpBatchSize;
+ for(int i = 0; i < lastMDPSupportedIndex and mdpBatchLeft; i++) {
+ if(mCurrentFrame.drop[i]) {
+ continue;
+ }
+ mCurrentFrame.isFBComposed[i] = false;
+ --mdpBatchLeft;
+ }
+
+ mCurrentFrame.fbZ = mdpBatchSize;
+ mCurrentFrame.fbCount = fbBatchSize;
+ mCurrentFrame.mdpCount = mdpBatchSize;
+
+ ALOGD_IF(isDebug(), "%s:Trying with: mdpbatch %d fbbatch %d dropped %d",
+ __FUNCTION__, mdpBatchSize, fbBatchSize,
+ mCurrentFrame.dropCount);
+
+ if(postHeuristicsHandling(ctx, list)) {
+ ALOGD_IF(isDebug(), "%s: Postheuristics handling succeeded",
+ __FUNCTION__);
+ ALOGD_IF(sSimulationFlags,"%s: LOAD_MDP_COMP SUCCEEDED",
+ __FUNCTION__);
+ return true;
+ }
+
+ reset(ctx);
+ --mdpBatchSize;
+ ++fbBatchSize;
+ }
+
+ return false;
+}
+
+bool MDPComp::isLoadBasedCompDoable(hwc_context_t *ctx) {
+ if(mDpy or isSecurePresent(ctx, mDpy) or
+ isYuvPresent(ctx, mDpy)) {
+ return false;
+ }
+ return true;
+}
+
+bool MDPComp::canPartialUpdate(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list){
+ if(!qdutils::MDPVersion::getInstance().isPartialUpdateEnabled() ||
+ isSkipPresent(ctx, mDpy) || (list->flags & HWC_GEOMETRY_CHANGED) ||
+ !sIsPartialUpdateActive || mDpy ) {
+ return false;
+ }
+ if(ctx->listStats[mDpy].secureUI)
+ return false;
+ return true;
+}
+
+bool MDPComp::tryVideoOnly(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+ const bool secureOnly = true;
+ return videoOnlyComp(ctx, list, not secureOnly) or
+ videoOnlyComp(ctx, list, secureOnly);
+}
+
+bool MDPComp::videoOnlyComp(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list, bool secureOnly) {
+ if(sSimulationFlags & MDPCOMP_AVOID_VIDEO_ONLY)
+ return false;
+ int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+
+ mCurrentFrame.reset(numAppLayers);
+ mCurrentFrame.fbCount -= mCurrentFrame.dropCount;
+ updateYUV(ctx, list, secureOnly, mCurrentFrame);
+ int mdpCount = mCurrentFrame.mdpCount;
+
+ if(!isYuvPresent(ctx, mDpy) or (mdpCount == 0)) {
+ reset(ctx);
+ return false;
+ }
+
+ /* Bail out if we are processing only secured video layers
+ * and we dont have any */
+ if(!isSecurePresent(ctx, mDpy) && secureOnly){
+ reset(ctx);
+ return false;
+ }
+
+ if(mCurrentFrame.fbCount)
+ mCurrentFrame.fbZ = mCurrentFrame.mdpCount;
+
+ if(sEnableYUVsplit){
+ adjustForSourceSplit(ctx, list);
+ }
+
+ if(!postHeuristicsHandling(ctx, list)) {
+ ALOGD_IF(isDebug(), "post heuristic handling failed");
+ reset(ctx);
+ return false;
+ }
+
+ ALOGD_IF(sSimulationFlags,"%s: VIDEO_ONLY_COMP SUCCEEDED",
+ __FUNCTION__);
+ return true;
+}
+
+/* if tryFullFrame fails, try to push all video and secure RGB layers to MDP */
+bool MDPComp::tryMDPOnlyLayers(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+ // Fall back to video only composition, if AIV video mode is enabled
+ if(ctx->listStats[mDpy].mAIVVideoMode) {
+ ALOGD_IF(isDebug(), "%s: AIV Video Mode enabled dpy %d",
+ __FUNCTION__, mDpy);
+ return false;
+ }
+
+ const bool secureOnly = true;
+ return mdpOnlyLayersComp(ctx, list, not secureOnly) or
+ mdpOnlyLayersComp(ctx, list, secureOnly);
+
+}
+
+bool MDPComp::mdpOnlyLayersComp(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list, bool secureOnly) {
+
+ if(sSimulationFlags & MDPCOMP_AVOID_MDP_ONLY_LAYERS)
+ return false;
+
+ /* Bail out if we are processing only secured video layers
+ * and we dont have any */
+ if(!isSecurePresent(ctx, mDpy) && secureOnly){
+ reset(ctx);
+ return false;
+ }
+
+ int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+ mCurrentFrame.reset(numAppLayers);
+ mCurrentFrame.fbCount -= mCurrentFrame.dropCount;
+
+ updateYUV(ctx, list, secureOnly, mCurrentFrame);
+ /* mark secure RGB layers for MDP comp */
+ updateSecureRGB(ctx, list);
+
+ if(mCurrentFrame.mdpCount == 0) {
+ reset(ctx);
+ return false;
+ }
+
+ /* find the maximum batch of layers to be marked for framebuffer */
+ bool ret = markLayersForCaching(ctx, list); //sets up fbZ also
+ if(!ret) {
+ ALOGD_IF(isDebug(),"%s: batching failed, dpy %d",__FUNCTION__, mDpy);
+ reset(ctx);
+ return false;
+ }
+
+ if(sEnableYUVsplit){
+ adjustForSourceSplit(ctx, list);
+ }
+
+ if(!postHeuristicsHandling(ctx, list)) {
+ ALOGD_IF(isDebug(), "post heuristic handling failed");
+ reset(ctx);
+ return false;
+ }
+
+ ALOGD_IF(sSimulationFlags,"%s: MDP_ONLY_LAYERS_COMP SUCCEEDED",
+ __FUNCTION__);
+ return true;
+}
+
+/* Checks for conditions where YUV layers cannot be bypassed */
+bool MDPComp::isYUVDoable(hwc_context_t* ctx, hwc_layer_1_t* layer) {
+ if(isSkipLayer(layer)) {
+ ALOGD_IF(isDebug(), "%s: Video marked SKIP dpy %d", __FUNCTION__, mDpy);
+ return false;
+ }
+
+ if(has90Transform(layer) && !canUseRotator(ctx, mDpy)) {
+ ALOGD_IF(isDebug(), "%s: no free DMA pipe",__FUNCTION__);
+ return false;
+ }
+
+ if(isSecuring(ctx, layer)) {
+ ALOGD_IF(isDebug(), "%s: MDP securing is active", __FUNCTION__);
+ return false;
+ }
+
+ if(!isValidDimension(ctx, layer)) {
+ ALOGD_IF(isDebug(), "%s: Buffer is of invalid width",
+ __FUNCTION__);
+ return false;
+ }
+
+ if(layer->planeAlpha < 0xFF) {
+ ALOGD_IF(isDebug(), "%s: Cannot handle YUV layer with plane alpha\
+ in video only mode",
+ __FUNCTION__);
+ return false;
+ }
+
+ return true;
+}
+
+/* Checks for conditions where Secure RGB layers cannot be bypassed */
+bool MDPComp::isSecureRGBDoable(hwc_context_t* ctx, hwc_layer_1_t* layer) {
+ if(isSkipLayer(layer)) {
+ ALOGD_IF(isDebug(), "%s: Secure RGB layer marked SKIP dpy %d",
+ __FUNCTION__, mDpy);
+ return false;
+ }
+
+ if(isSecuring(ctx, layer)) {
+ ALOGD_IF(isDebug(), "%s: MDP securing is active", __FUNCTION__);
+ return false;
+ }
+
+ if(not isSupportedForMDPComp(ctx, layer)) {
+ ALOGD_IF(isDebug(), "%s: Unsupported secure RGB layer",
+ __FUNCTION__);
+ return false;
+ }
+ return true;
+}
+
+/* starts at fromIndex and check for each layer to find
+ * if it it has overlapping with any Updating layer above it in zorder
+ * till the end of the batch. returns true if it finds any intersection */
+bool MDPComp::canPushBatchToTop(const hwc_display_contents_1_t* list,
+ int fromIndex, int toIndex) {
+ for(int i = fromIndex; i < toIndex; i++) {
+ if(mCurrentFrame.isFBComposed[i] && !mCurrentFrame.drop[i]) {
+ if(intersectingUpdatingLayers(list, i+1, toIndex, i)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/* Checks if given layer at targetLayerIndex has any
+ * intersection with all the updating layers in beween
+ * fromIndex and toIndex. Returns true if it finds intersectiion */
+bool MDPComp::intersectingUpdatingLayers(const hwc_display_contents_1_t* list,
+ int fromIndex, int toIndex, int targetLayerIndex) {
+ for(int i = fromIndex; i <= toIndex; i++) {
+ if(!mCurrentFrame.isFBComposed[i]) {
+ if(areLayersIntersecting(&list->hwLayers[i],
+ &list->hwLayers[targetLayerIndex])) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+int MDPComp::getBatch(hwc_display_contents_1_t* list,
+ int& maxBatchStart, int& maxBatchEnd,
+ int& maxBatchCount) {
+ int i = 0;
+ int fbZOrder =-1;
+ int droppedLayerCt = 0;
+ while (i < mCurrentFrame.layerCount) {
+ int batchCount = 0;
+ int batchStart = i;
+ int batchEnd = i;
+ /* Adjust batch Z order with the dropped layers so far */
+ int fbZ = batchStart - droppedLayerCt;
+ int firstZReverseIndex = -1;
+ int updatingLayersAbove = 0;//Updating layer count in middle of batch
+ while(i < mCurrentFrame.layerCount) {
+ if(!mCurrentFrame.isFBComposed[i]) {
+ if(!batchCount) {
+ i++;
+ break;
+ }
+ updatingLayersAbove++;
+ i++;
+ continue;
+ } else {
+ if(mCurrentFrame.drop[i]) {
+ i++;
+ droppedLayerCt++;
+ continue;
+ } else if(updatingLayersAbove <= 0) {
+ batchCount++;
+ batchEnd = i;
+ i++;
+ continue;
+ } else { //Layer is FBComposed, not a drop & updatingLayer > 0
+
+ // We have a valid updating layer already. If layer-i not
+ // have overlapping with all updating layers in between
+ // batch-start and i, then we can add layer i to batch.
+ if(!intersectingUpdatingLayers(list, batchStart, i-1, i)) {
+ batchCount++;
+ batchEnd = i;
+ i++;
+ continue;
+ } else if(canPushBatchToTop(list, batchStart, i)) {
+ //If All the non-updating layers with in this batch
+ //does not have intersection with the updating layers
+ //above in z-order, then we can safely move the batch to
+ //higher z-order. Increment fbZ as it is moving up.
+ if( firstZReverseIndex < 0) {
+ firstZReverseIndex = i;
+ }
+ batchCount++;
+ batchEnd = i;
+ fbZ += updatingLayersAbove;
+ i++;
+ updatingLayersAbove = 0;
+ continue;
+ } else {
+ //both failed.start the loop again from here.
+ if(firstZReverseIndex >= 0) {
+ i = firstZReverseIndex;
+ }
+ break;
+ }
+ }
+ }
+ }
+ if(batchCount > maxBatchCount) {
+ maxBatchCount = batchCount;
+ maxBatchStart = batchStart;
+ maxBatchEnd = batchEnd;
+ fbZOrder = fbZ;
+ }
+ }
+ return fbZOrder;
+}
+
+bool MDPComp::markLayersForCaching(hwc_context_t* ctx,
+ hwc_display_contents_1_t* list) {
+ /* Idea is to keep as many non-updating(cached) layers in FB and
+ * send rest of them through MDP. This is done in 2 steps.
+ * 1. Find the maximum contiguous batch of non-updating layers.
+ * 2. See if we can improve this batch size for caching by adding
+ * opaque layers around the batch, if they don't have
+ * any overlapping with the updating layers in between.
+ * NEVER mark an updating layer for caching.
+ * But cached ones can be marked for MDP */
+
+ int maxBatchStart = -1;
+ int maxBatchEnd = -1;
+ int maxBatchCount = 0;
+ int fbZ = -1;
+
+ /* Nothing is cached. No batching needed */
+ if(mCurrentFrame.fbCount == 0) {
+ return true;
+ }
+
+ /* No MDP comp layers, try to use other comp modes */
+ if(mCurrentFrame.mdpCount == 0) {
+ return false;
+ }
+
+ fbZ = getBatch(list, maxBatchStart, maxBatchEnd, maxBatchCount);
+
+ /* reset rest of the layers lying inside ROI for MDP comp */
+ for(int i = 0; i < mCurrentFrame.layerCount; i++) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ if((i < maxBatchStart || i > maxBatchEnd) &&
+ mCurrentFrame.isFBComposed[i]){
+ if(!mCurrentFrame.drop[i]){
+ //If an unsupported layer is being attempted to
+ //be pulled out we should fail
+ if(not isSupportedForMDPComp(ctx, layer)) {
+ return false;
+ }
+ mCurrentFrame.isFBComposed[i] = false;
+ }
+ }
+ }
+
+ // update the frame data
+ mCurrentFrame.fbZ = fbZ;
+ mCurrentFrame.fbCount = maxBatchCount;
+ mCurrentFrame.mdpCount = mCurrentFrame.layerCount -
+ mCurrentFrame.fbCount - mCurrentFrame.dropCount;
+
+ ALOGD_IF(isDebug(),"%s: cached count: %d",__FUNCTION__,
+ mCurrentFrame.fbCount);
+
+ return true;
+}
+
+void MDPComp::updateLayerCache(hwc_context_t* ctx,
+ hwc_display_contents_1_t* list, FrameInfo& frame) {
+ int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+ int fbCount = 0;
+
+ for(int i = 0; i < numAppLayers; i++) {
+ hwc_layer_1_t * layer = &list->hwLayers[i];
+ if (!layerUpdating(layer)) {
+ if(!frame.drop[i])
+ fbCount++;
+ frame.isFBComposed[i] = true;
+ } else {
+ frame.isFBComposed[i] = false;
+ }
+ }
+
+ frame.fbCount = fbCount;
+ frame.mdpCount = frame.layerCount - frame.fbCount
+ - frame.dropCount;
+
+ ALOGD_IF(isDebug(),"%s: MDP count: %d FB count %d drop count: %d",
+ __FUNCTION__, frame.mdpCount, frame.fbCount, frame.dropCount);
+}
+
+// drop other non-AIV layers from external display list.
+void MDPComp::dropNonAIVLayers(hwc_context_t* ctx,
+ hwc_display_contents_1_t* list) {
+ for (size_t i = 0; i < (size_t)ctx->listStats[mDpy].numAppLayers; i++) {
+ hwc_layer_1_t * layer = &list->hwLayers[i];
+ if(!(isAIVVideoLayer(layer) || isAIVCCLayer(layer))) {
+ mCurrentFrame.dropCount++;
+ mCurrentFrame.drop[i] = true;
+ }
+ }
+ mCurrentFrame.fbCount -= mCurrentFrame.dropCount;
+ mCurrentFrame.mdpCount = mCurrentFrame.layerCount -
+ mCurrentFrame.fbCount - mCurrentFrame.dropCount;
+ ALOGD_IF(isDebug(),"%s: fb count: %d mdp count %d drop count %d",
+ __FUNCTION__, mCurrentFrame.fbCount, mCurrentFrame.mdpCount,
+ mCurrentFrame.dropCount);
+}
+
+void MDPComp::updateYUV(hwc_context_t* ctx, hwc_display_contents_1_t* list,
+ bool secureOnly, FrameInfo& frame) {
+ int nYuvCount = ctx->listStats[mDpy].yuvCount;
+ for(int index = 0;index < nYuvCount; index++){
+ int nYuvIndex = ctx->listStats[mDpy].yuvIndices[index];
+ hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex];
+
+ if(mCurrentFrame.drop[nYuvIndex]) {
+ continue;
+ }
+
+ if(!isYUVDoable(ctx, layer)) {
+ if(!frame.isFBComposed[nYuvIndex]) {
+ frame.isFBComposed[nYuvIndex] = true;
+ frame.fbCount++;
+ }
+ } else {
+ if(frame.isFBComposed[nYuvIndex]) {
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(!secureOnly || isSecureBuffer(hnd)) {
+ frame.isFBComposed[nYuvIndex] = false;
+ frame.fbCount--;
+ }
+ }
+ }
+ }
+
+ frame.mdpCount = frame.layerCount - frame.fbCount - frame.dropCount;
+ ALOGD_IF(isDebug(),"%s: fb count: %d",__FUNCTION__, frame.fbCount);
+}
+
+void MDPComp::updateSecureRGB(hwc_context_t* ctx,
+ hwc_display_contents_1_t* list) {
+ int nSecureRGBCount = ctx->listStats[mDpy].secureRGBCount;
+ for(int index = 0;index < nSecureRGBCount; index++){
+ int nSecureRGBIndex = ctx->listStats[mDpy].secureRGBIndices[index];
+ hwc_layer_1_t* layer = &list->hwLayers[nSecureRGBIndex];
+
+ if(!isSecureRGBDoable(ctx, layer)) {
+ if(!mCurrentFrame.isFBComposed[nSecureRGBIndex]) {
+ mCurrentFrame.isFBComposed[nSecureRGBIndex] = true;
+ mCurrentFrame.fbCount++;
+ }
+ } else {
+ if(mCurrentFrame.isFBComposed[nSecureRGBIndex]) {
+ mCurrentFrame.isFBComposed[nSecureRGBIndex] = false;
+ mCurrentFrame.fbCount--;
+ }
+ }
+ }
+
+ mCurrentFrame.mdpCount = mCurrentFrame.layerCount -
+ mCurrentFrame.fbCount - mCurrentFrame.dropCount;
+ ALOGD_IF(isDebug(),"%s: fb count: %d",__FUNCTION__,
+ mCurrentFrame.fbCount);
+}
+
+hwc_rect_t MDPComp::getUpdatingFBRect(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list){
+ hwc_rect_t fbRect = (struct hwc_rect){0, 0, 0, 0};
+
+ /* Update only the region of FB needed for composition */
+ for(int i = 0; i < mCurrentFrame.layerCount; i++ ) {
+ if(mCurrentFrame.isFBComposed[i] && !mCurrentFrame.drop[i]) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ hwc_rect_t dst = layer->displayFrame;
+ fbRect = getUnion(fbRect, dst);
+ }
+ }
+ trimAgainstROI(ctx, fbRect);
+ return fbRect;
+}
+
+bool MDPComp::postHeuristicsHandling(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+
+ //Capability checks
+ if(!resourceCheck(ctx, list)) {
+ ALOGD_IF(isDebug(), "%s: resource check failed", __FUNCTION__);
+ return false;
+ }
+
+ //Limitations checks
+ if(!hwLimitationsCheck(ctx, list)) {
+ ALOGD_IF(isDebug(), "%s: HW limitations",__FUNCTION__);
+ return false;
+ }
+
+ //Configure framebuffer first if applicable
+ if(mCurrentFrame.fbZ >= 0) {
+ hwc_rect_t fbRect = getUpdatingFBRect(ctx, list);
+ if(!ctx->mFBUpdate[mDpy]->prepare(ctx, list, fbRect, mCurrentFrame.fbZ))
+ {
+ ALOGD_IF(isDebug(), "%s configure framebuffer failed",
+ __FUNCTION__);
+ return false;
+ }
+ }
+
+ mCurrentFrame.map();
+
+ if(!allocLayerPipes(ctx, list)) {
+ ALOGD_IF(isDebug(), "%s: Unable to allocate MDP pipes", __FUNCTION__);
+ return false;
+ }
+
+ for (int index = 0, mdpNextZOrder = 0; index < mCurrentFrame.layerCount;
+ index++) {
+ if(!mCurrentFrame.isFBComposed[index]) {
+ int mdpIndex = mCurrentFrame.layerToMDP[index];
+ hwc_layer_1_t* layer = &list->hwLayers[index];
+
+ //Leave fbZ for framebuffer. CACHE/GLES layers go here.
+ if(mdpNextZOrder == mCurrentFrame.fbZ) {
+ mdpNextZOrder++;
+ }
+ MdpPipeInfo* cur_pipe = mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
+ cur_pipe->zOrder = mdpNextZOrder++;
+
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(isYUVSplitNeeded(hnd) && sEnableYUVsplit){
+ if(configure4k2kYuv(ctx, layer,
+ mCurrentFrame.mdpToLayer[mdpIndex])
+ != 0 ){
+ ALOGD_IF(isDebug(), "%s: Failed to configure split pipes \
+ for layer %d",__FUNCTION__, index);
+ return false;
+ }
+ else{
+ mdpNextZOrder++;
+ }
+ continue;
+ }
+ if(configure(ctx, layer, mCurrentFrame.mdpToLayer[mdpIndex]) != 0 ){
+ ALOGD_IF(isDebug(), "%s: Failed to configure overlay for \
+ layer %d",__FUNCTION__, index);
+ return false;
+ }
+ }
+ }
+
+ if(!ctx->mOverlay->validateAndSet(mDpy, ctx->dpyAttr[mDpy].fd)) {
+ ALOGD_IF(isDebug(), "%s: Failed to validate and set overlay for dpy %d"
+ ,__FUNCTION__, mDpy);
+ return false;
+ }
+
+ setRedraw(ctx, list);
+ return true;
+}
+
+bool MDPComp::resourceCheck(hwc_context_t* ctx,
+ hwc_display_contents_1_t* list) {
+ const bool fbUsed = mCurrentFrame.fbCount;
+ if(mCurrentFrame.mdpCount > sMaxPipesPerMixer - fbUsed) {
+ ALOGD_IF(isDebug(), "%s: Exceeds MAX_PIPES_PER_MIXER",__FUNCTION__);
+ return false;
+ }
+ // Init rotCount to number of rotate sessions used by other displays
+ int rotCount = ctx->mRotMgr->getNumActiveSessions();
+ // Count the number of rotator sessions required for current display
+ for (int index = 0; index < mCurrentFrame.layerCount; index++) {
+ if(!mCurrentFrame.isFBComposed[index]) {
+ hwc_layer_1_t* layer = &list->hwLayers[index];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(has90Transform(layer) && isRotationDoable(ctx, hnd)) {
+ rotCount++;
+ }
+ }
+ }
+ // if number of layers to rotate exceeds max rotator sessions, bail out.
+ if(rotCount > RotMgr::MAX_ROT_SESS) {
+ ALOGD_IF(isDebug(), "%s: Exceeds max rotator sessions %d",
+ __FUNCTION__, mDpy);
+ return false;
+ }
+ return true;
+}
+
+bool MDPComp::hwLimitationsCheck(hwc_context_t* ctx,
+ hwc_display_contents_1_t* list) {
+
+ //A-family hw limitation:
+ //If a layer need alpha scaling, MDP can not support.
+ if(ctx->mMDP.version < qdutils::MDSS_V5) {
+ for(int i = 0; i < mCurrentFrame.layerCount; ++i) {
+ if(!mCurrentFrame.isFBComposed[i] &&
+ isAlphaScaled( &list->hwLayers[i])) {
+ ALOGD_IF(isDebug(), "%s:frame needs alphaScaling",__FUNCTION__);
+ return false;
+ }
+ }
+ }
+
+ // On 8x26 & 8974 hw, we have a limitation of downscaling+blending.
+ //If multiple layers requires downscaling and also they are overlapping
+ //fall back to GPU since MDSS can not handle it.
+ if(qdutils::MDPVersion::getInstance().is8x74v2() ||
+ qdutils::MDPVersion::getInstance().is8x26()) {
+ for(int i = 0; i < mCurrentFrame.layerCount-1; ++i) {
+ hwc_layer_1_t* botLayer = &list->hwLayers[i];
+ if(!mCurrentFrame.isFBComposed[i] &&
+ isDownscaleRequired(botLayer)) {
+ //if layer-i is marked for MDP and needs downscaling
+ //check if any MDP layer on top of i & overlaps with layer-i
+ for(int j = i+1; j < mCurrentFrame.layerCount; ++j) {
+ hwc_layer_1_t* topLayer = &list->hwLayers[j];
+ if(!mCurrentFrame.isFBComposed[j] &&
+ isDownscaleRequired(topLayer)) {
+ hwc_rect_t r = getIntersection(botLayer->displayFrame,
+ topLayer->displayFrame);
+ if(isValidRect(r))
+ return false;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+void MDPComp::setDynRefreshRate(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+ //For primary display, set the dynamic refreshrate
+ if(!mDpy && qdutils::MDPVersion::getInstance().isDynFpsSupported() &&
+ ctx->mUseMetaDataRefreshRate) {
+ FrameInfo frame;
+ frame.reset(mCurrentFrame.layerCount);
+ memset(&frame.drop, 0, sizeof(frame.drop));
+ frame.dropCount = 0;
+ ALOGD_IF(isDebug(), "%s: Update Cache and YUVInfo for Dyn Refresh Rate",
+ __FUNCTION__);
+ updateLayerCache(ctx, list, frame);
+ updateYUV(ctx, list, false /*secure only*/, frame);
+ uint32_t refreshRate = ctx->dpyAttr[mDpy].refreshRate;
+ MDPVersion& mdpHw = MDPVersion::getInstance();
+ if(sIdleFallBack) {
+ //Set minimum panel refresh rate during idle timeout
+ refreshRate = mdpHw.getMinFpsSupported();
+ } else if((ctx->listStats[mDpy].yuvCount == frame.mdpCount) ||
+ (frame.layerCount == 1)) {
+ //Set the new fresh rate, if there is only one updating YUV layer
+ //or there is one single RGB layer with this request
+ refreshRate = ctx->listStats[mDpy].refreshRateRequest;
+ }
+ setRefreshRate(ctx, mDpy, refreshRate);
+ }
+}
+
+int MDPComp::prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+ int ret = 0;
+ char property[PROPERTY_VALUE_MAX];
+
+ if(!ctx || !list) {
+ ALOGE("%s: Invalid context or list",__FUNCTION__);
+ mCachedFrame.reset();
+ return -1;
+ }
+
+ const int numLayers = ctx->listStats[mDpy].numAppLayers;
+ if(mDpy == HWC_DISPLAY_PRIMARY) {
+ sSimulationFlags = 0;
+ if(property_get("debug.hwc.simulate", property, NULL) > 0) {
+ int currentFlags = atoi(property);
+ if(currentFlags != sSimulationFlags) {
+ sSimulationFlags = currentFlags;
+ ALOGI("%s: Simulation Flag read: 0x%x (%d)", __FUNCTION__,
+ sSimulationFlags, sSimulationFlags);
+ }
+ }
+ }
+ // reset PTOR
+ if(!mDpy)
+ memset(&(ctx->mPtorInfo), 0, sizeof(ctx->mPtorInfo));
+
+ //reset old data
+ mCurrentFrame.reset(numLayers);
+ memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
+ mCurrentFrame.dropCount = 0;
+
+ //Do not cache the information for next draw cycle.
+ if(numLayers > MAX_NUM_APP_LAYERS or (!numLayers)) {
+ ALOGI("%s: Unsupported layer count for mdp composition",
+ __FUNCTION__);
+ mCachedFrame.reset();
+#ifdef DYNAMIC_FPS
+ // Reset refresh rate
+ setRefreshRate(ctx, mDpy, ctx->dpyAttr[mDpy].refreshRate);
+#endif
+ return -1;
+ }
+
+ // Detect the start of animation and fall back to GPU only once to cache
+ // all the layers in FB and display FB content untill animation completes.
+ if(ctx->listStats[mDpy].isDisplayAnimating) {
+ mCurrentFrame.needsRedraw = false;
+ if(ctx->mAnimationState[mDpy] == ANIMATION_STOPPED) {
+ mCurrentFrame.needsRedraw = true;
+ ctx->mAnimationState[mDpy] = ANIMATION_STARTED;
+ }
+ setMDPCompLayerFlags(ctx, list);
+ mCachedFrame.updateCounts(mCurrentFrame);
+#ifdef DYNAMIC_FPS
+ // Reset refresh rate
+ setRefreshRate(ctx, mDpy, ctx->dpyAttr[mDpy].refreshRate);
+#endif
+ ret = -1;
+ return ret;
+ } else {
+ ctx->mAnimationState[mDpy] = ANIMATION_STOPPED;
+ }
+
+ if(!mDpy and !isSecondaryConnected(ctx) and !mPrevModeOn and
+ mCachedFrame.isSameFrame(ctx,mDpy,list)) {
+
+ ALOGD_IF(isDebug(),"%s: Avoid new composition",__FUNCTION__);
+ mCurrentFrame.needsRedraw = false;
+ setMDPCompLayerFlags(ctx, list);
+ mCachedFrame.updateCounts(mCurrentFrame);
+#ifdef DYNAMIC_FPS
+ setDynRefreshRate(ctx, list);
+#endif
+ return -1;
+
+ }
+
+ //Hard conditions, if not met, cannot do MDP comp
+ if(isFrameDoable(ctx)) {
+ generateROI(ctx, list);
+ // if AIV Video mode is enabled, drop all non AIV layers from the
+ // external display list.
+ if(ctx->listStats[mDpy].mAIVVideoMode) {
+ dropNonAIVLayers(ctx, list);
+ }
+
+ // if tryFullFrame fails, try to push all video and secure RGB layers
+ // to MDP for composition.
+ mModeOn = tryFullFrame(ctx, list) || tryMDPOnlyLayers(ctx, list) ||
+ tryVideoOnly(ctx, list);
+ if(mModeOn) {
+ setMDPCompLayerFlags(ctx, list);
+ } else {
+ resetROI(ctx, mDpy);
+ reset(ctx);
+ memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
+ mCurrentFrame.dropCount = 0;
+ ret = -1;
+ ALOGE_IF(sSimulationFlags && (mDpy == HWC_DISPLAY_PRIMARY),
+ "MDP Composition Strategies Failed");
+ }
+ } else {
+ if ((ctx->mMDP.version == qdutils::MDP_V3_0_5) && ctx->mCopyBit[mDpy] &&
+ enablePartialUpdateForMDP3) {
+ generateROI(ctx, list);
+ for(int i = 0; i < ctx->listStats[mDpy].numAppLayers; i++) {
+ ctx->copybitDrop[i] = mCurrentFrame.drop[i];
+ }
+ }
+ ALOGD_IF( isDebug(),"%s: MDP Comp not possible for this frame",
+ __FUNCTION__);
+ ret = -1;
+ }
+
+ if(isDebug()) {
+ ALOGD("GEOMETRY change: %d",
+ (list->flags & HWC_GEOMETRY_CHANGED));
+ android::String8 sDump("");
+ dump(sDump, ctx);
+ ALOGD("%s",sDump.string());
+ }
+
+#ifdef DYNAMIC_FPS
+ setDynRefreshRate(ctx, list);
+#endif
+
+ mCachedFrame.updateCounts(mCurrentFrame);
+ return ret;
+}
+
+bool MDPComp::allocSplitVGPipesfor4k2k(hwc_context_t *ctx, int index) {
+
+ bool bRet = true;
+ int mdpIndex = mCurrentFrame.layerToMDP[index];
+ PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
+ info.pipeInfo = new MdpYUVPipeInfo;
+ info.rot = NULL;
+ MdpYUVPipeInfo& pipe_info = *(MdpYUVPipeInfo*)info.pipeInfo;
+
+ pipe_info.lIndex = ovutils::OV_INVALID;
+ pipe_info.rIndex = ovutils::OV_INVALID;
+
+ Overlay::PipeSpecs pipeSpecs;
+ pipeSpecs.formatClass = Overlay::FORMAT_YUV;
+ pipeSpecs.needsScaling = true;
+ pipeSpecs.dpy = mDpy;
+ pipeSpecs.fb = false;
+
+ pipe_info.lIndex = ctx->mOverlay->getPipe(pipeSpecs);
+ if(pipe_info.lIndex == ovutils::OV_INVALID){
+ bRet = false;
+ ALOGD_IF(isDebug(),"%s: allocating first VG pipe failed",
+ __FUNCTION__);
+ }
+ pipe_info.rIndex = ctx->mOverlay->getPipe(pipeSpecs);
+ if(pipe_info.rIndex == ovutils::OV_INVALID){
+ bRet = false;
+ ALOGD_IF(isDebug(),"%s: allocating second VG pipe failed",
+ __FUNCTION__);
+ }
+ return bRet;
+}
+
+int MDPComp::drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+ int fd = -1;
+ if (ctx->mPtorInfo.isActive()) {
+ fd = ctx->mCopyBit[mDpy]->drawOverlap(ctx, list);
+ if (fd < 0) {
+ ALOGD_IF(isDebug(),"%s: failed", __FUNCTION__);
+ }
+ }
+ return fd;
+}
+//=============MDPCompNonSplit==================================================
+
+void MDPCompNonSplit::adjustForSourceSplit(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+ //If 4k2k Yuv layer split is possible, and if
+ //fbz is above 4k2k layer, increment fb zorder by 1
+ //as we split 4k2k layer and increment zorder for right half
+ //of the layer
+ if(!ctx)
+ return;
+ if(mCurrentFrame.fbZ >= 0) {
+ for (int index = 0, mdpNextZOrder = 0; index < mCurrentFrame.layerCount;
+ index++) {
+ if(!mCurrentFrame.isFBComposed[index]) {
+ if(mdpNextZOrder == mCurrentFrame.fbZ) {
+ mdpNextZOrder++;
+ }
+ mdpNextZOrder++;
+ hwc_layer_1_t* layer = &list->hwLayers[index];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(isYUVSplitNeeded(hnd)) {
+ if(mdpNextZOrder <= mCurrentFrame.fbZ)
+ mCurrentFrame.fbZ += 1;
+ mdpNextZOrder++;
+ //As we split 4kx2k yuv layer and program to 2 VG pipes
+ //(if available) increase mdpcount by 1.
+ mCurrentFrame.mdpCount++;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Configures pipe(s) for MDP composition
+ */
+int MDPCompNonSplit::configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ PipeLayerPair& PipeLayerPair) {
+ MdpPipeInfoNonSplit& mdp_info =
+ *(static_cast<MdpPipeInfoNonSplit*>(PipeLayerPair.pipeInfo));
+ eMdpFlags mdpFlags = OV_MDP_BACKEND_COMPOSITION;
+ eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder);
+ eDest dest = mdp_info.index;
+
+ ALOGD_IF(isDebug(),"%s: configuring: layer: %p z_order: %d dest_pipe: %d",
+ __FUNCTION__, layer, zOrder, dest);
+
+ return configureNonSplit(ctx, layer, mDpy, mdpFlags, zOrder, dest,
+ &PipeLayerPair.rot);
+}
+
+bool MDPCompNonSplit::allocLayerPipes(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+ for(int index = 0; index < mCurrentFrame.layerCount; index++) {
+
+ if(mCurrentFrame.isFBComposed[index]) continue;
+
+ hwc_layer_1_t* layer = &list->hwLayers[index];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(isYUVSplitNeeded(hnd) && sEnableYUVsplit){
+ if(allocSplitVGPipesfor4k2k(ctx, index)){
+ continue;
+ }
+ }
+
+ int mdpIndex = mCurrentFrame.layerToMDP[index];
+ PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
+ info.pipeInfo = new MdpPipeInfoNonSplit;
+ info.rot = NULL;
+ MdpPipeInfoNonSplit& pipe_info = *(MdpPipeInfoNonSplit*)info.pipeInfo;
+
+ Overlay::PipeSpecs pipeSpecs;
+ pipeSpecs.formatClass = isYuvBuffer(hnd) ?
+ Overlay::FORMAT_YUV : Overlay::FORMAT_RGB;
+ pipeSpecs.needsScaling = qhwc::needsScaling(layer) or
+ (qdutils::MDPVersion::getInstance().is8x26() and
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres > 1024);
+ pipeSpecs.dpy = mDpy;
+ pipeSpecs.fb = false;
+ pipeSpecs.numActiveDisplays = ctx->numActiveDisplays;
+
+ pipe_info.index = ctx->mOverlay->getPipe(pipeSpecs);
+
+ if(pipe_info.index == ovutils::OV_INVALID) {
+ ALOGD_IF(isDebug(), "%s: Unable to get pipe", __FUNCTION__);
+ return false;
+ }
+ }
+ return true;
+}
+
+int MDPCompNonSplit::configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ PipeLayerPair& PipeLayerPair) {
+ MdpYUVPipeInfo& mdp_info =
+ *(static_cast<MdpYUVPipeInfo*>(PipeLayerPair.pipeInfo));
+ eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder);
+ eMdpFlags mdpFlagsL = OV_MDP_BACKEND_COMPOSITION;
+ eDest lDest = mdp_info.lIndex;
+ eDest rDest = mdp_info.rIndex;
+
+ return configureSourceSplit(ctx, layer, mDpy, mdpFlagsL, zOrder,
+ lDest, rDest, &PipeLayerPair.rot);
+}
+
+bool MDPCompNonSplit::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+
+ if(!isEnabled() or !mModeOn) {
+ ALOGD_IF(isDebug(),"%s: MDP Comp not enabled/configured", __FUNCTION__);
+ return true;
+ }
+
+ overlay::Overlay& ov = *ctx->mOverlay;
+ LayerProp *layerProp = ctx->layerProp[mDpy];
+
+ int numHwLayers = ctx->listStats[mDpy].numAppLayers;
+ for(int i = 0; i < numHwLayers && mCurrentFrame.mdpCount; i++ )
+ {
+ if(mCurrentFrame.isFBComposed[i]) continue;
+
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(!hnd) {
+ if (!(layer->flags & HWC_COLOR_FILL)) {
+ ALOGE("%s handle null", __FUNCTION__);
+ return false;
+ }
+ // No PLAY for Color layer
+ layerProp[i].mFlags &= ~HWC_MDPCOMP;
+ continue;
+ }
+
+ int mdpIndex = mCurrentFrame.layerToMDP[i];
+
+ if(isYUVSplitNeeded(hnd) && sEnableYUVsplit)
+ {
+ MdpYUVPipeInfo& pipe_info =
+ *(MdpYUVPipeInfo*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
+ Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
+ ovutils::eDest indexL = pipe_info.lIndex;
+ ovutils::eDest indexR = pipe_info.rIndex;
+ int fd = hnd->fd;
+ uint32_t offset = (uint32_t)hnd->offset;
+ if(rot) {
+ rot->queueBuffer(fd, offset);
+ fd = rot->getDstMemId();
+ offset = rot->getDstOffset();
+ }
+ if(indexL != ovutils::OV_INVALID) {
+ ovutils::eDest destL = (ovutils::eDest)indexL;
+ ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+ using pipe: %d", __FUNCTION__, layer, hnd, indexL );
+ if (!ov.queueBuffer(fd, offset, destL)) {
+ ALOGE("%s: queueBuffer failed for display:%d",
+ __FUNCTION__, mDpy);
+ return false;
+ }
+ }
+
+ if(indexR != ovutils::OV_INVALID) {
+ ovutils::eDest destR = (ovutils::eDest)indexR;
+ ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+ using pipe: %d", __FUNCTION__, layer, hnd, indexR );
+ if (!ov.queueBuffer(fd, offset, destR)) {
+ ALOGE("%s: queueBuffer failed for display:%d",
+ __FUNCTION__, mDpy);
+ return false;
+ }
+ }
+ }
+ else{
+ MdpPipeInfoNonSplit& pipe_info =
+ *(MdpPipeInfoNonSplit*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
+ ovutils::eDest dest = pipe_info.index;
+ if(dest == ovutils::OV_INVALID) {
+ ALOGE("%s: Invalid pipe index (%d)", __FUNCTION__, dest);
+ return false;
+ }
+
+ if(!(layerProp[i].mFlags & HWC_MDPCOMP)) {
+ continue;
+ }
+
+ int fd = hnd->fd;
+ uint32_t offset = (uint32_t)hnd->offset;
+ int index = ctx->mPtorInfo.getPTORArrayIndex(i);
+ if (!mDpy && (index != -1)) {
+ hnd = ctx->mCopyBit[mDpy]->getCurrentRenderBuffer();
+ fd = hnd->fd;
+ offset = 0;
+ }
+
+ ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+ using pipe: %d", __FUNCTION__, layer,
+ hnd, dest );
+
+ Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
+ if(rot) {
+ if(!rot->queueBuffer(fd, offset))
+ return false;
+ fd = rot->getDstMemId();
+ offset = rot->getDstOffset();
+ }
+
+ if (!ov.queueBuffer(fd, offset, dest)) {
+ ALOGE("%s: queueBuffer failed for display:%d ",
+ __FUNCTION__, mDpy);
+ return false;
+ }
+ }
+
+ layerProp[i].mFlags &= ~HWC_MDPCOMP;
+ }
+ return true;
+}
+
+//=============MDPCompSplit===================================================
+
+void MDPCompSplit::adjustForSourceSplit(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list){
+ //if 4kx2k yuv layer is totally present in either in left half
+ //or right half then try splitting the yuv layer to avoid decimation
+ const int lSplit = getLeftSplit(ctx, mDpy);
+ if(mCurrentFrame.fbZ >= 0) {
+ for (int index = 0, mdpNextZOrder = 0; index < mCurrentFrame.layerCount;
+ index++) {
+ if(!mCurrentFrame.isFBComposed[index]) {
+ if(mdpNextZOrder == mCurrentFrame.fbZ) {
+ mdpNextZOrder++;
+ }
+ mdpNextZOrder++;
+ hwc_layer_1_t* layer = &list->hwLayers[index];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(isYUVSplitNeeded(hnd)) {
+ hwc_rect_t dst = layer->displayFrame;
+ if((dst.left > lSplit) || (dst.right < lSplit)) {
+ mCurrentFrame.mdpCount += 1;
+ }
+ if(mdpNextZOrder <= mCurrentFrame.fbZ)
+ mCurrentFrame.fbZ += 1;
+ mdpNextZOrder++;
+ }
+ }
+ }
+ }
+}
+
+bool MDPCompSplit::acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer,
+ MdpPipeInfoSplit& pipe_info) {
+
+ const int lSplit = getLeftSplit(ctx, mDpy);
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ hwc_rect_t dst = layer->displayFrame;
+ pipe_info.lIndex = ovutils::OV_INVALID;
+ pipe_info.rIndex = ovutils::OV_INVALID;
+
+ Overlay::PipeSpecs pipeSpecs;
+ pipeSpecs.formatClass = isYuvBuffer(hnd) ?
+ Overlay::FORMAT_YUV : Overlay::FORMAT_RGB;
+ pipeSpecs.needsScaling = qhwc::needsScalingWithSplit(ctx, layer, mDpy);
+ pipeSpecs.dpy = mDpy;
+ pipeSpecs.mixer = Overlay::MIXER_LEFT;
+ pipeSpecs.fb = false;
+
+ // Acquire pipe only for the updating half
+ hwc_rect_t l_roi = ctx->listStats[mDpy].lRoi;
+ hwc_rect_t r_roi = ctx->listStats[mDpy].rRoi;
+
+ if (dst.left < lSplit && isValidRect(getIntersection(dst, l_roi))) {
+ pipe_info.lIndex = ctx->mOverlay->getPipe(pipeSpecs);
+ if(pipe_info.lIndex == ovutils::OV_INVALID)
+ return false;
+ }
+
+ if(dst.right > lSplit && isValidRect(getIntersection(dst, r_roi))) {
+ pipeSpecs.mixer = Overlay::MIXER_RIGHT;
+ pipe_info.rIndex = ctx->mOverlay->getPipe(pipeSpecs);
+ if(pipe_info.rIndex == ovutils::OV_INVALID)
+ return false;
+ }
+
+ return true;
+}
+
+bool MDPCompSplit::allocLayerPipes(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+ for(int index = 0 ; index < mCurrentFrame.layerCount; index++) {
+
+ if(mCurrentFrame.isFBComposed[index]) continue;
+
+ hwc_layer_1_t* layer = &list->hwLayers[index];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ hwc_rect_t dst = layer->displayFrame;
+ const int lSplit = getLeftSplit(ctx, mDpy);
+ if(isYUVSplitNeeded(hnd) && sEnableYUVsplit){
+ if((dst.left > lSplit)||(dst.right < lSplit)){
+ if(allocSplitVGPipesfor4k2k(ctx, index)){
+ continue;
+ }
+ }
+ }
+ int mdpIndex = mCurrentFrame.layerToMDP[index];
+ PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
+ info.pipeInfo = new MdpPipeInfoSplit;
+ info.rot = NULL;
+ MdpPipeInfoSplit& pipe_info = *(MdpPipeInfoSplit*)info.pipeInfo;
+
+ if(!acquireMDPPipes(ctx, layer, pipe_info)) {
+ ALOGD_IF(isDebug(), "%s: Unable to get pipe for type",
+ __FUNCTION__);
+ return false;
+ }
+ }
+ return true;
+}
+
+int MDPCompSplit::configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ PipeLayerPair& PipeLayerPair) {
+ const int lSplit = getLeftSplit(ctx, mDpy);
+ hwc_rect_t dst = layer->displayFrame;
+ if((dst.left > lSplit)||(dst.right < lSplit)){
+ MdpYUVPipeInfo& mdp_info =
+ *(static_cast<MdpYUVPipeInfo*>(PipeLayerPair.pipeInfo));
+ eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder);
+ eMdpFlags mdpFlagsL = OV_MDP_BACKEND_COMPOSITION;
+ eDest lDest = mdp_info.lIndex;
+ eDest rDest = mdp_info.rIndex;
+
+ return configureSourceSplit(ctx, layer, mDpy, mdpFlagsL, zOrder,
+ lDest, rDest, &PipeLayerPair.rot);
+ }
+ else{
+ return configure(ctx, layer, PipeLayerPair);
+ }
+}
+
+/*
+ * Configures pipe(s) for MDP composition
+ */
+int MDPCompSplit::configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ PipeLayerPair& PipeLayerPair) {
+ MdpPipeInfoSplit& mdp_info =
+ *(static_cast<MdpPipeInfoSplit*>(PipeLayerPair.pipeInfo));
+ eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder);
+ eMdpFlags mdpFlagsL = OV_MDP_BACKEND_COMPOSITION;
+ eDest lDest = mdp_info.lIndex;
+ eDest rDest = mdp_info.rIndex;
+
+ ALOGD_IF(isDebug(),"%s: configuring: layer: %p z_order: %d dest_pipeL: %d"
+ "dest_pipeR: %d",__FUNCTION__, layer, zOrder, lDest, rDest);
+
+ return configureSplit(ctx, layer, mDpy, mdpFlagsL, zOrder, lDest,
+ rDest, &PipeLayerPair.rot);
+}
+
+bool MDPCompSplit::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+
+ if(!isEnabled() or !mModeOn) {
+ ALOGD_IF(isDebug(),"%s: MDP Comp not enabled/configured", __FUNCTION__);
+ return true;
+ }
+
+ overlay::Overlay& ov = *ctx->mOverlay;
+ LayerProp *layerProp = ctx->layerProp[mDpy];
+
+ int numHwLayers = ctx->listStats[mDpy].numAppLayers;
+ for(int i = 0; i < numHwLayers && mCurrentFrame.mdpCount; i++ )
+ {
+ if(mCurrentFrame.isFBComposed[i]) continue;
+
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(!hnd) {
+ ALOGE("%s handle null", __FUNCTION__);
+ return false;
+ }
+
+ if(!(layerProp[i].mFlags & HWC_MDPCOMP)) {
+ continue;
+ }
+
+ int mdpIndex = mCurrentFrame.layerToMDP[i];
+
+ if(isYUVSplitNeeded(hnd) && sEnableYUVsplit)
+ {
+ MdpYUVPipeInfo& pipe_info =
+ *(MdpYUVPipeInfo*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
+ Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
+ ovutils::eDest indexL = pipe_info.lIndex;
+ ovutils::eDest indexR = pipe_info.rIndex;
+ int fd = hnd->fd;
+ uint32_t offset = (uint32_t)hnd->offset;
+ if(rot) {
+ rot->queueBuffer(fd, offset);
+ fd = rot->getDstMemId();
+ offset = rot->getDstOffset();
+ }
+ if(indexL != ovutils::OV_INVALID) {
+ ovutils::eDest destL = (ovutils::eDest)indexL;
+ ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+ using pipe: %d", __FUNCTION__, layer, hnd, indexL );
+ if (!ov.queueBuffer(fd, offset, destL)) {
+ ALOGE("%s: queueBuffer failed for display:%d",
+ __FUNCTION__, mDpy);
+ return false;
+ }
+ }
+
+ if(indexR != ovutils::OV_INVALID) {
+ ovutils::eDest destR = (ovutils::eDest)indexR;
+ ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+ using pipe: %d", __FUNCTION__, layer, hnd, indexR );
+ if (!ov.queueBuffer(fd, offset, destR)) {
+ ALOGE("%s: queueBuffer failed for display:%d",
+ __FUNCTION__, mDpy);
+ return false;
+ }
+ }
+ }
+ else{
+ MdpPipeInfoSplit& pipe_info =
+ *(MdpPipeInfoSplit*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
+ Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
+
+ ovutils::eDest indexL = pipe_info.lIndex;
+ ovutils::eDest indexR = pipe_info.rIndex;
+
+ int fd = hnd->fd;
+ uint32_t offset = (uint32_t)hnd->offset;
+ int index = ctx->mPtorInfo.getPTORArrayIndex(i);
+ if (!mDpy && (index != -1)) {
+ hnd = ctx->mCopyBit[mDpy]->getCurrentRenderBuffer();
+ fd = hnd->fd;
+ offset = 0;
+ }
+
+ if(ctx->mAD->draw(ctx, fd, offset)) {
+ fd = ctx->mAD->getDstFd();
+ offset = ctx->mAD->getDstOffset();
+ }
+
+ if(rot) {
+ rot->queueBuffer(fd, offset);
+ fd = rot->getDstMemId();
+ offset = rot->getDstOffset();
+ }
+
+ //************* play left mixer **********
+ if(indexL != ovutils::OV_INVALID) {
+ ovutils::eDest destL = (ovutils::eDest)indexL;
+ ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+ using pipe: %d", __FUNCTION__, layer, hnd, indexL );
+ if (!ov.queueBuffer(fd, offset, destL)) {
+ ALOGE("%s: queueBuffer failed for left mixer",
+ __FUNCTION__);
+ return false;
+ }
+ }
+
+ //************* play right mixer **********
+ if(indexR != ovutils::OV_INVALID) {
+ ovutils::eDest destR = (ovutils::eDest)indexR;
+ ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+ using pipe: %d", __FUNCTION__, layer, hnd, indexR );
+ if (!ov.queueBuffer(fd, offset, destR)) {
+ ALOGE("%s: queueBuffer failed for right mixer",
+ __FUNCTION__);
+ return false;
+ }
+ }
+ }
+
+ layerProp[i].mFlags &= ~HWC_MDPCOMP;
+ }
+
+ return true;
+}
+
+//================MDPCompSrcSplit==============================================
+bool MDPCompSrcSplit::acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer,
+ MdpPipeInfoSplit& pipe_info) {
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ hwc_rect_t dst = layer->displayFrame;
+ hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+ pipe_info.lIndex = ovutils::OV_INVALID;
+ pipe_info.rIndex = ovutils::OV_INVALID;
+
+ //If 2 pipes are staged on a single stage of a mixer, then the left pipe
+ //should have a higher priority than the right one. Pipe priorities are
+ //starting with VG0, VG1 ... , RGB0 ..., DMA1
+
+ Overlay::PipeSpecs pipeSpecs;
+ pipeSpecs.formatClass = isYuvBuffer(hnd) ?
+ Overlay::FORMAT_YUV : Overlay::FORMAT_RGB;
+ pipeSpecs.needsScaling = qhwc::needsScaling(layer);
+ pipeSpecs.dpy = mDpy;
+ pipeSpecs.fb = false;
+
+ //1 pipe by default for a layer
+ pipe_info.lIndex = ctx->mOverlay->getPipe(pipeSpecs);
+ if(pipe_info.lIndex == ovutils::OV_INVALID) {
+ return false;
+ }
+
+ /* Use 2 pipes IF
+ a) Layer's crop width is > 2048 or
+ b) Layer's dest width > 2048 or
+ c) On primary, driver has indicated with caps to split always. This is
+ based on an empirically derived value of panel height. Applied only
+ if the layer's width is > mixer's width
+ */
+
+ MDPVersion& mdpHw = MDPVersion::getInstance();
+ bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and
+ mdpHw.isSrcSplitAlways();
+ int lSplit = getLeftSplit(ctx, mDpy);
+ int dstWidth = dst.right - dst.left;
+ int cropWidth = has90Transform(layer) ? crop.bottom - crop.top :
+ crop.right - crop.left;
+
+ //TODO Even if a 4k video is going to be rot-downscaled to dimensions under
+ //pipe line length, we are still using 2 pipes. This is fine just because
+ //this is source split where destination doesn't matter. Evaluate later to
+ //see if going through all the calcs to save a pipe is worth it
+ if(dstWidth > (int) mdpHw.getMaxMixerWidth() or
+ cropWidth > (int) mdpHw.getMaxMixerWidth() or
+ (primarySplitAlways and (cropWidth > lSplit))) {
+ pipe_info.rIndex = ctx->mOverlay->getPipe(pipeSpecs);
+ if(pipe_info.rIndex == ovutils::OV_INVALID) {
+ return false;
+ }
+
+ // Return values
+ // 1 Left pipe is higher priority, do nothing.
+ // 0 Pipes of same priority.
+ //-1 Right pipe is of higher priority, needs swap.
+ if(ctx->mOverlay->comparePipePriority(pipe_info.lIndex,
+ pipe_info.rIndex) == -1) {
+ qhwc::swap(pipe_info.lIndex, pipe_info.rIndex);
+ }
+ }
+
+ return true;
+}
+
+int MDPCompSrcSplit::configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ PipeLayerPair& PipeLayerPair) {
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(!hnd) {
+ ALOGE("%s: layer handle is NULL", __FUNCTION__);
+ return -1;
+ }
+ MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+ MdpPipeInfoSplit& mdp_info =
+ *(static_cast<MdpPipeInfoSplit*>(PipeLayerPair.pipeInfo));
+ Rotator **rot = &PipeLayerPair.rot;
+ eZorder z = static_cast<eZorder>(mdp_info.zOrder);
+ eDest lDest = mdp_info.lIndex;
+ eDest rDest = mdp_info.rIndex;
+ hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+ hwc_rect_t dst = layer->displayFrame;
+ int transform = layer->transform;
+ eTransform orient = static_cast<eTransform>(transform);
+ int rotFlags = ROT_FLAGS_NONE;
+ uint32_t format = ovutils::getMdpFormat(hnd->format, isTileRendered(hnd));
+ Whf whf(getWidth(hnd), getHeight(hnd), format, hnd->size);
+
+ ALOGD_IF(isDebug(),"%s: configuring: layer: %p z_order: %d dest_pipeL: %d"
+ "dest_pipeR: %d",__FUNCTION__, layer, z, lDest, rDest);
+
+ // Handle R/B swap
+ if (layer->flags & HWC_FORMAT_RB_SWAP) {
+ if (hnd->format == HAL_PIXEL_FORMAT_RGBA_8888)
+ whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRA_8888);
+ else if (hnd->format == HAL_PIXEL_FORMAT_RGBX_8888)
+ whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRX_8888);
+ }
+ // update source crop and destination position of AIV video layer.
+ if(ctx->listStats[mDpy].mAIVVideoMode && isYuvBuffer(hnd)) {
+ updateCoordinates(ctx, crop, dst, mDpy);
+ }
+ /* Calculate the external display position based on MDP downscale,
+ ActionSafe, and extorientation features. */
+ calcExtDisplayPosition(ctx, hnd, mDpy, crop, dst, transform, orient);
+
+ int downscale = getRotDownscale(ctx, layer);
+ eMdpFlags mdpFlags = OV_MDP_BACKEND_COMPOSITION;
+ setMdpFlags(ctx, layer, mdpFlags, downscale, transform);
+
+ if(lDest != OV_INVALID && rDest != OV_INVALID) {
+ //Enable overfetch
+ setMdpFlags(mdpFlags, OV_MDSS_MDP_DUAL_PIPE);
+ }
+
+ if((has90Transform(layer) or downscale) and isRotationDoable(ctx, hnd)) {
+ (*rot) = ctx->mRotMgr->getNext();
+ if((*rot) == NULL) return -1;
+ ctx->mLayerRotMap[mDpy]->add(layer, *rot);
+ //If the video is using a single pipe, enable BWC
+ if(rDest == OV_INVALID) {
+ BwcPM::setBwc(crop, dst, transform, downscale, mdpFlags);
+ }
+ //Configure rotator for pre-rotation
+ if(configRotator(*rot, whf, crop, mdpFlags, orient, downscale) < 0) {
+ ALOGE("%s: configRotator failed!", __FUNCTION__);
+ return -1;
+ }
+ updateSource(orient, whf, crop, *rot);
+ rotFlags |= ovutils::ROT_PREROTATED;
+ }
+
+ //If 2 pipes being used, divide layer into half, crop and dst
+ hwc_rect_t cropL = crop;
+ hwc_rect_t cropR = crop;
+ hwc_rect_t dstL = dst;
+ hwc_rect_t dstR = dst;
+ if(lDest != OV_INVALID && rDest != OV_INVALID) {
+ cropL.right = (crop.right + crop.left) / 2;
+ cropR.left = cropL.right;
+ sanitizeSourceCrop(cropL, cropR, hnd);
+
+ bool cropSwap = false;
+ //Swap crops on H flip since 2 pipes are being used
+ if((orient & OVERLAY_TRANSFORM_FLIP_H) && (*rot) == NULL) {
+ hwc_rect_t tmp = cropL;
+ cropL = cropR;
+ cropR = tmp;
+ cropSwap = true;
+ }
+
+ //cropSwap trick: If the src and dst widths are both odd, let us say
+ //2507, then splitting both into half would cause left width to be 1253
+ //and right 1254. If crop is swapped because of H flip, this will cause
+ //left crop width to be 1254, whereas left dst width remains 1253, thus
+ //inducing a scaling that is unaccounted for. To overcome that we add 1
+ //to the dst width if there is a cropSwap. So if the original width was
+ //2507, the left dst width will be 1254. Even if the original width was
+ //even for ex: 2508, the left dst width will still remain 1254.
+ dstL.right = (dst.right + dst.left + cropSwap) / 2;
+ dstR.left = dstL.right;
+ }
+
+ //For the mdp, since either we are pre-rotating or MDP does flips
+ orient = OVERLAY_TRANSFORM_0;
+ transform = 0;
+
+ //configure left pipe
+ if(lDest != OV_INVALID) {
+ PipeArgs pargL(mdpFlags, whf, z,
+ static_cast<eRotFlags>(rotFlags), layer->planeAlpha,
+ (ovutils::eBlending) getBlending(layer->blending));
+
+ if(configMdp(ctx->mOverlay, pargL, orient,
+ cropL, dstL, metadata, lDest) < 0) {
+ ALOGE("%s: commit failed for left mixer config", __FUNCTION__);
+ return -1;
+ }
+ }
+
+ //configure right pipe
+ if(rDest != OV_INVALID) {
+ PipeArgs pargR(mdpFlags, whf, z,
+ static_cast<eRotFlags>(rotFlags),
+ layer->planeAlpha,
+ (ovutils::eBlending) getBlending(layer->blending));
+ if(configMdp(ctx->mOverlay, pargR, orient,
+ cropR, dstR, metadata, rDest) < 0) {
+ ALOGE("%s: commit failed for right mixer config", __FUNCTION__);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int MDPComp::getPartialUpdatePref(hwc_context_t *ctx) {
+ Locker::Autolock _l(ctx->mDrawLock);
+ const int fbNum = Overlay::getFbForDpy(Overlay::DPY_PRIMARY);
+ char path[MAX_SYSFS_FILE_PATH];
+ snprintf (path, sizeof(path), "sys/class/graphics/fb%d/dyn_pu", fbNum);
+ int fd = open(path, O_RDONLY);
+ if(fd < 0) {
+ ALOGE("%s: Failed to open sysfs node: %s", __FUNCTION__, path);
+ return -1;
+ }
+ char value[4];
+ ssize_t size_read = read(fd, value, sizeof(value)-1);
+ if(size_read <= 0) {
+ ALOGE("%s: Failed to read sysfs node: %s", __FUNCTION__, path);
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ value[size_read] = '\0';
+ return atoi(value);
+}
+
+int MDPComp::setPartialUpdatePref(hwc_context_t *ctx, bool enable) {
+ Locker::Autolock _l(ctx->mDrawLock);
+ const int fbNum = Overlay::getFbForDpy(Overlay::DPY_PRIMARY);
+ char path[MAX_SYSFS_FILE_PATH];
+ snprintf (path, sizeof(path), "sys/class/graphics/fb%d/dyn_pu", fbNum);
+ int fd = open(path, O_WRONLY);
+ if(fd < 0) {
+ ALOGE("%s: Failed to open sysfs node: %s", __FUNCTION__, path);
+ return -1;
+ }
+ char value[4];
+ snprintf(value, sizeof(value), "%d", (int)enable);
+ ssize_t ret = write(fd, value, strlen(value));
+ if(ret <= 0) {
+ ALOGE("%s: Failed to write to sysfs nodes: %s", __FUNCTION__, path);
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ return 0;
+}
+}; //namespace
+
diff --git a/msm8909/libhwcomposer/hwc_mdpcomp.h b/msm8909/libhwcomposer/hwc_mdpcomp.h
new file mode 100644
index 0000000..e6b0228
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_mdpcomp.h
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2012-2015, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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_MDP_COMP
+#define HWC_MDP_COMP
+
+#include <hwc_utils.h>
+#include <idle_invalidator.h>
+#include <cutils/properties.h>
+#include <overlay.h>
+
+#define MAX_PIPES_PER_MIXER 4
+
+namespace overlay {
+class Rotator;
+};
+
+namespace qhwc {
+namespace ovutils = overlay::utils;
+
+class MDPComp {
+public:
+ explicit MDPComp(int);
+ virtual ~MDPComp(){};
+ /*sets up mdp comp for the current frame */
+ int prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+ /* draw */
+ virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list) = 0;
+ //Reset values
+ void reset();
+ /* dumpsys */
+ void dump(android::String8& buf, hwc_context_t *ctx);
+ bool isGLESOnlyComp() { return (mCurrentFrame.mdpCount == 0); }
+ bool isMDPComp() { return mModeOn; }
+ int drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+ static MDPComp* getObject(hwc_context_t *ctx, const int& dpy);
+ /* Handler to invoke frame redraw on Idle Timer expiry */
+ static void timeout_handler(void *udata);
+ /* Initialize MDP comp*/
+ static bool init(hwc_context_t *ctx);
+ static void resetIdleFallBack() { sIdleFallBack = false; }
+ static bool isIdleFallback() { return sIdleFallBack; }
+ static void dynamicDebug(bool enable){ sDebugLogs = enable; }
+ static void setIdleTimeout(const uint32_t& timeout);
+ static int setPartialUpdatePref(hwc_context_t *ctx, bool enable);
+ void setDynRefreshRate(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+ static int getPartialUpdatePref(hwc_context_t *ctx);
+ static void enablePartialUpdate(bool enable)
+ { sIsPartialUpdateActive = enable; };
+
+protected:
+ enum { MAX_SEC_LAYERS = 1 }; //TODO add property support
+
+ enum ePipeType {
+ MDPCOMP_OV_RGB = ovutils::OV_MDP_PIPE_RGB,
+ MDPCOMP_OV_VG = ovutils::OV_MDP_PIPE_VG,
+ MDPCOMP_OV_DMA = ovutils::OV_MDP_PIPE_DMA,
+ MDPCOMP_OV_ANY,
+ };
+
+ //Simulation flags
+ enum {
+ MDPCOMP_AVOID_FULL_MDP = 0x001,
+ MDPCOMP_AVOID_CACHE_MDP = 0x002,
+ MDPCOMP_AVOID_LOAD_MDP = 0x004,
+ MDPCOMP_AVOID_VIDEO_ONLY = 0x008,
+ MDPCOMP_AVOID_MDP_ONLY_LAYERS = 0x010,
+ };
+
+ /* mdp pipe data */
+ struct MdpPipeInfo {
+ int zOrder;
+ virtual ~MdpPipeInfo(){};
+ };
+
+ struct MdpYUVPipeInfo : public MdpPipeInfo{
+ ovutils::eDest lIndex;
+ ovutils::eDest rIndex;
+ virtual ~MdpYUVPipeInfo(){};
+ };
+
+ /* per layer data */
+ struct PipeLayerPair {
+ MdpPipeInfo *pipeInfo;
+ overlay::Rotator* rot;
+ int listIndex;
+ };
+
+ /* per frame data */
+ struct FrameInfo {
+ /* maps layer list to mdp list */
+ int layerCount;
+ int layerToMDP[MAX_NUM_APP_LAYERS];
+
+ /* maps mdp list to layer list */
+ int mdpCount;
+ struct PipeLayerPair mdpToLayer[MAX_PIPES_PER_MIXER];
+
+ /* layer composing on FB? */
+ int fbCount;
+ bool isFBComposed[MAX_NUM_APP_LAYERS];
+ /* layers lying outside ROI. Will
+ * be dropped off from the composition */
+ int dropCount;
+ bool drop[MAX_NUM_APP_LAYERS];
+
+ bool needsRedraw;
+ int fbZ;
+
+ /* c'tor */
+ FrameInfo();
+ /* clear old frame data */
+ void reset(const int& numLayers);
+ void map();
+ };
+
+ /* cached data */
+ struct LayerCache {
+ int layerCount;
+ bool isFBComposed[MAX_NUM_APP_LAYERS];
+ bool drop[MAX_NUM_APP_LAYERS];
+
+ /* c'tor */
+ LayerCache();
+ /* clear caching info*/
+ void reset();
+ void updateCounts(const FrameInfo&);
+ bool isSameFrame(const FrameInfo& curFrame,
+ hwc_display_contents_1_t* list);
+ bool isSameFrame(hwc_context_t *ctx, int dpy,
+ hwc_display_contents_1_t* list);
+ };
+
+ /* allocates pipe from pipe book */
+ virtual bool allocLayerPipes(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) = 0;
+ /* configures MPD pipes */
+ virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ PipeLayerPair& pipeLayerPair) = 0;
+ /* Increments mdpCount if 4k2k yuv layer split is enabled.
+ * updates framebuffer z order if fb lies above source-split layer */
+ virtual void adjustForSourceSplit(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) = 0;
+ /* configures 4kx2k yuv layer*/
+ virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ PipeLayerPair& PipeLayerPair) = 0;
+ /* generates ROI based on the modified area of the frame */
+ virtual void generateROI(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) = 0;
+ /* validates the ROI generated for fallback conditions */
+ virtual bool validateAndApplyROI(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) = 0;
+ /* Trims fbRect calculated against ROI generated */
+ virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect) = 0;
+
+ /* set/reset flags for MDPComp */
+ void setMDPCompLayerFlags(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list);
+ void setRedraw(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list);
+ /* checks for conditions where mdpcomp is not possible */
+ bool isFrameDoable(hwc_context_t *ctx);
+ /* checks for conditions where RGB layers cannot be bypassed */
+ bool tryFullFrame(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+ /* checks if full MDP comp can be done */
+ bool fullMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+ /* Full MDP Composition with Peripheral Tiny Overlap Removal */
+ bool fullMDPCompWithPTOR(hwc_context_t *ctx,hwc_display_contents_1_t* list);
+ /* check if we can use layer cache to do at least partial MDP comp */
+ bool partialMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+ /* Partial MDP comp that uses caching to save power as primary goal */
+ bool cacheBasedComp(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+ /* Partial MDP comp that balances the load between MDP and GPU such that
+ * MDP is loaded to the max of its capacity. The lower z order layers are
+ * fed to MDP, whereas the upper ones to GPU, because the upper ones have
+ * lower number of pixels and can reduce GPU processing time */
+ bool loadBasedComp(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+ /* Checks if its worth doing load based partial comp */
+ bool isLoadBasedCompDoable(hwc_context_t *ctx);
+ /* checks for conditions where only video can be bypassed */
+ bool tryVideoOnly(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+ bool videoOnlyComp(hwc_context_t *ctx, hwc_display_contents_1_t* list,
+ bool secureOnly);
+ /* checks for conditions where only secure RGB and video can be bypassed */
+ bool tryMDPOnlyLayers(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+ bool mdpOnlyLayersComp(hwc_context_t *ctx, hwc_display_contents_1_t* list,
+ bool secureOnly);
+ /* checks for conditions where YUV layers cannot be bypassed */
+ bool isYUVDoable(hwc_context_t* ctx, hwc_layer_1_t* layer);
+ /* checks for conditions where Secure RGB layers cannot be bypassed */
+ bool isSecureRGBDoable(hwc_context_t* ctx, hwc_layer_1_t* layer);
+ /* checks if MDP/MDSS can process current list w.r.to HW limitations
+ * All peculiar HW limitations should go here */
+ bool hwLimitationsCheck(hwc_context_t* ctx, hwc_display_contents_1_t* list);
+ /* Is debug enabled */
+ static bool isDebug() { return sDebugLogs ? true : false; };
+ /* Is feature enabled */
+ static bool isEnabled() { return sEnabled; };
+ /* checks for mdp comp dimension limitation */
+ bool isValidDimension(hwc_context_t *ctx, hwc_layer_1_t *layer);
+ /* tracks non updating layers*/
+ void updateLayerCache(hwc_context_t* ctx, hwc_display_contents_1_t* list,
+ FrameInfo& frame);
+ /* optimize layers for mdp comp*/
+ bool markLayersForCaching(hwc_context_t* ctx,
+ hwc_display_contents_1_t* list);
+ int getBatch(hwc_display_contents_1_t* list,
+ int& maxBatchStart, int& maxBatchEnd,
+ int& maxBatchCount);
+ bool canPushBatchToTop(const hwc_display_contents_1_t* list,
+ int fromIndex, int toIndex);
+ bool intersectingUpdatingLayers(const hwc_display_contents_1_t* list,
+ int fromIndex, int toIndex, int targetLayerIndex);
+
+ /* drop other non-AIV layers from external display list.*/
+ void dropNonAIVLayers(hwc_context_t* ctx, hwc_display_contents_1_t* list);
+
+ /* updates cache map with YUV info */
+ void updateYUV(hwc_context_t* ctx, hwc_display_contents_1_t* list,
+ bool secureOnly, FrameInfo& frame);
+ /* updates cache map with secure RGB info */
+ void updateSecureRGB(hwc_context_t* ctx,
+ hwc_display_contents_1_t* list);
+ /* Validates if the GPU/MDP layer split chosen by a strategy is supported
+ * by MDP.
+ * Sets up MDP comp data structures to reflect covnversion from layers to
+ * overlay pipes.
+ * Configures overlay.
+ * Configures if GPU should redraw.
+ */
+ bool postHeuristicsHandling(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list);
+ void reset(hwc_context_t *ctx);
+ bool isSupportedForMDPComp(hwc_context_t *ctx, hwc_layer_1_t* layer);
+ bool resourceCheck(hwc_context_t* ctx, hwc_display_contents_1_t* list);
+ hwc_rect_t getUpdatingFBRect(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list);
+ /* checks for conditions to enable partial udpate */
+ bool canPartialUpdate(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+
+ int mDpy;
+ static bool sEnabled;
+ static bool sEnableMixedMode;
+ static int sSimulationFlags;
+ static bool sDebugLogs;
+ static bool sIdleFallBack;
+ static int sMaxPipesPerMixer;
+ static bool sSrcSplitEnabled;
+ static IdleInvalidator *sIdleInvalidator;
+ struct FrameInfo mCurrentFrame;
+ struct LayerCache mCachedFrame;
+ static bool sIsPartialUpdateActive;
+ //Enable 4kx2k yuv layer split
+ static bool sEnableYUVsplit;
+ bool mModeOn; // if prepare happened
+ bool allocSplitVGPipesfor4k2k(hwc_context_t *ctx, int index);
+ bool mPrevModeOn; //if previous prepare happened
+ //Enable Partial Update for MDP3 targets
+ static bool enablePartialUpdateForMDP3;
+};
+
+class MDPCompNonSplit : public MDPComp {
+public:
+ explicit MDPCompNonSplit(int dpy):MDPComp(dpy){};
+ virtual ~MDPCompNonSplit(){};
+ virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list);
+
+private:
+ struct MdpPipeInfoNonSplit : public MdpPipeInfo {
+ ovutils::eDest index;
+ virtual ~MdpPipeInfoNonSplit() {};
+ };
+
+ /* configure's overlay pipes for the frame */
+ virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ PipeLayerPair& pipeLayerPair);
+
+ /* allocates pipes to selected candidates */
+ virtual bool allocLayerPipes(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list);
+
+ /* Increments mdpCount if 4k2k yuv layer split is enabled.
+ * updates framebuffer z order if fb lies above source-split layer */
+ virtual void adjustForSourceSplit(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list);
+
+ /* configures 4kx2k yuv layer to 2 VG pipes*/
+ virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ PipeLayerPair& PipeLayerPair);
+ /* generates ROI based on the modified area of the frame */
+ virtual void generateROI(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list);
+ /* validates the ROI generated for fallback conditions */
+ virtual bool validateAndApplyROI(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list);
+ /* Trims fbRect calculated against ROI generated */
+ virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect);
+};
+
+class MDPCompSplit : public MDPComp {
+public:
+ explicit MDPCompSplit(int dpy):MDPComp(dpy){};
+ virtual ~MDPCompSplit(){};
+ virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list);
+
+protected:
+ struct MdpPipeInfoSplit : public MdpPipeInfo {
+ ovutils::eDest lIndex;
+ ovutils::eDest rIndex;
+ virtual ~MdpPipeInfoSplit() {};
+ };
+
+ virtual bool acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer,
+ MdpPipeInfoSplit& pipe_info);
+
+ /* configure's overlay pipes for the frame */
+ virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ PipeLayerPair& pipeLayerPair);
+
+ /* allocates pipes to selected candidates */
+ virtual bool allocLayerPipes(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list);
+private:
+ /* Increments mdpCount if 4k2k yuv layer split is enabled.
+ * updates framebuffer z order if fb lies above source-split layer */
+ virtual void adjustForSourceSplit(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list);
+
+ /* configures 4kx2k yuv layer*/
+ virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ PipeLayerPair& PipeLayerPair);
+ /* generates ROI based on the modified area of the frame */
+ virtual void generateROI(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list);
+ /* validates the ROI generated for fallback conditions */
+ virtual bool validateAndApplyROI(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list);
+ /* Trims fbRect calculated against ROI generated */
+ virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect);
+};
+
+class MDPCompSrcSplit : public MDPCompSplit {
+public:
+ explicit MDPCompSrcSplit(int dpy) : MDPCompSplit(dpy){};
+ virtual ~MDPCompSrcSplit(){};
+private:
+ virtual bool acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer,
+ MdpPipeInfoSplit& pipe_info);
+
+ virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ PipeLayerPair& pipeLayerPair);
+};
+
+}; //namespace
+#endif
diff --git a/msm8909/libhwcomposer/hwc_qclient.cpp b/msm8909/libhwcomposer/hwc_qclient.cpp
new file mode 100644
index 0000000..4db4fa7
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_qclient.cpp
@@ -0,0 +1,401 @@
+/*
+ * Copyright (c) 2013-15, The Linux Foundation. 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 The Linux Foundation 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 CLIENTS; 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 <hwc_qclient.h>
+#include <IQService.h>
+#include <hwc_utils.h>
+#include <mdp_version.h>
+#include <hwc_mdpcomp.h>
+#include <hwc_virtual.h>
+#include <overlay.h>
+#include <display_config.h>
+#include <hwc_qdcm.h>
+
+#define QCLIENT_DEBUG 0
+
+using namespace android;
+using namespace qService;
+using namespace qhwc;
+using namespace overlay;
+using namespace qdutils;
+using namespace qQdcm;
+
+namespace qClient {
+
+// ----------------------------------------------------------------------------
+QClient::QClient(hwc_context_t *ctx) : mHwcContext(ctx),
+ mMPDeathNotifier(new MPDeathNotifier(ctx))
+{
+ ALOGD_IF(QCLIENT_DEBUG, "QClient Constructor invoked");
+}
+
+QClient::~QClient()
+{
+ ALOGD_IF(QCLIENT_DEBUG,"QClient Destructor invoked");
+}
+
+static void securing(hwc_context_t *ctx, uint32_t startEnd) {
+ //The only way to make this class in this process subscribe to media
+ //player's death.
+ IMediaDeathNotifier::getMediaPlayerService();
+
+ ctx->mDrawLock.lock();
+ ctx->mSecuring = startEnd;
+ //We're done securing
+ if(startEnd == IQService::END)
+ ctx->mSecureMode = true;
+ ctx->mDrawLock.unlock();
+
+ if(ctx->proc)
+ ctx->proc->invalidate(ctx->proc);
+}
+
+static void unsecuring(hwc_context_t *ctx, uint32_t startEnd) {
+ ctx->mDrawLock.lock();
+ ctx->mSecuring = startEnd;
+ //We're done unsecuring
+ if(startEnd == IQService::END)
+ ctx->mSecureMode = false;
+ ctx->mDrawLock.unlock();
+
+ if(ctx->proc)
+ ctx->proc->invalidate(ctx->proc);
+}
+
+void QClient::MPDeathNotifier::died() {
+ mHwcContext->mDrawLock.lock();
+ ALOGD_IF(QCLIENT_DEBUG, "Media Player died");
+ mHwcContext->mSecuring = false;
+ mHwcContext->mSecureMode = false;
+ mHwcContext->mDrawLock.unlock();
+ if(mHwcContext->proc)
+ mHwcContext->proc->invalidate(mHwcContext->proc);
+}
+
+static android::status_t screenRefresh(hwc_context_t *ctx) {
+ status_t result = NO_INIT;
+ if(ctx->proc) {
+ ctx->proc->invalidate(ctx->proc);
+ result = NO_ERROR;
+ }
+ return result;
+}
+
+static void setExtOrientation(hwc_context_t *ctx, uint32_t orientation) {
+ ctx->mExtOrientation = orientation;
+}
+
+static void isExternalConnected(hwc_context_t* ctx, Parcel* outParcel) {
+ int connected;
+ connected = ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected ? 1 : 0;
+ outParcel->writeInt32(connected);
+}
+
+static void getDisplayAttributes(hwc_context_t* ctx, const Parcel* inParcel,
+ Parcel* outParcel) {
+ int dpy = inParcel->readInt32();
+ outParcel->writeInt32(ctx->dpyAttr[dpy].vsync_period);
+ if (ctx->dpyAttr[dpy].customFBSize) {
+ outParcel->writeInt32(ctx->dpyAttr[dpy].xres_new);
+ outParcel->writeInt32(ctx->dpyAttr[dpy].yres_new);
+ } else {
+ outParcel->writeInt32(ctx->dpyAttr[dpy].xres);
+ outParcel->writeInt32(ctx->dpyAttr[dpy].yres);
+ }
+ outParcel->writeFloat(ctx->dpyAttr[dpy].xdpi);
+ outParcel->writeFloat(ctx->dpyAttr[dpy].ydpi);
+ //XXX: Need to check what to return for HDMI
+ outParcel->writeInt32(ctx->mMDP.panel);
+}
+static void setHSIC(const Parcel* inParcel) {
+ int dpy = inParcel->readInt32();
+ ALOGD_IF(0, "In %s: dpy = %d", __FUNCTION__, dpy);
+ HSICData_t hsic_data;
+ hsic_data.hue = inParcel->readInt32();
+ hsic_data.saturation = inParcel->readFloat();
+ hsic_data.intensity = inParcel->readInt32();
+ hsic_data.contrast = inParcel->readFloat();
+ //XXX: Actually set the HSIC data through ABL lib
+}
+
+
+static void setBufferMirrorMode(hwc_context_t *ctx, uint32_t enable) {
+ ctx->mBufferMirrorMode = enable;
+}
+
+static status_t getDisplayVisibleRegion(hwc_context_t* ctx, int dpy,
+ Parcel* outParcel) {
+ // Get the info only if the dpy is valid
+ if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) {
+ Locker::Autolock _sl(ctx->mDrawLock);
+ if(dpy && (ctx->mExtOrientation || ctx->mBufferMirrorMode)) {
+ // Return the destRect on external, if external orienation
+ // is enabled
+ outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.left);
+ outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.top);
+ outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.right);
+ outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.bottom);
+ } else {
+ outParcel->writeInt32(ctx->mViewFrame[dpy].left);
+ outParcel->writeInt32(ctx->mViewFrame[dpy].top);
+ outParcel->writeInt32(ctx->mViewFrame[dpy].right);
+ outParcel->writeInt32(ctx->mViewFrame[dpy].bottom);
+ }
+ return NO_ERROR;
+ } else {
+ ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy);
+ return BAD_VALUE;
+ }
+}
+
+// USed for setting the secondary(hdmi/wfd) status
+static void setSecondaryDisplayStatus(hwc_context_t *ctx,
+ const Parcel* inParcel) {
+ uint32_t dpy = inParcel->readInt32();
+ uint32_t status = inParcel->readInt32();
+ ALOGD_IF(QCLIENT_DEBUG, "%s: dpy = %d status = %s", __FUNCTION__,
+ dpy, getExternalDisplayState(status));
+
+ if(dpy > HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) {
+ if(dpy == HWC_DISPLAY_VIRTUAL && status == qdutils::EXTERNAL_OFFLINE) {
+ ctx->mWfdSyncLock.lock();
+ ctx->mWfdSyncLock.signal();
+ ctx->mWfdSyncLock.unlock();
+ } else if(status == qdutils::EXTERNAL_PAUSE) {
+ handle_pause(ctx, dpy);
+ } else if(status == qdutils::EXTERNAL_RESUME) {
+ handle_resume(ctx, dpy);
+ }
+ } else {
+ ALOGE("%s: Invalid dpy %d", __FUNCTION__, dpy);
+ return;
+ }
+}
+
+
+static status_t setViewFrame(hwc_context_t* ctx, const Parcel* inParcel) {
+ int dpy = inParcel->readInt32();
+ if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) {
+ Locker::Autolock _sl(ctx->mDrawLock);
+ ctx->mViewFrame[dpy].left = inParcel->readInt32();
+ ctx->mViewFrame[dpy].top = inParcel->readInt32();
+ ctx->mViewFrame[dpy].right = inParcel->readInt32();
+ ctx->mViewFrame[dpy].bottom = inParcel->readInt32();
+ ALOGD_IF(QCLIENT_DEBUG, "%s: mViewFrame[%d] = [%d %d %d %d]",
+ __FUNCTION__, dpy,
+ ctx->mViewFrame[dpy].left, ctx->mViewFrame[dpy].top,
+ ctx->mViewFrame[dpy].right, ctx->mViewFrame[dpy].bottom);
+ return NO_ERROR;
+ } else {
+ ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy);
+ return BAD_VALUE;
+ }
+}
+
+static void toggleDynamicDebug(hwc_context_t* ctx, const Parcel* inParcel) {
+ int debug_type = inParcel->readInt32();
+ bool enable = !!inParcel->readInt32();
+ ALOGD("%s: debug_type: %d enable:%d",
+ __FUNCTION__, debug_type, enable);
+ Locker::Autolock _sl(ctx->mDrawLock);
+ switch (debug_type) {
+ //break is ignored for DEBUG_ALL to toggle all of them at once
+ case IQService::DEBUG_ALL:
+ case IQService::DEBUG_MDPCOMP:
+ qhwc::MDPComp::dynamicDebug(enable);
+ if (debug_type != IQService::DEBUG_ALL)
+ break;
+ case IQService::DEBUG_VSYNC:
+ ctx->vstate.debug = enable;
+ if (debug_type != IQService::DEBUG_ALL)
+ break;
+ case IQService::DEBUG_VD:
+ HWCVirtualVDS::dynamicDebug(enable);
+ if (debug_type != IQService::DEBUG_ALL)
+ break;
+ case IQService::DEBUG_PIPE_LIFECYCLE:
+ Overlay::debugPipeLifecycle(enable);
+ if (debug_type != IQService::DEBUG_ALL)
+ break;
+ }
+}
+
+static void setIdleTimeout(hwc_context_t* ctx, const Parcel* inParcel) {
+ uint32_t timeout = (uint32_t)inParcel->readInt32();
+ ALOGD("%s :%u ms", __FUNCTION__, timeout);
+ Locker::Autolock _sl(ctx->mDrawLock);
+ MDPComp::setIdleTimeout(timeout);
+}
+
+static void configureDynRefreshRate(hwc_context_t* ctx,
+ const Parcel* inParcel) {
+ uint32_t op = (uint32_t)inParcel->readInt32();
+ uint32_t refresh_rate = (uint32_t)inParcel->readInt32();
+ MDPVersion& mdpHw = MDPVersion::getInstance();
+ uint32_t dpy = HWC_DISPLAY_PRIMARY;
+
+ if(mdpHw.isDynFpsSupported()) {
+ Locker::Autolock _sl(ctx->mDrawLock);
+
+ switch (op) {
+ case DISABLE_METADATA_DYN_REFRESH_RATE:
+ ctx->mUseMetaDataRefreshRate = false;
+ setRefreshRate(ctx, dpy, ctx->dpyAttr[dpy].refreshRate);
+ break;
+ case ENABLE_METADATA_DYN_REFRESH_RATE:
+ ctx->mUseMetaDataRefreshRate = true;
+ setRefreshRate(ctx, dpy, ctx->dpyAttr[dpy].refreshRate);
+ break;
+ case SET_BINDER_DYN_REFRESH_RATE:
+ if(ctx->mUseMetaDataRefreshRate)
+ ALOGW("%s: Ignoring binder request to change refresh-rate",
+ __FUNCTION__);
+ else {
+ uint32_t rate = roundOff(refresh_rate);
+ if((rate >= mdpHw.getMinFpsSupported() &&
+ rate <= mdpHw.getMaxFpsSupported())) {
+ setRefreshRate(ctx, dpy, rate);
+ } else {
+ ALOGE("%s: Requested refresh-rate should be between \
+ (%d) and (%d). Given (%d)", __FUNCTION__,
+ mdpHw.getMinFpsSupported(),
+ mdpHw.getMaxFpsSupported(), rate);
+ }
+ }
+ break;
+ default:
+ ALOGE("%s: Invalid op %d",__FUNCTION__,op);
+ }
+ }
+}
+
+static status_t setPartialUpdateState(hwc_context_t *ctx, uint32_t state) {
+ ALOGD("%s: state: %d", __FUNCTION__, state);
+ switch(state) {
+ case IQService::PREF_PARTIAL_UPDATE:
+ if(qhwc::MDPComp::setPartialUpdatePref(ctx, true) < 0)
+ return NO_INIT;
+ return NO_ERROR;
+ case IQService::PREF_POST_PROCESSING:
+ if(qhwc::MDPComp::setPartialUpdatePref(ctx, false) < 0)
+ return NO_INIT;
+ qhwc::MDPComp::enablePartialUpdate(false);
+ return NO_ERROR;
+ case IQService::ENABLE_PARTIAL_UPDATE:
+ qhwc::MDPComp::enablePartialUpdate(true);
+ return NO_ERROR;
+ default:
+ ALOGE("%s: Invalid state", __FUNCTION__);
+ return NO_ERROR;
+ };
+}
+
+static void toggleScreenUpdate(hwc_context_t* ctx, uint32_t on) {
+ ALOGD("%s: toggle update: %d", __FUNCTION__, on);
+ if (on == 0) {
+ ctx->mDrawLock.lock();
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isPause = true;
+ ctx->mOverlay->configBegin();
+ ctx->mOverlay->configDone();
+ ctx->mRotMgr->clear();
+ if(!Overlay::displayCommit(ctx->dpyAttr[0].fd)) {
+ ALOGE("%s: Display commit failed", __FUNCTION__);
+ }
+ ctx->mDrawLock.unlock();
+ } else {
+ ctx->mDrawLock.lock();
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isPause = false;
+ ctx->mDrawLock.unlock();
+ ctx->proc->invalidate(ctx->proc);
+ }
+}
+
+status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
+ Parcel* outParcel) {
+ status_t ret = NO_ERROR;
+
+ switch(command) {
+ case IQService::SECURING:
+ securing(mHwcContext, inParcel->readInt32());
+ break;
+ case IQService::UNSECURING:
+ unsecuring(mHwcContext, inParcel->readInt32());
+ break;
+ case IQService::SCREEN_REFRESH:
+ return screenRefresh(mHwcContext);
+ break;
+ case IQService::EXTERNAL_ORIENTATION:
+ setExtOrientation(mHwcContext, inParcel->readInt32());
+ break;
+ case IQService::BUFFER_MIRRORMODE:
+ setBufferMirrorMode(mHwcContext, inParcel->readInt32());
+ break;
+ case IQService::GET_DISPLAY_VISIBLE_REGION:
+ ret = getDisplayVisibleRegion(mHwcContext, inParcel->readInt32(),
+ outParcel);
+ break;
+ case IQService::CHECK_EXTERNAL_STATUS:
+ isExternalConnected(mHwcContext, outParcel);
+ break;
+ case IQService::GET_DISPLAY_ATTRIBUTES:
+ getDisplayAttributes(mHwcContext, inParcel, outParcel);
+ break;
+ case IQService::SET_HSIC_DATA:
+ setHSIC(inParcel);
+ break;
+ case IQService::SET_SECONDARY_DISPLAY_STATUS:
+ setSecondaryDisplayStatus(mHwcContext, inParcel);
+ break;
+ case IQService::SET_VIEW_FRAME:
+ setViewFrame(mHwcContext, inParcel);
+ break;
+ case IQService::DYNAMIC_DEBUG:
+ toggleDynamicDebug(mHwcContext, inParcel);
+ break;
+ case IQService::SET_IDLE_TIMEOUT:
+ setIdleTimeout(mHwcContext, inParcel);
+ break;
+ case IQService::SET_PARTIAL_UPDATE:
+ ret = setPartialUpdateState(mHwcContext, inParcel->readInt32());
+ break;
+ case IQService::CONFIGURE_DYN_REFRESH_RATE:
+ configureDynRefreshRate(mHwcContext, inParcel);
+ case IQService::QDCM_SVC_CMDS:
+ qdcmCmdsHandler(mHwcContext, inParcel, outParcel);
+ break;
+ case IQService::TOGGLE_SCREEN_UPDATE:
+ toggleScreenUpdate(mHwcContext, inParcel->readInt32());
+ break;
+ default:
+ ret = NO_ERROR;
+ }
+ return ret;
+}
+
+}
diff --git a/msm8909/libhwcomposer/hwc_qclient.h b/msm8909/libhwcomposer/hwc_qclient.h
new file mode 100644
index 0000000..d955377
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_qclient.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. 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 The Linux Foundation 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 CLIENTS; 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 ANDROID_QCLIENT_H
+#define ANDROID_QCLIENT_H
+
+#include <utils/Errors.h>
+#include <sys/types.h>
+#include <cutils/log.h>
+#include <binder/IServiceManager.h>
+#include <media/IMediaDeathNotifier.h>
+#include <IQClient.h>
+
+struct hwc_context_t;
+
+class Params;
+namespace qClient {
+// ----------------------------------------------------------------------------
+
+class QClient : public BnQClient {
+public:
+ QClient(hwc_context_t *ctx);
+ virtual ~QClient();
+ virtual android::status_t notifyCallback(uint32_t command,
+ const android::Parcel* inParcel,
+ android::Parcel* outParcel);
+
+private:
+ //Notifies of Media Player death
+ class MPDeathNotifier : public android::IMediaDeathNotifier {
+ public:
+ MPDeathNotifier(hwc_context_t* ctx) : mHwcContext(ctx){}
+ virtual void died();
+ hwc_context_t *mHwcContext;
+ };
+
+ hwc_context_t *mHwcContext;
+ const android::sp<android::IMediaDeathNotifier> mMPDeathNotifier;
+};
+}; // namespace qClient
+#endif // ANDROID_QCLIENT_H
diff --git a/msm8909/libhwcomposer/hwc_qdcm.cpp b/msm8909/libhwcomposer/hwc_qdcm.cpp
new file mode 100644
index 0000000..9821e4e
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_qdcm.cpp
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. 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 The Linux Foundation 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 <hwc_qdcm.h>
+#include <hwc_utils.h>
+#include <utils/String16.h>
+#include <mdp_version.h>
+#include "mode_manager.h"
+#include "libmm-disp-apis.h"
+#include "IQService.h"
+
+using namespace android;
+using namespace qService;
+using namespace qhwc;
+using namespace qmode;
+
+namespace qQdcm {
+//----------------------------------------------------------------------------
+void qdcmInitContext(hwc_context_t *ctx)
+{
+ loadQdcmLibrary(ctx);
+}
+
+void qdcmCloseContext(hwc_context_t *ctx)
+{
+ if (ctx->mQdcmInfo.mQdcmMode) {
+ unloadQdcmLibrary(ctx);
+ }
+}
+
+void qdcmApplyDefaultAfterBootAnimationDone(hwc_context_t *ctx)
+{
+ if (ctx->mQdcmInfo.mQdcmMode)
+ ctx->mQdcmInfo.mQdcmMode->applyDefaultMode(0);
+}
+
+static void qdcmSetActiveMode(hwc_context_t *ctx, const Parcel *in, Parcel *out)
+{
+ int ret = 0;
+
+ if (ctx->mQdcmInfo.mQdcmMode && in && out) {
+
+ struct SET_MODE_PROP_IN params =
+ { (disp_id_type)in->readInt32(), in->readInt32()};
+
+ ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_SET_ACTIVE_MODE,
+ (void *)¶ms, (void *)NULL);
+
+ out->writeInt32(ret); //return operation status via binder.
+ }
+}
+
+static void qdcmSetDefaultMode(hwc_context_t *ctx, const Parcel *in, Parcel *out)
+{
+ int ret = 0;
+
+ if (ctx->mQdcmInfo.mQdcmMode && in && out) {
+
+ struct SET_MODE_PROP_IN params =
+ { (disp_id_type)in->readInt32(), in->readInt32()};
+
+ ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_SET_DEFAULT_MODE,
+ (void *)¶ms, (void *)NULL);
+
+ out->writeInt32(ret); //return operation status via binder.
+ }
+}
+
+static void qdcmGetDefaultMode(hwc_context_t *ctx,
+ const Parcel *in, Parcel *out)
+{
+ int ret = 0;
+
+ if (ctx->mQdcmInfo.mQdcmMode && in && out) {
+
+ int params = in->readInt32();
+ int modeid = 0;
+
+ ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_GET_DEFAULT_MODE,
+ (const void *)¶ms, (void *)&modeid);
+
+ out->writeInt32(modeid);
+ out->writeInt32(ret); //return operation status via binder.
+ }
+}
+
+static void qdcmGetColorBalanceRange(hwc_context_t *ctx __unused,
+ const Parcel *in __unused, Parcel *out __unused)
+{
+}
+
+static void qdcmGetColorBalance(hwc_context_t *ctx,
+ const Parcel *in, Parcel *out)
+{
+ int ret = 0;
+
+ if (ctx->mQdcmInfo.mQdcmMode && in && out) {
+
+ int params = in->readInt32();
+ int warmness = 0;
+
+ ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_GET_CB,
+ (const void *)¶ms, (void *)&warmness);
+
+ out->writeInt32(warmness);
+ out->writeInt32(ret); //return operation status via binder.
+ }
+}
+
+static void qdcmSetColorBalance(hwc_context_t *ctx,
+ const Parcel *in, Parcel *out)
+{
+ int ret = 0;
+
+ if (ctx->mQdcmInfo.mQdcmMode && in && out) {
+
+ struct SET_CB_IN params =
+ { (disp_id_type)in->readInt32(), in->readInt32() };
+
+ ALOGD_IF(QDCM_DEBUG, "%s dispID = %d, warmness = %d\n",
+ __FUNCTION__, params.id, params.warmness);
+
+ ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_SET_CB,
+ (const void *)¶ms, NULL);
+
+ out->writeInt32(ret); //return operation status via binder.
+ }
+}
+
+static void qdcmSaveModeV2(hwc_context_t *ctx, const Parcel *in, Parcel *out)
+{
+ int ret = 0;
+
+ if (ctx->mQdcmInfo.mQdcmMode && in && out) {
+
+ struct SAVE_DISPLAY_MODE_V2_IN params =
+ { (disp_id_type)in->readInt32(),
+ in->readCString(),
+ (uint32_t)in->readInt32(),
+ in->readInt32()
+ };
+ int value = 0;
+
+ ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_SAVE_MODE_V2,
+ (const void *)¶ms, (void *)&value);
+
+ out->writeInt32(value);
+ out->writeInt32(ret); //return operation status via binder.
+ }
+}
+
+static void qdcmSetPaConfig(hwc_context_t *ctx, const Parcel *in, Parcel *out)
+{
+ int ret = 0;
+
+ if (ctx->mQdcmInfo.mQdcmMode && in && out) {
+
+ struct SET_PA_CONFIG_IN params;
+
+ params.id = (disp_id_type)in->readInt32();
+ params.pa.ops = in->readInt32();
+ params.pa.data.hue = in->readInt32();
+ params.pa.data.saturation = in->readInt32();
+ params.pa.data.value = in->readInt32();
+ params.pa.data.contrast = in->readInt32();
+ params.pa.data.sat_thresh = in->readInt32();
+
+ ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_SET_PA_CONFIG,
+ (const void *)¶ms, NULL);
+
+ out->writeInt32(ret); //return operation status via binder.
+ }
+}
+
+static void qdcmGetPaConfig(hwc_context_t *ctx, const Parcel *in, Parcel *out)
+{
+ int ret = 0;
+
+ if (ctx->mQdcmInfo.mQdcmMode && in && out) {
+
+ int params = in->readInt32();
+ struct disp_pa_config value;
+
+ ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_GET_PA_CONFIG,
+ (const void *)¶ms, (void *)&value);
+
+ out->writeInt32(value.ops);
+ out->writeInt32(value.data.hue);
+ out->writeInt32(value.data.saturation);
+ out->writeInt32(value.data.value);
+ out->writeInt32(value.data.contrast);
+ out->writeInt32(value.data.sat_thresh);
+
+ out->writeInt32(ret); //return operation status via binder.
+ }
+}
+
+static void qdcmGetPaRange(hwc_context_t *ctx, const Parcel *in, Parcel *out)
+{
+ int ret = 0;
+
+ if (ctx->mQdcmInfo.mQdcmMode && in && out) {
+
+ int params = in->readInt32();
+ struct disp_pa_range value;
+
+ ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_GET_PA_RANGE,
+ (const void *)¶ms, (void *)&value);
+
+ out->writeInt32(value.max.hue);
+ out->writeInt32(value.max.saturation);
+ out->writeInt32(value.max.value);
+ out->writeInt32(value.max.contrast);
+ out->writeInt32(value.max.sat_thresh);
+ out->writeInt32(value.min.hue);
+ out->writeInt32(value.min.saturation);
+ out->writeInt32(value.min.value);
+ out->writeInt32(value.min.contrast);
+ out->writeInt32(value.min.sat_thresh);
+
+ out->writeInt32(ret); //return operation status via binder.
+ }
+}
+
+void qdcmCmdsHandler(hwc_context_t *ctx, const Parcel *in, Parcel *out)
+{
+ int subcmd = in->readInt32();
+
+ ALOGD_IF(QDCM_DEBUG, "%s enter subcmd = %d\n", __FUNCTION__, subcmd);
+ switch (subcmd) {
+ case CMD_SET_ACTIVE_MODE:
+ qdcmSetActiveMode(ctx, in, out);
+ break;
+ case CMD_SET_DEFAULT_MODE:
+ qdcmSetDefaultMode(ctx, in, out);
+ break;
+ case CMD_GET_DEFAULT_MODE:
+ qdcmGetDefaultMode(ctx, in, out);
+ break;
+ case CMD_GET_CB_RANGE:
+ qdcmGetColorBalanceRange(ctx, in, out);
+ break;
+ case CMD_GET_CB:
+ qdcmGetColorBalance(ctx, in, out);
+ break;
+ case CMD_SET_CB:
+ qdcmSetColorBalance(ctx, in, out);
+ break;
+ case CMD_SAVE_MODE_V2:
+ qdcmSaveModeV2(ctx, in, out);
+ break;
+ case CMD_SET_PA_CONFIG:
+ qdcmSetPaConfig(ctx, in, out);
+ break;
+ case CMD_GET_PA_CONFIG:
+ qdcmGetPaConfig(ctx, in, out);
+ break;
+ case CMD_GET_PA_RANGE:
+ qdcmGetPaRange(ctx, in, out);
+ break;
+ }
+}
+
+
+} //namespace qQdcm
+
diff --git a/msm8909/libhwcomposer/hwc_qdcm.h b/msm8909/libhwcomposer/hwc_qdcm.h
new file mode 100644
index 0000000..6453159
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_qdcm.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. 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 The Linux Foundation 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 ANDROID_QDCM_H
+#define ANDROID_QDCM_H
+
+#include <utils/Errors.h>
+#include <sys/types.h>
+#include <cutils/log.h>
+#include <hwc_utils.h>
+#include <dlfcn.h>
+#include <binder/Parcel.h>
+#include <cutils/properties.h>
+
+#define QDCM_DEBUG 0
+
+namespace qmode {
+class ModeManager;
+}
+
+using namespace android;
+
+namespace qQdcm {
+// ----------------------------------------------------------------------------
+
+//function prototypes used for QDCM library and service
+static inline void loadQdcmLibrary(hwc_context_t *ctx)
+{
+ ctx->mQdcmInfo.mQdcmLib = dlopen("libmm-qdcm.so", RTLD_NOW);
+ qmode::ModeManager* (*factory)() = NULL;
+
+ if (ctx->mQdcmInfo.mQdcmLib)
+ *(void **)&factory = dlsym(ctx->mQdcmInfo.mQdcmLib, "getObject");
+
+ if (factory) {
+ ctx->mQdcmInfo.mQdcmMode = factory();
+ } else {
+ ctx->mQdcmInfo.mQdcmMode = NULL;
+ ALOGE("QDCM LIbrary load failing!");
+ }
+
+ ALOGD_IF(QDCM_DEBUG, "QDCM LIbrary loaded successfully!");
+}
+
+static inline void unloadQdcmLibrary(hwc_context_t *ctx)
+{
+ void (*destroy)(qmode::ModeManager*) = NULL;
+
+ if (ctx->mQdcmInfo.mQdcmLib) {
+ *(void **)&destroy = dlsym(ctx->mQdcmInfo.mQdcmLib, "deleteObject");
+
+ if (destroy) {
+ destroy(ctx->mQdcmInfo.mQdcmMode);
+ ctx->mQdcmInfo.mQdcmMode = NULL;
+ }
+
+ dlclose(ctx->mQdcmInfo.mQdcmLib);
+ ctx->mQdcmInfo.mQdcmLib = NULL;
+ }
+}
+
+void qdcmInitContext(hwc_context_t *);
+void qdcmCloseContext(hwc_context_t *);
+void qdcmApplyDefaultAfterBootAnimationDone(hwc_context_t *);
+void qdcmCmdsHandler(hwc_context_t*, const Parcel*, Parcel*);
+
+}; // namespace qQdcm
+#endif // ANDROID_QDCM_H
diff --git a/msm8909/libhwcomposer/hwc_qdcm_legacy.cpp b/msm8909/libhwcomposer/hwc_qdcm_legacy.cpp
new file mode 100644
index 0000000..9c2c7b0
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_qdcm_legacy.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. 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 The Linux Foundation 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 <hwc_qdcm.h>
+#include <hwc_utils.h>
+#include <IQService.h>
+#include <mdp_version.h>
+#include <dlfcn.h>
+
+using namespace android;
+using namespace qService;
+using namespace qhwc;
+
+namespace qQdcm {
+//----------------------------------------------------------------------------
+void qdcmInitContext(hwc_context_t *ctx)
+{
+}
+
+void qdcmCloseContext(hwc_context_t *ctx)
+{
+}
+
+void qdcmApplyDefaultAfterBootAnimationDone(hwc_context_t *ctx)
+{
+ int ret = 0;
+ int (*applyMode)(int) = NULL;
+ void *modeHandle = NULL;
+
+ modeHandle = dlopen("libmm-qdcm.so", RTLD_NOW);
+ if (modeHandle) {
+ *(void **)&applyMode = dlsym(modeHandle, "applyDefaults");
+ if (applyMode) {
+ ret = applyMode(HWC_DISPLAY_PRIMARY);
+ if (ret)
+ ALOGE("%s: Not able to apply default mode", __FUNCTION__);
+ } else {
+ ALOGE("%s: No symbol applyDefaults found", __FUNCTION__);
+ }
+ dlclose(modeHandle);
+ } else {
+ ALOGE("%s: Not able to load libmm-qdcm.so", __FUNCTION__);
+ }
+}
+
+//do nothing in case qdcm legacy implementation.
+void qdcmCmdsHandler(hwc_context_t *ctx, const Parcel *in, Parcel *out)
+{
+}
+
+
+} //namespace qQdcm
+
diff --git a/msm8909/libhwcomposer/hwc_uevents.cpp b/msm8909/libhwcomposer/hwc_uevents.cpp
new file mode 100644
index 0000000..d1c68a5
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_uevents.cpp
@@ -0,0 +1,243 @@
+
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-14, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are
+ * retained for attribution purposes only.
+
+ * 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 UEVENT_DEBUG 0
+#include <hardware_legacy/uevent.h>
+#include <utils/Log.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
+#include <string.h>
+#include <stdlib.h>
+#include "hwc_utils.h"
+#include "hwc_fbupdate.h"
+#include "hwc_mdpcomp.h"
+#include "hwc_copybit.h"
+#include "comptype.h"
+#include "hdmi.h"
+#include "hwc_virtual.h"
+#include "mdp_version.h"
+using namespace overlay;
+namespace qhwc {
+#define HWC_UEVENT_SWITCH_STR "change@/devices/virtual/switch/"
+#define HWC_UEVENT_THREAD_NAME "hwcUeventThread"
+
+/* Parse uevent data for devices which we are interested */
+static int getConnectedDisplay(hwc_context_t* ctx, const char* strUdata)
+{
+ int ret = -1;
+ // Switch node for HDMI as PRIMARY/EXTERNAL
+ if(strcasestr("change@/devices/virtual/switch/hdmi", strUdata)) {
+ if (ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) {
+ ret = HWC_DISPLAY_PRIMARY;
+ } else {
+ ret = HWC_DISPLAY_EXTERNAL;
+ }
+ }
+ return ret;
+}
+
+static bool getPanelResetStatus(hwc_context_t* ctx, const char* strUdata, int len)
+{
+ const char* iter_str = strUdata;
+ if (strcasestr("change@/devices/virtual/graphics/fb0", strUdata)) {
+ while(((iter_str - strUdata) <= len) && (*iter_str)) {
+ char* pstr = strstr(iter_str, "PANEL_ALIVE=0");
+ if (pstr != NULL) {
+ ALOGI("%s: got change event in fb0 with PANEL_ALIVE=0",
+ __FUNCTION__);
+ ctx->mPanelResetStatus = true;
+ return true;
+ }
+ iter_str += strlen(iter_str)+1;
+ }
+ }
+ return false;
+}
+
+/* Parse uevent data for action requested for the display */
+static int getConnectedState(const char* strUdata, int len)
+{
+ const char* iter_str = strUdata;
+ while(((iter_str - strUdata) <= len) && (*iter_str)) {
+ char* pstr = strstr(iter_str, "SWITCH_STATE=");
+ if (pstr != NULL) {
+ return (atoi(pstr + strlen("SWITCH_STATE=")));
+ }
+ iter_str += strlen(iter_str)+1;
+ }
+ return -1;
+}
+
+static void handle_uevent(hwc_context_t* ctx, const char* udata, int len)
+{
+ bool bpanelReset = getPanelResetStatus(ctx, udata, len);
+ if (bpanelReset) {
+ ctx->proc->invalidate(ctx->proc);
+ return;
+ }
+
+ int dpy = getConnectedDisplay(ctx, udata);
+ if(dpy < 0) {
+ ALOGD_IF(UEVENT_DEBUG, "%s: Not disp Event ", __FUNCTION__);
+ return;
+ }
+
+ int switch_state = getConnectedState(udata, len);
+
+ ALOGE_IF(UEVENT_DEBUG,"%s: uevent received: %s switch state: %d",
+ __FUNCTION__,udata, switch_state);
+
+ switch(switch_state) {
+ case EXTERNAL_OFFLINE:
+ {
+ /* Display not connected */
+ if(!ctx->dpyAttr[dpy].connected){
+ ALOGE_IF(UEVENT_DEBUG,"%s: Ignoring EXTERNAL_OFFLINE event"
+ "for display: %d", __FUNCTION__, dpy);
+ break;
+ }
+
+ ctx->mDrawLock.lock();
+ handle_offline(ctx, dpy);
+ ctx->mDrawLock.unlock();
+
+ /* We need to send hotplug to SF only when we are disconnecting
+ * HDMI as an external display. */
+ if(dpy == HWC_DISPLAY_EXTERNAL) {
+ ALOGE_IF(UEVENT_DEBUG,"%s:Sending EXTERNAL OFFLINE hotplug"
+ "event", __FUNCTION__);
+ ctx->proc->hotplug(ctx->proc, dpy, EXTERNAL_OFFLINE);
+ }
+ break;
+ }
+ case EXTERNAL_ONLINE:
+ {
+ /* Display already connected */
+ if(ctx->dpyAttr[dpy].connected) {
+ ALOGE_IF(UEVENT_DEBUG,"%s: Ignoring EXTERNAL_ONLINE event"
+ "for display: %d", __FUNCTION__, dpy);
+ break;
+ }
+
+ if (ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) {
+ ctx->mDrawLock.lock();
+ handle_online(ctx, dpy);
+ ctx->mDrawLock.unlock();
+
+ ctx->proc->invalidate(ctx->proc);
+ break;
+ } else {
+ ctx->mDrawLock.lock();
+ //Force composition to give up resources like pipes and
+ //close fb. For example if assertive display is going on,
+ //fb2 could be open, thus connecting Layer Mixer#0 to
+ //WriteBack module. If HDMI attempts to open fb1, the driver
+ //will try to attach Layer Mixer#0 to HDMI INT, which will
+ //fail, since Layer Mixer#0 is still connected to WriteBack.
+ //This block will force composition to close fb2 in above
+ //example.
+ ctx->dpyAttr[dpy].isConfiguring = true;
+ ctx->mDrawLock.unlock();
+
+ ctx->proc->invalidate(ctx->proc);
+ }
+ //2 cycles for slower content
+ usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+ * 2 / 1000);
+
+ if(isVDConnected(ctx)) {
+ // Do not initiate WFD teardown if WFD architecture is based
+ // on VDS mechanism.
+ // WFD Stack listens to HDMI intent and initiates virtual
+ // display teardown.
+ // ToDo: Currently non-WFD Virtual display clients do not
+ // involve HWC. If there is a change, we need to come up
+ // with mechanism of how to address non-WFD Virtual display
+ // clients + HDMI
+ ctx->mWfdSyncLock.lock();
+ ALOGD_IF(HWC_WFDDISPSYNC_LOG,
+ "%s: Waiting for wfd-teardown to be signalled",
+ __FUNCTION__);
+ ctx->mWfdSyncLock.wait();
+ ALOGD_IF(HWC_WFDDISPSYNC_LOG,
+ "%s: Teardown signalled. Completed waiting in"
+ "uevent thread", __FUNCTION__);
+ ctx->mWfdSyncLock.unlock();
+ }
+ ctx->mHDMIDisplay->configure();
+ ctx->mHDMIDisplay->activateDisplay();
+
+ ctx->mDrawLock.lock();
+ updateDisplayInfo(ctx, dpy);
+ initCompositionResources(ctx, dpy);
+ ctx->dpyAttr[dpy].isPause = false;
+ ctx->dpyAttr[dpy].connected = true;
+ ctx->dpyAttr[dpy].isConfiguring = true;
+ ctx->mDrawLock.unlock();
+
+ /* External display is HDMI */
+ ALOGE_IF(UEVENT_DEBUG, "%s: Sending EXTERNAL ONLINE"
+ "hotplug event", __FUNCTION__);
+ ctx->proc->hotplug(ctx->proc, dpy, EXTERNAL_ONLINE);
+ break;
+ }
+ default:
+ {
+ ALOGE("%s: Invalid state to swtich:%d", __FUNCTION__, switch_state);
+ break;
+ }
+ }
+}
+
+static void *uevent_loop(void *param)
+{
+ int len = 0;
+ static char udata[PAGE_SIZE];
+ hwc_context_t * ctx = reinterpret_cast<hwc_context_t *>(param);
+ char thread_name[64] = HWC_UEVENT_THREAD_NAME;
+ prctl(PR_SET_NAME, (unsigned long) &thread_name, 0, 0, 0);
+ setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
+ if(!uevent_init()) {
+ ALOGE("%s: failed to init uevent ",__FUNCTION__);
+ return NULL;
+ }
+
+ while(1) {
+ len = uevent_next_event(udata, (int)sizeof(udata) - 2);
+ handle_uevent(ctx, udata, len);
+ }
+
+ return NULL;
+}
+
+void init_uevent_thread(hwc_context_t* ctx)
+{
+ pthread_t uevent_thread;
+ int ret;
+
+ ALOGI("Initializing UEVENT Thread");
+ ret = pthread_create(&uevent_thread, NULL, uevent_loop, (void*) ctx);
+ if (ret) {
+ ALOGE("%s: failed to create %s: %s", __FUNCTION__,
+ HWC_UEVENT_THREAD_NAME, strerror(ret));
+ }
+}
+
+}; //namespace
diff --git a/msm8909/libhwcomposer/hwc_utils.cpp b/msm8909/libhwcomposer/hwc_utils.cpp
new file mode 100644
index 0000000..9222977
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_utils.cpp
@@ -0,0 +1,2902 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2014, The Linux Foundation All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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 ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
+#define HWC_UTILS_DEBUG 0
+#include <math.h>
+#include <sys/ioctl.h>
+#include <linux/fb.h>
+#include <binder/IServiceManager.h>
+#include <EGL/egl.h>
+#include <cutils/properties.h>
+#include <utils/Trace.h>
+#include <gralloc_priv.h>
+#include <overlay.h>
+#include <overlayRotator.h>
+#include <overlayWriteback.h>
+#include "hwc_utils.h"
+#include "hwc_mdpcomp.h"
+#include "hwc_fbupdate.h"
+#include "hwc_ad.h"
+#include "mdp_version.h"
+#include "hwc_copybit.h"
+#include "hwc_dump_layers.h"
+#include "hdmi.h"
+#include "hwc_qclient.h"
+#include "QService.h"
+#include "comptype.h"
+#include "hwc_virtual.h"
+#include "qd_utils.h"
+#include "hwc_qdcm.h"
+#include <sys/sysinfo.h>
+#include <dlfcn.h>
+
+using namespace qClient;
+using namespace qService;
+using namespace android;
+using namespace overlay;
+using namespace overlay::utils;
+using namespace qQdcm;
+namespace ovutils = overlay::utils;
+
+#ifdef QTI_BSP
+
+#define EGL_GPU_HINT_1 0x32D0
+#define EGL_GPU_HINT_2 0x32D1
+
+#define EGL_GPU_LEVEL_0 0x0
+#define EGL_GPU_LEVEL_1 0x1
+#define EGL_GPU_LEVEL_2 0x2
+#define EGL_GPU_LEVEL_3 0x3
+#define EGL_GPU_LEVEL_4 0x4
+#define EGL_GPU_LEVEL_5 0x5
+
+#endif
+
+#define PROP_DEFAULT_APPBUFFER "hw.sf.app_buff_count"
+#define MAX_RAM_SIZE 512*1024*1024
+#define qHD_WIDTH 540
+
+
+namespace qhwc {
+
+// Std refresh rates for digital videos- 24p, 30p, 48p and 60p
+uint32_t stdRefreshRates[] = { 30, 24, 48, 60 };
+
+static uint32_t getFBformat(fb_var_screeninfo vinfo) {
+ uint32_t fbformat = HAL_PIXEL_FORMAT_RGBA_8888;
+
+#ifdef GET_FRAMEBUFFER_FORMAT_FROM_HWC
+ // Here, we are adding the formats that are supported by both GPU and MDP.
+ // The formats that fall in this category are RGBA_8888, RGB_565, RGB_888
+ switch(vinfo.bits_per_pixel) {
+ case 16:
+ fbformat = HAL_PIXEL_FORMAT_RGB_565;
+ break;
+ case 24:
+ if ((vinfo.transp.offset == 0) && (vinfo.transp.length == 0))
+ fbformat = HAL_PIXEL_FORMAT_RGB_888;
+ break;
+ case 32:
+ if ((vinfo.red.offset == 0) && (vinfo.green.offset == 8) &&
+ (vinfo.blue.offset == 16) && (vinfo.transp.offset == 24))
+ fbformat = HAL_PIXEL_FORMAT_RGBA_8888;
+ break;
+ default:
+ fbformat = HAL_PIXEL_FORMAT_RGBA_8888;
+ }
+#endif
+ return fbformat;
+}
+
+bool isValidResolution(hwc_context_t *ctx, uint32_t xres, uint32_t yres)
+{
+ return !((xres > qdutils::MDPVersion::getInstance().getMaxMixerWidth() &&
+ !isDisplaySplit(ctx, HWC_DISPLAY_PRIMARY)) ||
+ (xres < MIN_DISPLAY_XRES || yres < MIN_DISPLAY_YRES));
+}
+
+void changeResolution(hwc_context_t *ctx, int xres_orig, int yres_orig,
+ int width, int height) {
+ //Store original display resolution.
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres_new = xres_orig;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres_new = yres_orig;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].customFBSize = false;
+ char property[PROPERTY_VALUE_MAX] = {'\0'};
+ char *yptr = NULL;
+ if (property_get("debug.hwc.fbsize", property, NULL) > 0) {
+ yptr = strcasestr(property,"x");
+ if(yptr) {
+ int xres_new = atoi(property);
+ int yres_new = atoi(yptr + 1);
+ if (isValidResolution(ctx,xres_new,yres_new) &&
+ xres_new != xres_orig && yres_new != yres_orig) {
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres_new = xres_new;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres_new = yres_new;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].customFBSize = true;
+
+ //Caluculate DPI according to changed resolution.
+ float xdpi = ((float)xres_new * 25.4f) / (float)width;
+ float ydpi = ((float)yres_new * 25.4f) / (float)height;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xdpi = xdpi;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].ydpi = ydpi;
+ }
+ }
+ }
+}
+
+// Initialize hdmi display attributes based on
+// hdmi display class state
+void updateDisplayInfo(hwc_context_t* ctx, int dpy) {
+ struct fb_var_screeninfo info;
+
+ if (ioctl(ctx->mHDMIDisplay->getFd(), FBIOGET_VSCREENINFO, &info) == -1) {
+ ALOGE("%s:Error in ioctl FBIOGET_VSCREENINFO: %s",
+ __FUNCTION__, strerror(errno));
+ }
+
+ ctx->dpyAttr[dpy].fbformat = getFBformat(info);
+ ctx->dpyAttr[dpy].fd = ctx->mHDMIDisplay->getFd();
+ ctx->dpyAttr[dpy].xres = ctx->mHDMIDisplay->getWidth();
+ ctx->dpyAttr[dpy].yres = ctx->mHDMIDisplay->getHeight();
+ ctx->dpyAttr[dpy].mMDPScalingMode = ctx->mHDMIDisplay->getMDPScalingMode();
+ ctx->dpyAttr[dpy].vsync_period = ctx->mHDMIDisplay->getVsyncPeriod();
+ ctx->mViewFrame[dpy].left = 0;
+ ctx->mViewFrame[dpy].top = 0;
+ ctx->mViewFrame[dpy].right = ctx->dpyAttr[dpy].xres;
+ ctx->mViewFrame[dpy].bottom = ctx->dpyAttr[dpy].yres;
+}
+
+// Reset hdmi display attributes and list stats structures
+void resetDisplayInfo(hwc_context_t* ctx, int dpy) {
+ memset(&(ctx->dpyAttr[dpy]), 0, sizeof(ctx->dpyAttr[dpy]));
+ memset(&(ctx->listStats[dpy]), 0, sizeof(ctx->listStats[dpy]));
+ // We reset the fd to -1 here but External display class is responsible
+ // for it when the display is disconnected. This is handled as part of
+ // EXTERNAL_OFFLINE event.
+ ctx->dpyAttr[dpy].fd = -1;
+}
+
+// Initialize composition resources
+void initCompositionResources(hwc_context_t* ctx, int dpy) {
+ ctx->mFBUpdate[dpy] = IFBUpdate::getObject(ctx, dpy);
+ ctx->mMDPComp[dpy] = MDPComp::getObject(ctx, dpy);
+}
+
+void destroyCompositionResources(hwc_context_t* ctx, int dpy) {
+ if(ctx->mFBUpdate[dpy]) {
+ delete ctx->mFBUpdate[dpy];
+ ctx->mFBUpdate[dpy] = NULL;
+ }
+ if(ctx->mMDPComp[dpy]) {
+ delete ctx->mMDPComp[dpy];
+ ctx->mMDPComp[dpy] = NULL;
+ }
+}
+
+static int openFramebufferDevice(hwc_context_t *ctx)
+{
+ struct fb_fix_screeninfo finfo;
+ struct fb_var_screeninfo info;
+
+ int fb_fd = openFb(HWC_DISPLAY_PRIMARY);
+ if(fb_fd < 0) {
+ ALOGE("%s: Error Opening FB : %s", __FUNCTION__, strerror(errno));
+ return -errno;
+ }
+
+ if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &info) == -1) {
+ ALOGE("%s:Error in ioctl FBIOGET_VSCREENINFO: %s", __FUNCTION__,
+ strerror(errno));
+ close(fb_fd);
+ return -errno;
+ }
+
+ if (int(info.width) <= 0 || int(info.height) <= 0) {
+ // the driver doesn't return that information
+ // default to 160 dpi
+ info.width = (int)(((float)info.xres * 25.4f)/160.0f + 0.5f);
+ info.height = (int)(((float)info.yres * 25.4f)/160.0f + 0.5f);
+ }
+
+ float xdpi = ((float)info.xres * 25.4f) / (float)info.width;
+ float ydpi = ((float)info.yres * 25.4f) / (float)info.height;
+
+#ifdef MSMFB_METADATA_GET
+ struct msmfb_metadata metadata;
+ memset(&metadata, 0 , sizeof(metadata));
+ metadata.op = metadata_op_frame_rate;
+
+ if (ioctl(fb_fd, MSMFB_METADATA_GET, &metadata) == -1) {
+ ALOGE("%s:Error retrieving panel frame rate: %s", __FUNCTION__,
+ strerror(errno));
+ close(fb_fd);
+ return -errno;
+ }
+
+ float fps = (float)metadata.data.panel_frame_rate;
+#else
+ //XXX: Remove reserved field usage on all baselines
+ //The reserved[3] field is used to store FPS by the driver.
+ float fps = info.reserved[3] & 0xFF;
+#endif
+
+ if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo) == -1) {
+ ALOGE("%s:Error in ioctl FBIOGET_FSCREENINFO: %s", __FUNCTION__,
+ strerror(errno));
+ close(fb_fd);
+ return -errno;
+ }
+
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd = fb_fd;
+ //xres, yres may not be 32 aligned
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].stride = finfo.line_length /(info.xres/8);
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres = info.xres;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres = info.yres;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xdpi = xdpi;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].ydpi = ydpi;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].refreshRate = (uint32_t)fps;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].dynRefreshRate = (uint32_t)fps;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period =
+ (uint32_t)(1000000000l / fps);
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fbformat = getFBformat(info);
+
+ //To change resolution of primary display
+ changeResolution(ctx, info.xres, info.yres, info.width, info.height);
+
+ //Unblank primary on first boot
+ if(ioctl(fb_fd, FBIOBLANK,FB_BLANK_UNBLANK) < 0) {
+ ALOGE("%s: Failed to unblank display", __FUNCTION__);
+ return -errno;
+ }
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isActive = true;
+
+ return 0;
+}
+
+static void changeDefaultAppBufferCount() {
+ struct sysinfo info;
+ unsigned long int ramSize = 0;
+ if (!sysinfo(&info)) {
+ ramSize = info.totalram ;
+ }
+ int fb_fd = -1;
+ struct fb_var_screeninfo sInfo ={0};
+ fb_fd = open("/dev/graphics/fb0", O_RDONLY);
+ if (fb_fd >=0) {
+ ioctl(fb_fd, FBIOGET_VSCREENINFO, &sInfo);
+ close(fb_fd);
+ }
+ if ((ramSize && ramSize < MAX_RAM_SIZE) &&
+ (sInfo.xres && sInfo.xres <= qHD_WIDTH )) {
+ property_set(PROP_DEFAULT_APPBUFFER, "3");
+ }
+}
+
+void initContext(hwc_context_t *ctx)
+{
+ overlay::Overlay::initOverlay();
+ ctx->mHDMIDisplay = new HDMIDisplay();
+ uint32_t priW = 0, priH = 0;
+ // 1. HDMI as Primary
+ // -If HDMI cable is connected, read display configs from edid data
+ // -If HDMI cable is not connected then use default data in vscreeninfo
+ // 2. HDMI as External
+ // -Initialize HDMI class for use with external display
+ // -Use vscreeninfo to populate display configs
+ if(ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) {
+ int connected = ctx->mHDMIDisplay->getConnectedState();
+ if(connected == 1) {
+ ctx->mHDMIDisplay->configure();
+ updateDisplayInfo(ctx, HWC_DISPLAY_PRIMARY);
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = true;
+ } else {
+ openFramebufferDevice(ctx);
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = false;
+ }
+ } else {
+ openFramebufferDevice(ctx);
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = true;
+ // Send the primary resolution to the hdmi display class
+ // to be used for MDP scaling functionality
+ priW = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
+ priH = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
+ ctx->mHDMIDisplay->setPrimaryAttributes(priW, priH);
+ }
+
+ char value[PROPERTY_VALUE_MAX];
+ ctx->mMDP.version = qdutils::MDPVersion::getInstance().getMDPVersion();
+ ctx->mMDP.hasOverlay = qdutils::MDPVersion::getInstance().hasOverlay();
+ ctx->mMDP.panel = qdutils::MDPVersion::getInstance().getPanelType();
+ ctx->mOverlay = overlay::Overlay::getInstance();
+ ctx->mRotMgr = RotMgr::getInstance();
+
+ //default_app_buffer for ferrum
+ if (ctx->mMDP.version == qdutils::MDP_V3_0_5) {
+ changeDefaultAppBufferCount();
+ }
+ // Initialize composition objects for the primary display
+ initCompositionResources(ctx, HWC_DISPLAY_PRIMARY);
+
+ // Check if the target supports copybit compostion (dyn/mdp) to
+ // decide if we need to open the copybit module.
+ int compositionType =
+ qdutils::QCCompositionType::getInstance().getCompositionType();
+
+ // Only MDP copybit is used
+ if ((compositionType & (qdutils::COMPOSITION_TYPE_DYN |
+ qdutils::COMPOSITION_TYPE_MDP)) &&
+ ((qdutils::MDPVersion::getInstance().getMDPVersion() ==
+ qdutils::MDP_V3_0_4) ||
+ (qdutils::MDPVersion::getInstance().getMDPVersion() ==
+ qdutils::MDP_V3_0_5))) {
+ ctx->mCopyBit[HWC_DISPLAY_PRIMARY] = new CopyBit(ctx,
+ HWC_DISPLAY_PRIMARY);
+ }
+
+ ctx->mHWCVirtual = new HWCVirtualVDS();
+ ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive = false;
+ ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected = false;
+ ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = false;
+ ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected = false;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].mMDPScalingMode= false;
+ ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].mMDPScalingMode = false;
+ ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].mMDPScalingMode = false;
+
+ //Initialize the primary display viewFrame info
+ ctx->mViewFrame[HWC_DISPLAY_PRIMARY].left = 0;
+ ctx->mViewFrame[HWC_DISPLAY_PRIMARY].top = 0;
+ ctx->mViewFrame[HWC_DISPLAY_PRIMARY].right =
+ (int)ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
+ ctx->mViewFrame[HWC_DISPLAY_PRIMARY].bottom =
+ (int)ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
+
+ for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
+ ctx->mHwcDebug[i] = new HwcDebug(i);
+ ctx->mLayerRotMap[i] = new LayerRotMap();
+ ctx->mAnimationState[i] = ANIMATION_STOPPED;
+ ctx->dpyAttr[i].mActionSafePresent = false;
+ ctx->dpyAttr[i].mAsWidthRatio = 0;
+ ctx->dpyAttr[i].mAsHeightRatio = 0;
+ }
+
+ for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
+ ctx->mPrevHwLayerCount[i] = 0;
+ }
+
+ MDPComp::init(ctx);
+ ctx->mAD = new AssertiveDisplay(ctx);
+
+ ctx->vstate.enable = false;
+ ctx->vstate.fakevsync = false;
+ ctx->mExtOrientation = 0;
+ ctx->numActiveDisplays = 1;
+
+ //Right now hwc starts the service but anybody could do it, or it could be
+ //independent process as well.
+ QService::init();
+ sp<IQClient> client = new QClient(ctx);
+ android::sp<qService::IQService> qservice_sp = interface_cast<IQService>(
+ defaultServiceManager()->getService(
+ String16("display.qservice")));
+ if (qservice_sp.get()) {
+ qservice_sp->connect(client);
+ } else {
+ ALOGE("%s: Failed to acquire service pointer", __FUNCTION__);
+ return ;
+ }
+
+ // Initialize device orientation to its default orientation
+ ctx->deviceOrientation = 0;
+ ctx->mBufferMirrorMode = false;
+
+ property_get("sys.hwc.windowbox_aspect_ratio_tolerance", value, "0");
+ ctx->mAspectRatioToleranceLevel = (((float)atoi(value)) / 100.0f);
+
+ ctx->enableABC = false;
+ property_get("debug.sf.hwc.canUseABC", value, "0");
+ ctx->enableABC = atoi(value) ? true : false;
+
+ // Initializing boot anim completed check to false
+ ctx->mBootAnimCompleted = false;
+
+ // Initialize gpu perfomance hint related parameters
+#ifdef QTI_BSP
+ ctx->mEglLib = NULL;
+ ctx->mpfn_eglGpuPerfHintQCOM = NULL;
+ ctx->mpfn_eglGetCurrentDisplay = NULL;
+ ctx->mpfn_eglGetCurrentContext = NULL;
+ ctx->mGPUHintInfo.mGpuPerfModeEnable = false;
+ ctx->mGPUHintInfo.mEGLDisplay = NULL;
+ ctx->mGPUHintInfo.mEGLContext = NULL;
+ ctx->mGPUHintInfo.mCompositionState = COMPOSITION_STATE_MDP;
+ ctx->mGPUHintInfo.mCurrGPUPerfMode = EGL_GPU_LEVEL_0;
+ if(property_get("sys.hwc.gpu_perf_mode", value, "0") > 0) {
+ int val = atoi(value);
+ if(val > 0 && loadEglLib(ctx)) {
+ ctx->mGPUHintInfo.mGpuPerfModeEnable = true;
+ }
+ }
+#endif
+ // Read the system property to determine if windowboxing feature is enabled.
+ ctx->mWindowboxFeature = false;
+ if(property_get("sys.hwc.windowbox_feature", value, "false")
+ && !strcmp(value, "true")) {
+ ctx->mWindowboxFeature = true;
+ }
+
+ ctx->mUseMetaDataRefreshRate = true;
+ if(property_get("persist.metadata_dynfps.disable", value, "false")
+ && !strcmp(value, "true")) {
+ ctx->mUseMetaDataRefreshRate = false;
+ }
+
+ memset(&(ctx->mPtorInfo), 0, sizeof(ctx->mPtorInfo));
+
+ //init qdcm service related context.
+ qdcmInitContext(ctx);
+
+ ALOGI("Initializing Qualcomm Hardware Composer");
+ ALOGI("MDP version: %d", ctx->mMDP.version);
+}
+
+void closeContext(hwc_context_t *ctx)
+{
+ //close qdcm service related context.
+ qdcmCloseContext(ctx);
+
+ if(ctx->mOverlay) {
+ delete ctx->mOverlay;
+ ctx->mOverlay = NULL;
+ }
+
+ if(ctx->mRotMgr) {
+ delete ctx->mRotMgr;
+ ctx->mRotMgr = NULL;
+ }
+
+ for(int i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
+ if(ctx->mCopyBit[i]) {
+ delete ctx->mCopyBit[i];
+ ctx->mCopyBit[i] = NULL;
+ }
+ }
+
+ if(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd) {
+ close(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd);
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd = -1;
+ }
+
+ if(ctx->mHDMIDisplay) {
+ delete ctx->mHDMIDisplay;
+ ctx->mHDMIDisplay = NULL;
+ }
+
+ for(int i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
+ destroyCompositionResources(ctx, i);
+
+ if(ctx->mHwcDebug[i]) {
+ delete ctx->mHwcDebug[i];
+ ctx->mHwcDebug[i] = NULL;
+ }
+ if(ctx->mLayerRotMap[i]) {
+ delete ctx->mLayerRotMap[i];
+ ctx->mLayerRotMap[i] = NULL;
+ }
+ }
+ if(ctx->mHWCVirtual) {
+ delete ctx->mHWCVirtual;
+ ctx->mHWCVirtual = NULL;
+ }
+ if(ctx->mAD) {
+ delete ctx->mAD;
+ ctx->mAD = NULL;
+ }
+
+#ifdef QTI_BSP
+ ctx->mpfn_eglGpuPerfHintQCOM = NULL;
+ ctx->mpfn_eglGetCurrentDisplay = NULL;
+ ctx->mpfn_eglGetCurrentContext = NULL;
+ if(ctx->mEglLib) {
+ dlclose(ctx->mEglLib);
+ ctx->mEglLib = NULL;
+ }
+#endif
+}
+
+uint32_t getRefreshRate(hwc_context_t* ctx, uint32_t requestedRefreshRate) {
+
+ qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance();
+ int dpy = HWC_DISPLAY_PRIMARY;
+ uint32_t defaultRefreshRate = ctx->dpyAttr[dpy].refreshRate;
+ uint32_t rate = defaultRefreshRate;
+
+ if(!requestedRefreshRate)
+ return defaultRefreshRate;
+
+ uint32_t maxNumIterations =
+ (uint32_t)ceil(
+ (float)mdpHw.getMaxFpsSupported()/
+ (float)requestedRefreshRate);
+
+ for(uint32_t i = 1; i <= maxNumIterations; i++) {
+ rate = i * roundOff(requestedRefreshRate);
+ if(rate < mdpHw.getMinFpsSupported()) {
+ continue;
+ } else if((rate >= mdpHw.getMinFpsSupported() &&
+ rate <= mdpHw.getMaxFpsSupported())) {
+ break;
+ } else {
+ rate = defaultRefreshRate;
+ break;
+ }
+ }
+ return rate;
+}
+
+//Helper to roundoff the refreshrates to the std refresh-rates
+uint32_t roundOff(uint32_t refreshRate) {
+ int count = (int) (sizeof(stdRefreshRates)/sizeof(stdRefreshRates[0]));
+ uint32_t rate = refreshRate;
+ for(int i=0; i< count; i++) {
+ if(abs(stdRefreshRates[i] - refreshRate) < 2) {
+ // Most likely used for video, the fps can fluctuate
+ // Ex: b/w 29 and 30 for 30 fps clip
+ rate = stdRefreshRates[i];
+ break;
+ }
+ }
+ return rate;
+}
+
+//Helper func to set the dyn fps
+void setRefreshRate(hwc_context_t* ctx, int dpy, uint32_t refreshRate) {
+ //Update only if different
+ if(!ctx || refreshRate == ctx->dpyAttr[dpy].dynRefreshRate)
+ return;
+ const int fbNum = Overlay::getFbForDpy(dpy);
+ char sysfsPath[qdutils::MAX_SYSFS_FILE_PATH];
+ snprintf (sysfsPath, sizeof(sysfsPath),
+ "/sys/class/graphics/fb%d/dynamic_fps", fbNum);
+
+ int fd = open(sysfsPath, O_WRONLY);
+ if(fd >= 0) {
+ char str[64];
+ snprintf(str, sizeof(str), "%d", refreshRate);
+ ssize_t ret = write(fd, str, strlen(str));
+ if(ret < 0) {
+ ALOGE("%s: Failed to write %d with error %s",
+ __FUNCTION__, refreshRate, strerror(errno));
+ } else {
+ ctx->dpyAttr[dpy].dynRefreshRate = refreshRate;
+ ALOGD_IF(HWC_UTILS_DEBUG, "%s: Wrote %d to dynamic_fps",
+ __FUNCTION__, refreshRate);
+ }
+ close(fd);
+ } else {
+ ALOGE("%s: Failed to open %s with error %s", __FUNCTION__, sysfsPath,
+ strerror(errno));
+ }
+}
+
+void dumpsys_log(android::String8& buf, const char* fmt, ...)
+{
+ va_list varargs;
+ va_start(varargs, fmt);
+ buf.appendFormatV(fmt, varargs);
+ va_end(varargs);
+}
+
+int getExtOrientation(hwc_context_t* ctx) {
+ int extOrient = ctx->mExtOrientation;
+ if(ctx->mBufferMirrorMode)
+ extOrient = getMirrorModeOrientation(ctx);
+ return extOrient;
+}
+
+/* Calculates the destination position based on the action safe rectangle */
+void getActionSafePosition(hwc_context_t *ctx, int dpy, hwc_rect_t& rect) {
+ // Position
+ int x = rect.left, y = rect.top;
+ int w = rect.right - rect.left;
+ int h = rect.bottom - rect.top;
+
+ if(!ctx->dpyAttr[dpy].mActionSafePresent)
+ return;
+ // Read action safe properties
+ int asWidthRatio = ctx->dpyAttr[dpy].mAsWidthRatio;
+ int asHeightRatio = ctx->dpyAttr[dpy].mAsHeightRatio;
+
+ float wRatio = 1.0;
+ float hRatio = 1.0;
+ float xRatio = 1.0;
+ float yRatio = 1.0;
+
+ uint32_t fbWidth = ctx->dpyAttr[dpy].xres;
+ uint32_t fbHeight = ctx->dpyAttr[dpy].yres;
+ if(ctx->dpyAttr[dpy].mMDPScalingMode) {
+ // if MDP scaling mode is enabled for external, need to query
+ // the actual width and height, as that is the physical w & h
+ ctx->mHDMIDisplay->getAttributes(fbWidth, fbHeight);
+ }
+
+
+ // Since external is rotated 90, need to swap width/height
+ int extOrient = getExtOrientation(ctx);
+
+ if(extOrient & HWC_TRANSFORM_ROT_90)
+ swap(fbWidth, fbHeight);
+
+ float asX = 0;
+ float asY = 0;
+ float asW = (float)fbWidth;
+ float asH = (float)fbHeight;
+
+ // based on the action safe ratio, get the Action safe rectangle
+ asW = ((float)fbWidth * (1.0f - (float)asWidthRatio / 100.0f));
+ asH = ((float)fbHeight * (1.0f - (float)asHeightRatio / 100.0f));
+ asX = ((float)fbWidth - asW) / 2;
+ asY = ((float)fbHeight - asH) / 2;
+
+ // calculate the position ratio
+ xRatio = (float)x/(float)fbWidth;
+ yRatio = (float)y/(float)fbHeight;
+ wRatio = (float)w/(float)fbWidth;
+ hRatio = (float)h/(float)fbHeight;
+
+ //Calculate the position...
+ x = int((xRatio * asW) + asX);
+ y = int((yRatio * asH) + asY);
+ w = int(wRatio * asW);
+ h = int(hRatio * asH);
+
+ // Convert it back to hwc_rect_t
+ rect.left = x;
+ rect.top = y;
+ rect.right = w + rect.left;
+ rect.bottom = h + rect.top;
+
+ return;
+}
+
+// This function gets the destination position for Seconday display
+// based on the position and aspect ratio with orientation
+void getAspectRatioPosition(hwc_context_t* ctx, int dpy, int extOrientation,
+ hwc_rect_t& inRect, hwc_rect_t& outRect) {
+ // Physical display resolution
+ float fbWidth = (float)ctx->dpyAttr[dpy].xres;
+ float fbHeight = (float)ctx->dpyAttr[dpy].yres;
+ //display position(x,y,w,h) in correct aspectratio after rotation
+ int xPos = 0;
+ int yPos = 0;
+ float width = fbWidth;
+ float height = fbHeight;
+ // Width/Height used for calculation, after rotation
+ float actualWidth = fbWidth;
+ float actualHeight = fbHeight;
+
+ float wRatio = 1.0;
+ float hRatio = 1.0;
+ float xRatio = 1.0;
+ float yRatio = 1.0;
+ hwc_rect_t rect = {0, 0, (int)fbWidth, (int)fbHeight};
+
+ Dim inPos(inRect.left, inRect.top, inRect.right - inRect.left,
+ inRect.bottom - inRect.top);
+ Dim outPos(outRect.left, outRect.top, outRect.right - outRect.left,
+ outRect.bottom - outRect.top);
+
+ Whf whf((uint32_t)fbWidth, (uint32_t)fbHeight, 0);
+ eTransform extorient = static_cast<eTransform>(extOrientation);
+ // To calculate the destination co-ordinates in the new orientation
+ preRotateSource(extorient, whf, inPos);
+
+ if(extOrientation & HAL_TRANSFORM_ROT_90) {
+ // Swap width/height for input position
+ swapWidthHeight(actualWidth, actualHeight);
+ qdutils::getAspectRatioPosition((int)fbWidth, (int)fbHeight,
+ (int)actualWidth, (int)actualHeight, rect);
+ xPos = rect.left;
+ yPos = rect.top;
+ width = float(rect.right - rect.left);
+ height = float(rect.bottom - rect.top);
+ }
+ xRatio = (float)((float)inPos.x/actualWidth);
+ yRatio = (float)((float)inPos.y/actualHeight);
+ wRatio = (float)((float)inPos.w/actualWidth);
+ hRatio = (float)((float)inPos.h/actualHeight);
+
+ //Calculate the pos9ition...
+ outPos.x = uint32_t((xRatio * width) + (float)xPos);
+ outPos.y = uint32_t((yRatio * height) + (float)yPos);
+ outPos.w = uint32_t(wRatio * width);
+ outPos.h = uint32_t(hRatio * height);
+ ALOGD_IF(HWC_UTILS_DEBUG, "%s: Calculated AspectRatio Position: x = %d,"
+ "y = %d w = %d h = %d", __FUNCTION__, outPos.x, outPos.y,
+ outPos.w, outPos.h);
+
+ // For sidesync, the dest fb will be in portrait orientation, and the crop
+ // will be updated to avoid the black side bands, and it will be upscaled
+ // to fit the dest RB, so recalculate
+ // the position based on the new width and height
+ if ((extOrientation & HWC_TRANSFORM_ROT_90) &&
+ isOrientationPortrait(ctx)) {
+ hwc_rect_t r = {0, 0, 0, 0};
+ //Calculate the position
+ xRatio = (float)(outPos.x - xPos)/width;
+ // GetaspectRatio -- tricky to get the correct aspect ratio
+ // But we need to do this.
+ qdutils::getAspectRatioPosition((int)width, (int)height,
+ (int)width,(int)height, r);
+ xPos = r.left;
+ yPos = r.top;
+ float tempHeight = float(r.bottom - r.top);
+ yRatio = (float)yPos/height;
+ wRatio = (float)outPos.w/width;
+ hRatio = tempHeight/height;
+
+ //Map the coordinates back to Framebuffer domain
+ outPos.x = uint32_t(xRatio * fbWidth);
+ outPos.y = uint32_t(yRatio * fbHeight);
+ outPos.w = uint32_t(wRatio * fbWidth);
+ outPos.h = uint32_t(hRatio * fbHeight);
+
+ ALOGD_IF(HWC_UTILS_DEBUG, "%s: Calculated AspectRatio for device in"
+ "portrait: x = %d,y = %d w = %d h = %d", __FUNCTION__,
+ outPos.x, outPos.y,
+ outPos.w, outPos.h);
+ }
+ if(ctx->dpyAttr[dpy].mMDPScalingMode) {
+ uint32_t extW = 0, extH = 0;
+ if(dpy == HWC_DISPLAY_EXTERNAL) {
+ ctx->mHDMIDisplay->getAttributes(extW, extH);
+ } else if(dpy == HWC_DISPLAY_VIRTUAL) {
+ extW = ctx->mHWCVirtual->getScalingWidth();
+ extH = ctx->mHWCVirtual->getScalingHeight();
+ }
+ ALOGD_IF(HWC_UTILS_DEBUG, "%s: Scaling mode extW=%d extH=%d",
+ __FUNCTION__, extW, extH);
+
+ fbWidth = (float)ctx->dpyAttr[dpy].xres;
+ fbHeight = (float)ctx->dpyAttr[dpy].yres;
+ //Calculate the position...
+ xRatio = (float)outPos.x/fbWidth;
+ yRatio = (float)outPos.y/fbHeight;
+ wRatio = (float)outPos.w/fbWidth;
+ hRatio = (float)outPos.h/fbHeight;
+
+ outPos.x = uint32_t(xRatio * (float)extW);
+ outPos.y = uint32_t(yRatio * (float)extH);
+ outPos.w = uint32_t(wRatio * (float)extW);
+ outPos.h = uint32_t(hRatio * (float)extH);
+ }
+ // Convert Dim to hwc_rect_t
+ outRect.left = outPos.x;
+ outRect.top = outPos.y;
+ outRect.right = outPos.x + outPos.w;
+ outRect.bottom = outPos.y + outPos.h;
+
+ return;
+}
+
+bool isPrimaryPortrait(hwc_context_t *ctx) {
+ int fbWidth = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
+ int fbHeight = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
+ if(fbWidth < fbHeight) {
+ return true;
+ }
+ return false;
+}
+
+bool isOrientationPortrait(hwc_context_t *ctx) {
+ if(isPrimaryPortrait(ctx)) {
+ return !(ctx->deviceOrientation & 0x1);
+ }
+ return (ctx->deviceOrientation & 0x1);
+}
+
+void calcExtDisplayPosition(hwc_context_t *ctx,
+ private_handle_t *hnd,
+ int dpy,
+ hwc_rect_t& sourceCrop,
+ hwc_rect_t& displayFrame,
+ int& transform,
+ ovutils::eTransform& orient) {
+ // Swap width and height when there is a 90deg transform
+ int extOrient = getExtOrientation(ctx);
+ if(dpy && ctx->mOverlay->isUIScalingOnExternalSupported()) {
+ if(!isYuvBuffer(hnd)) {
+ if(extOrient & HWC_TRANSFORM_ROT_90) {
+ int dstWidth = ctx->dpyAttr[dpy].xres;
+ int dstHeight = ctx->dpyAttr[dpy].yres;;
+ int srcWidth = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
+ int srcHeight = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
+ if(!isPrimaryPortrait(ctx)) {
+ swap(srcWidth, srcHeight);
+ } // Get Aspect Ratio for external
+ qdutils::getAspectRatioPosition(dstWidth, dstHeight, srcWidth,
+ srcHeight, displayFrame);
+ // Crop - this is needed, because for sidesync, the dest fb will
+ // be in portrait orientation, so update the crop to not show the
+ // black side bands.
+ if (isOrientationPortrait(ctx)) {
+ sourceCrop = displayFrame;
+ displayFrame.left = 0;
+ displayFrame.top = 0;
+ displayFrame.right = dstWidth;
+ displayFrame.bottom = dstHeight;
+ }
+ }
+ if(ctx->dpyAttr[dpy].mMDPScalingMode) {
+ uint32_t extW = 0, extH = 0;
+ // if MDP scaling mode is enabled, map the co-ordinates to new
+ // domain(downscaled)
+ float fbWidth = (float)ctx->dpyAttr[dpy].xres;
+ float fbHeight = (float)ctx->dpyAttr[dpy].yres;
+ // query MDP configured attributes
+ if(dpy == HWC_DISPLAY_EXTERNAL) {
+ ctx->mHDMIDisplay->getAttributes(extW, extH);
+ } else if(dpy == HWC_DISPLAY_VIRTUAL) {
+ extW = ctx->mHWCVirtual->getScalingWidth();
+ extH = ctx->mHWCVirtual->getScalingHeight();
+ }
+ ALOGD_IF(HWC_UTILS_DEBUG, "%s: Scaling mode extW=%d extH=%d",
+ __FUNCTION__, extW, extH);
+
+ //Calculate the ratio...
+ float wRatio = ((float)extW)/fbWidth;
+ float hRatio = ((float)extH)/fbHeight;
+
+ //convert Dim to hwc_rect_t
+ displayFrame.left = int(wRatio*(float)displayFrame.left);
+ displayFrame.top = int(hRatio*(float)displayFrame.top);
+ displayFrame.right = int(wRatio*(float)displayFrame.right);
+ displayFrame.bottom = int(hRatio*(float)displayFrame.bottom);
+ ALOGD_IF(DEBUG_MDPDOWNSCALE, "Calculated external display frame"
+ " for MDPDownscale feature [%d %d %d %d]",
+ displayFrame.left, displayFrame.top,
+ displayFrame.right, displayFrame.bottom);
+ }
+ }else {
+ if(extOrient || ctx->dpyAttr[dpy].mMDPScalingMode) {
+ getAspectRatioPosition(ctx, dpy, extOrient,
+ displayFrame, displayFrame);
+ }
+ }
+ // If there is a external orientation set, use that
+ if(extOrient) {
+ transform = extOrient;
+ orient = static_cast<ovutils::eTransform >(extOrient);
+ }
+ // Calculate the actionsafe dimensions for External(dpy = 1 or 2)
+ getActionSafePosition(ctx, dpy, displayFrame);
+ }
+}
+
+/* Returns the orientation which needs to be set on External for
+ * SideSync/Buffer Mirrormode
+ */
+int getMirrorModeOrientation(hwc_context_t *ctx) {
+ int extOrientation = 0;
+ int deviceOrientation = ctx->deviceOrientation;
+ if(!isPrimaryPortrait(ctx))
+ deviceOrientation = (deviceOrientation + 1) % 4;
+ if (deviceOrientation == 0)
+ extOrientation = HWC_TRANSFORM_ROT_270;
+ else if (deviceOrientation == 1)//90
+ extOrientation = 0;
+ else if (deviceOrientation == 2)//180
+ extOrientation = HWC_TRANSFORM_ROT_90;
+ else if (deviceOrientation == 3)//270
+ extOrientation = HWC_TRANSFORM_FLIP_V | HWC_TRANSFORM_FLIP_H;
+
+ return extOrientation;
+}
+
+/* Get External State names */
+const char* getExternalDisplayState(uint32_t external_state) {
+ static const char* externalStates[EXTERNAL_MAXSTATES] = {0};
+ externalStates[EXTERNAL_OFFLINE] = STR(EXTERNAL_OFFLINE);
+ externalStates[EXTERNAL_ONLINE] = STR(EXTERNAL_ONLINE);
+ externalStates[EXTERNAL_PAUSE] = STR(EXTERNAL_PAUSE);
+ externalStates[EXTERNAL_RESUME] = STR(EXTERNAL_RESUME);
+
+ if(external_state >= EXTERNAL_MAXSTATES) {
+ return "EXTERNAL_INVALID";
+ }
+
+ return externalStates[external_state];
+}
+
+bool isDownscaleRequired(hwc_layer_1_t const* layer) {
+ hwc_rect_t displayFrame = layer->displayFrame;
+ hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
+ int dst_w, dst_h, src_w, src_h;
+ dst_w = displayFrame.right - displayFrame.left;
+ dst_h = displayFrame.bottom - displayFrame.top;
+ src_w = sourceCrop.right - sourceCrop.left;
+ src_h = sourceCrop.bottom - sourceCrop.top;
+
+ if(((src_w > dst_w) || (src_h > dst_h)))
+ return true;
+
+ return false;
+}
+bool needsScaling(hwc_layer_1_t const* layer) {
+ int dst_w, dst_h, src_w, src_h;
+ hwc_rect_t displayFrame = layer->displayFrame;
+ hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
+
+ dst_w = displayFrame.right - displayFrame.left;
+ dst_h = displayFrame.bottom - displayFrame.top;
+ src_w = sourceCrop.right - sourceCrop.left;
+ src_h = sourceCrop.bottom - sourceCrop.top;
+
+ if(((src_w != dst_w) || (src_h != dst_h)))
+ return true;
+
+ return false;
+}
+
+// Checks if layer needs scaling with split
+bool needsScalingWithSplit(hwc_context_t* ctx, hwc_layer_1_t const* layer,
+ const int& dpy) {
+
+ int src_width_l, src_height_l;
+ int src_width_r, src_height_r;
+ int dst_width_l, dst_height_l;
+ int dst_width_r, dst_height_r;
+ int hw_w = ctx->dpyAttr[dpy].xres;
+ int hw_h = ctx->dpyAttr[dpy].yres;
+ hwc_rect_t cropL, dstL, cropR, dstR;
+ const int lSplit = getLeftSplit(ctx, dpy);
+ hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
+ hwc_rect_t displayFrame = layer->displayFrame;
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+
+ cropL = sourceCrop;
+ dstL = displayFrame;
+ hwc_rect_t scissorL = { 0, 0, lSplit, hw_h };
+ scissorL = getIntersection(ctx->mViewFrame[dpy], scissorL);
+ qhwc::calculate_crop_rects(cropL, dstL, scissorL, 0);
+
+ cropR = sourceCrop;
+ dstR = displayFrame;
+ hwc_rect_t scissorR = { lSplit, 0, hw_w, hw_h };
+ scissorR = getIntersection(ctx->mViewFrame[dpy], scissorR);
+ qhwc::calculate_crop_rects(cropR, dstR, scissorR, 0);
+
+ // Sanitize Crop to stitch
+ sanitizeSourceCrop(cropL, cropR, hnd);
+
+ // Calculate the left dst
+ dst_width_l = dstL.right - dstL.left;
+ dst_height_l = dstL.bottom - dstL.top;
+ src_width_l = cropL.right - cropL.left;
+ src_height_l = cropL.bottom - cropL.top;
+
+ // check if there is any scaling on the left
+ if(((src_width_l != dst_width_l) || (src_height_l != dst_height_l)))
+ return true;
+
+ // Calculate the right dst
+ dst_width_r = dstR.right - dstR.left;
+ dst_height_r = dstR.bottom - dstR.top;
+ src_width_r = cropR.right - cropR.left;
+ src_height_r = cropR.bottom - cropR.top;
+
+ // check if there is any scaling on the right
+ if(((src_width_r != dst_width_r) || (src_height_r != dst_height_r)))
+ return true;
+
+ return false;
+}
+
+bool isAlphaScaled(hwc_layer_1_t const* layer) {
+ if(needsScaling(layer) && isAlphaPresent(layer)) {
+ return true;
+ }
+ return false;
+}
+
+bool isAlphaPresent(hwc_layer_1_t const* layer) {
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(hnd) {
+ int format = hnd->format;
+ switch(format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ // In any more formats with Alpha go here..
+ return true;
+ default : return false;
+ }
+ }
+ return false;
+}
+
+bool isAlphaPresentinFB(hwc_context_t *ctx, int dpy) {
+ switch(ctx->dpyAttr[dpy].fbformat) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ return true;
+ default : return false;
+ }
+ return false;
+}
+
+static void trimLayer(hwc_context_t *ctx, const int& dpy, const int& transform,
+ hwc_rect_t& crop, hwc_rect_t& dst) {
+ int hw_w = ctx->dpyAttr[dpy].xres;
+ int hw_h = ctx->dpyAttr[dpy].yres;
+ if(dst.left < 0 || dst.top < 0 ||
+ dst.right > hw_w || dst.bottom > hw_h) {
+ hwc_rect_t scissor = {0, 0, hw_w, hw_h };
+ scissor = getIntersection(ctx->mViewFrame[dpy], scissor);
+ qhwc::calculate_crop_rects(crop, dst, scissor, transform);
+ }
+}
+
+static void trimList(hwc_context_t *ctx, hwc_display_contents_1_t *list,
+ const int& dpy) {
+ for(uint32_t i = 0; i < list->numHwLayers - 1; i++) {
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+ int transform = (list->hwLayers[i].flags & HWC_COLOR_FILL) ? 0 :
+ list->hwLayers[i].transform;
+ trimLayer(ctx, dpy,
+ transform,
+ (hwc_rect_t&)crop,
+ (hwc_rect_t&)list->hwLayers[i].displayFrame);
+ layer->sourceCropf.left = (float)crop.left;
+ layer->sourceCropf.right = (float)crop.right;
+ layer->sourceCropf.top = (float)crop.top;
+ layer->sourceCropf.bottom = (float)crop.bottom;
+ }
+}
+
+void setListStats(hwc_context_t *ctx,
+ hwc_display_contents_1_t *list, int dpy) {
+ const int prevYuvCount = ctx->listStats[dpy].yuvCount;
+ memset(&ctx->listStats[dpy], 0, sizeof(ListStats));
+ ctx->listStats[dpy].numAppLayers = (int)list->numHwLayers - 1;
+ ctx->listStats[dpy].fbLayerIndex = (int)list->numHwLayers - 1;
+ ctx->listStats[dpy].skipCount = 0;
+ ctx->listStats[dpy].preMultipliedAlpha = false;
+ ctx->listStats[dpy].isSecurePresent = false;
+ ctx->listStats[dpy].yuvCount = 0;
+ char property[PROPERTY_VALUE_MAX];
+ ctx->listStats[dpy].isDisplayAnimating = false;
+ ctx->listStats[dpy].secureUI = false;
+ ctx->listStats[dpy].yuv4k2kCount = 0;
+ ctx->dpyAttr[dpy].mActionSafePresent = isActionSafePresent(ctx, dpy);
+ ctx->listStats[dpy].renderBufIndexforABC = -1;
+ ctx->listStats[dpy].secureRGBCount = 0;
+ ctx->listStats[dpy].refreshRateRequest = ctx->dpyAttr[dpy].refreshRate;
+ uint32_t refreshRate = 0;
+ qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance();
+
+ ctx->listStats[dpy].mAIVVideoMode = false;
+ resetROI(ctx, dpy);
+
+ trimList(ctx, list, dpy);
+ optimizeLayerRects(list);
+ for (size_t i = 0; i < (size_t)ctx->listStats[dpy].numAppLayers; i++) {
+ hwc_layer_1_t const* layer = &list->hwLayers[i];
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+
+#ifdef QTI_BSP
+ // Window boxing feature is applicable obly for external display, So
+ // enable mAIVVideoMode only for external display
+ if(ctx->mWindowboxFeature && dpy && isAIVVideoLayer(layer)) {
+ ctx->listStats[dpy].mAIVVideoMode = true;
+ }
+ if (layer->flags & HWC_SCREENSHOT_ANIMATOR_LAYER) {
+ ctx->listStats[dpy].isDisplayAnimating = true;
+ }
+ if(isSecureDisplayBuffer(hnd)) {
+ ctx->listStats[dpy].secureUI = true;
+ }
+#endif
+ // continue if number of app layers exceeds MAX_NUM_APP_LAYERS
+ if(ctx->listStats[dpy].numAppLayers > MAX_NUM_APP_LAYERS)
+ continue;
+
+ //reset yuv indices
+ ctx->listStats[dpy].yuvIndices[i] = -1;
+ ctx->listStats[dpy].yuv4k2kIndices[i] = -1;
+
+ if (isSecureBuffer(hnd)) {
+ ctx->listStats[dpy].isSecurePresent = true;
+ if(not isYuvBuffer(hnd)) {
+ // cache secureRGB layer parameters like we cache for YUV layers
+ int& secureRGBCount = ctx->listStats[dpy].secureRGBCount;
+ ctx->listStats[dpy].secureRGBIndices[secureRGBCount] = (int)i;
+ secureRGBCount++;
+ }
+ }
+
+ if (isSkipLayer(&list->hwLayers[i])) {
+ ctx->listStats[dpy].skipCount++;
+ }
+
+ if (UNLIKELY(isYuvBuffer(hnd))) {
+ int& yuvCount = ctx->listStats[dpy].yuvCount;
+ ctx->listStats[dpy].yuvIndices[yuvCount] = (int)i;
+ yuvCount++;
+
+ if(UNLIKELY(isYUVSplitNeeded(hnd))){
+ int& yuv4k2kCount = ctx->listStats[dpy].yuv4k2kCount;
+ ctx->listStats[dpy].yuv4k2kIndices[yuv4k2kCount] = (int)i;
+ yuv4k2kCount++;
+ }
+ }
+ if(layer->blending == HWC_BLENDING_PREMULT)
+ ctx->listStats[dpy].preMultipliedAlpha = true;
+
+#ifdef DYNAMIC_FPS
+ if (!dpy && mdpHw.isDynFpsSupported() && ctx->mUseMetaDataRefreshRate){
+ /* Dyn fps: get refreshrate from metadata */
+ MetaData_t *mdata = hnd ? (MetaData_t *)hnd->base_metadata : NULL;
+ if (mdata && (mdata->operation & UPDATE_REFRESH_RATE)) {
+ // Valid refreshRate in metadata and within the range
+ uint32_t rate = getRefreshRate(ctx, mdata->refreshrate);
+ if (!refreshRate) {
+ refreshRate = rate;
+ } else if(refreshRate != rate) {
+ /* Support multiple refresh rates if they are same
+ * else set to default.
+ */
+ refreshRate = ctx->dpyAttr[dpy].refreshRate;
+ }
+ }
+ }
+#endif
+ }
+ if(ctx->listStats[dpy].yuvCount > 0) {
+ if (property_get("hw.cabl.yuv", property, NULL) > 0) {
+ if (atoi(property) != 1) {
+ property_set("hw.cabl.yuv", "1");
+ }
+ }
+ } else {
+ if (property_get("hw.cabl.yuv", property, NULL) > 0) {
+ if (atoi(property) != 0) {
+ property_set("hw.cabl.yuv", "0");
+ }
+ }
+ }
+
+ //The marking of video begin/end is useful on some targets where we need
+ //to have a padding round to be able to shift pipes across mixers.
+ if(prevYuvCount != ctx->listStats[dpy].yuvCount) {
+ ctx->mVideoTransFlag = true;
+ }
+
+ if(dpy == HWC_DISPLAY_PRIMARY) {
+ ctx->mAD->markDoable(ctx, list);
+ //Store the requested fresh rate
+ ctx->listStats[dpy].refreshRateRequest = refreshRate ?
+ refreshRate : ctx->dpyAttr[dpy].refreshRate;
+ }
+}
+
+
+static void calc_cut(double& leftCutRatio, double& topCutRatio,
+ double& rightCutRatio, double& bottomCutRatio, int orient) {
+ if(orient & HAL_TRANSFORM_FLIP_H) {
+ swap(leftCutRatio, rightCutRatio);
+ }
+ if(orient & HAL_TRANSFORM_FLIP_V) {
+ swap(topCutRatio, bottomCutRatio);
+ }
+ if(orient & HAL_TRANSFORM_ROT_90) {
+ //Anti clock swapping
+ double tmpCutRatio = leftCutRatio;
+ leftCutRatio = topCutRatio;
+ topCutRatio = rightCutRatio;
+ rightCutRatio = bottomCutRatio;
+ bottomCutRatio = tmpCutRatio;
+ }
+}
+
+bool isSecuring(hwc_context_t* ctx, hwc_layer_1_t const* layer) {
+ if((ctx->mMDP.version < qdutils::MDSS_V5) &&
+ (ctx->mMDP.version > qdutils::MDP_V3_0) &&
+ ctx->mSecuring) {
+ return true;
+ }
+ if (isSecureModePolicy(ctx->mMDP.version)) {
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(ctx->mSecureMode) {
+ if (! isSecureBuffer(hnd)) {
+ ALOGD_IF(HWC_UTILS_DEBUG,"%s:Securing Turning ON ...",
+ __FUNCTION__);
+ return true;
+ }
+ } else {
+ if (isSecureBuffer(hnd)) {
+ ALOGD_IF(HWC_UTILS_DEBUG,"%s:Securing Turning OFF ...",
+ __FUNCTION__);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool isSecureModePolicy(int mdpVersion) {
+ if (mdpVersion < qdutils::MDSS_V5)
+ return true;
+ else
+ return false;
+}
+
+bool isRotatorSupportedFormat(private_handle_t *hnd) {
+ // Following rotator src formats are supported by mdp driver
+ // TODO: Add more formats in future, if mdp driver adds support
+ switch(hnd->format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGB_565:
+ case HAL_PIXEL_FORMAT_RGB_888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ return true;
+ default:
+ return false;
+ }
+ return false;
+}
+
+bool isRotationDoable(hwc_context_t *ctx, private_handle_t *hnd) {
+ // Rotate layers, if it is YUV type or rendered by CPU and not
+ // for the MDP versions below MDP5
+ if((isCPURendered(hnd) && isRotatorSupportedFormat(hnd) &&
+ !ctx->mMDP.version < qdutils::MDSS_V5)
+ || isYuvBuffer(hnd)) {
+ return true;
+ }
+ return false;
+}
+
+// returns true if Action safe dimensions are set and target supports Actionsafe
+bool isActionSafePresent(hwc_context_t *ctx, int dpy) {
+ // if external supports underscan, do nothing
+ // it will be taken care in the driver
+ // Disable Action safe for 8974 due to HW limitation for downscaling
+ // layers with overlapped region
+ // Disable Actionsafe for non HDMI displays.
+ if(!(dpy == HWC_DISPLAY_EXTERNAL) ||
+ qdutils::MDPVersion::getInstance().is8x74v2() ||
+ ctx->mHDMIDisplay->isCEUnderscanSupported()) {
+ return false;
+ }
+
+ char value[PROPERTY_VALUE_MAX];
+ // Read action safe properties
+ property_get("persist.sys.actionsafe.width", value, "0");
+ ctx->dpyAttr[dpy].mAsWidthRatio = atoi(value);
+ property_get("persist.sys.actionsafe.height", value, "0");
+ ctx->dpyAttr[dpy].mAsHeightRatio = atoi(value);
+
+ if(!ctx->dpyAttr[dpy].mAsWidthRatio && !ctx->dpyAttr[dpy].mAsHeightRatio) {
+ //No action safe ratio set, return
+ return false;
+ }
+ return true;
+}
+
+int getBlending(int blending) {
+ switch(blending) {
+ case HWC_BLENDING_NONE:
+ return overlay::utils::OVERLAY_BLENDING_OPAQUE;
+ case HWC_BLENDING_PREMULT:
+ return overlay::utils::OVERLAY_BLENDING_PREMULT;
+ case HWC_BLENDING_COVERAGE :
+ default:
+ return overlay::utils::OVERLAY_BLENDING_COVERAGE;
+ }
+}
+
+//Crops source buffer against destination and FB boundaries
+void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst,
+ const hwc_rect_t& scissor, int orient) {
+
+ int& crop_l = crop.left;
+ int& crop_t = 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_l = dst.left;
+ int& dst_t = dst.top;
+ int& dst_r = dst.right;
+ int& dst_b = dst.bottom;
+ int dst_w = abs(dst.right - dst.left);
+ int dst_h = abs(dst.bottom - dst.top);
+
+ const int& sci_l = scissor.left;
+ const int& sci_t = scissor.top;
+ const int& sci_r = scissor.right;
+ const int& sci_b = scissor.bottom;
+
+ double leftCutRatio = 0.0, rightCutRatio = 0.0, topCutRatio = 0.0,
+ bottomCutRatio = 0.0;
+
+ if(dst_l < sci_l) {
+ leftCutRatio = (double)(sci_l - dst_l) / (double)dst_w;
+ dst_l = sci_l;
+ }
+
+ if(dst_r > sci_r) {
+ rightCutRatio = (double)(dst_r - sci_r) / (double)dst_w;
+ dst_r = sci_r;
+ }
+
+ if(dst_t < sci_t) {
+ topCutRatio = (double)(sci_t - dst_t) / (double)dst_h;
+ dst_t = sci_t;
+ }
+
+ if(dst_b > sci_b) {
+ bottomCutRatio = (double)(dst_b - sci_b) / (double)dst_h;
+ dst_b = sci_b;
+ }
+
+ calc_cut(leftCutRatio, topCutRatio, rightCutRatio, bottomCutRatio, orient);
+ crop_l += (int)round((double)crop_w * leftCutRatio);
+ crop_t += (int)round((double)crop_h * topCutRatio);
+ crop_r -= (int)round((double)crop_w * rightCutRatio);
+ crop_b -= (int)round((double)crop_h * bottomCutRatio);
+}
+
+bool areLayersIntersecting(const hwc_layer_1_t* layer1,
+ const hwc_layer_1_t* layer2) {
+ hwc_rect_t irect = getIntersection(layer1->displayFrame,
+ layer2->displayFrame);
+ return isValidRect(irect);
+}
+
+bool isSameRect(const hwc_rect& rect1, const hwc_rect& rect2)
+{
+ return ((rect1.left == rect2.left) && (rect1.top == rect2.top) &&
+ (rect1.right == rect2.right) && (rect1.bottom == rect2.bottom));
+}
+
+bool isValidRect(const hwc_rect& rect)
+{
+ return ((rect.bottom > rect.top) && (rect.right > rect.left)) ;
+}
+
+bool operator ==(const hwc_rect_t& lhs, const hwc_rect_t& rhs) {
+ if(lhs.left == rhs.left && lhs.top == rhs.top &&
+ lhs.right == rhs.right && lhs.bottom == rhs.bottom )
+ return true ;
+ return false;
+}
+
+bool layerUpdating(const hwc_layer_1_t* layer) {
+ hwc_region_t surfDamage = layer->surfaceDamage;
+ return ((surfDamage.numRects == 0) ||
+ isValidRect(layer->surfaceDamage.rects[0]));
+}
+
+hwc_rect_t calculateDirtyRect(const hwc_layer_1_t* layer,
+ hwc_rect_t& scissor) {
+ hwc_region_t surfDamage = layer->surfaceDamage;
+ hwc_rect_t src = integerizeSourceCrop(layer->sourceCropf);
+ hwc_rect_t dst = layer->displayFrame;
+ int x_off = dst.left - src.left;
+ int y_off = dst.top - src.top;
+ hwc_rect dirtyRect = (hwc_rect){0, 0, 0, 0};
+ hwc_rect_t updatingRect = dst;
+
+ if (surfDamage.numRects == 0) {
+ // full layer updating, dirty rect is full frame
+ dirtyRect = getIntersection(layer->displayFrame, scissor);
+ } else {
+ for(uint32_t i = 0; i < surfDamage.numRects; i++) {
+ updatingRect = moveRect(surfDamage.rects[i], x_off, y_off);
+ hwc_rect_t intersect = getIntersection(updatingRect, scissor);
+ if(isValidRect(intersect)) {
+ dirtyRect = getUnion(intersect, dirtyRect);
+ }
+ }
+ }
+ return dirtyRect;
+}
+
+hwc_rect_t moveRect(const hwc_rect_t& rect, const int& x_off, const int& y_off)
+{
+ hwc_rect_t res;
+
+ if(!isValidRect(rect))
+ return (hwc_rect_t){0, 0, 0, 0};
+
+ res.left = rect.left + x_off;
+ res.top = rect.top + y_off;
+ res.right = rect.right + x_off;
+ res.bottom = rect.bottom + y_off;
+
+ return res;
+}
+
+/* computes the intersection of two rects */
+hwc_rect_t getIntersection(const hwc_rect_t& rect1, const hwc_rect_t& rect2)
+{
+ hwc_rect_t res;
+
+ if(!isValidRect(rect1) || !isValidRect(rect2)){
+ return (hwc_rect_t){0, 0, 0, 0};
+ }
+
+
+ res.left = max(rect1.left, rect2.left);
+ res.top = max(rect1.top, rect2.top);
+ res.right = min(rect1.right, rect2.right);
+ res.bottom = min(rect1.bottom, rect2.bottom);
+
+ if(!isValidRect(res))
+ return (hwc_rect_t){0, 0, 0, 0};
+
+ return res;
+}
+
+/* computes the union of two rects */
+hwc_rect_t getUnion(const hwc_rect &rect1, const hwc_rect &rect2)
+{
+ hwc_rect_t res;
+
+ if(!isValidRect(rect1)){
+ return rect2;
+ }
+
+ if(!isValidRect(rect2)){
+ return rect1;
+ }
+
+ res.left = min(rect1.left, rect2.left);
+ res.top = min(rect1.top, rect2.top);
+ res.right = max(rect1.right, rect2.right);
+ res.bottom = max(rect1.bottom, rect2.bottom);
+
+ return res;
+}
+
+/* Not a geometrical rect deduction. Deducts rect2 from rect1 only if it results
+ * a single rect */
+hwc_rect_t deductRect(const hwc_rect_t& rect1, const hwc_rect_t& rect2) {
+
+ hwc_rect_t res = rect1;
+
+ if((rect1.left == rect2.left) && (rect1.right == rect2.right)) {
+ if((rect1.top == rect2.top) && (rect2.bottom <= rect1.bottom))
+ res.top = rect2.bottom;
+ else if((rect1.bottom == rect2.bottom)&& (rect2.top >= rect1.top))
+ res.bottom = rect2.top;
+ }
+ else if((rect1.top == rect2.top) && (rect1.bottom == rect2.bottom)) {
+ if((rect1.left == rect2.left) && (rect2.right <= rect1.right))
+ res.left = rect2.right;
+ else if((rect1.right == rect2.right)&& (rect2.left >= rect1.left))
+ res.right = rect2.left;
+ }
+ return res;
+}
+
+void optimizeLayerRects(const hwc_display_contents_1_t *list) {
+ int i= (int)list->numHwLayers-2;
+ while(i > 0) {
+ //see if there is no blending required.
+ //If it is opaque see if we can substract this region from below
+ //layers.
+ if(list->hwLayers[i].blending == HWC_BLENDING_NONE &&
+ list->hwLayers[i].planeAlpha == 0xFF) {
+ int j= i-1;
+ hwc_rect_t& topframe =
+ (hwc_rect_t&)list->hwLayers[i].displayFrame;
+ while(j >= 0) {
+ if(!needsScaling(&list->hwLayers[j])) {
+ hwc_layer_1_t* layer = (hwc_layer_1_t*)&list->hwLayers[j];
+ hwc_rect_t& bottomframe = layer->displayFrame;
+ hwc_rect_t bottomCrop =
+ integerizeSourceCrop(layer->sourceCropf);
+ int transform = (layer->flags & HWC_COLOR_FILL) ? 0 :
+ layer->transform;
+
+ hwc_rect_t irect = getIntersection(bottomframe, topframe);
+ if(isValidRect(irect)) {
+ hwc_rect_t dest_rect;
+ //if intersection is valid rect, deduct it
+ dest_rect = deductRect(bottomframe, irect);
+ qhwc::calculate_crop_rects(bottomCrop, bottomframe,
+ dest_rect, transform);
+ //Update layer sourceCropf
+ layer->sourceCropf.left =(float)bottomCrop.left;
+ layer->sourceCropf.top = (float)bottomCrop.top;
+ layer->sourceCropf.right = (float)bottomCrop.right;
+ layer->sourceCropf.bottom = (float)bottomCrop.bottom;
+ }
+ }
+ j--;
+ }
+ }
+ i--;
+ }
+}
+
+void getNonWormholeRegion(hwc_display_contents_1_t* list,
+ hwc_rect_t& nwr)
+{
+ size_t last = list->numHwLayers - 1;
+ hwc_rect_t fbDisplayFrame = list->hwLayers[last].displayFrame;
+ //Initiliaze nwr to first frame
+ nwr.left = list->hwLayers[0].displayFrame.left;
+ nwr.top = list->hwLayers[0].displayFrame.top;
+ nwr.right = list->hwLayers[0].displayFrame.right;
+ nwr.bottom = list->hwLayers[0].displayFrame.bottom;
+
+ for (size_t i = 1; i < last; i++) {
+ hwc_rect_t displayFrame = list->hwLayers[i].displayFrame;
+ nwr = getUnion(nwr, displayFrame);
+ }
+
+ //Intersect with the framebuffer
+ nwr = getIntersection(nwr, fbDisplayFrame);
+}
+
+bool isExternalActive(hwc_context_t* ctx) {
+ return ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive;
+}
+
+void closeAcquireFds(hwc_display_contents_1_t* list) {
+ if(LIKELY(list)) {
+ for(uint32_t i = 0; i < list->numHwLayers; i++) {
+ //Close the acquireFenceFds
+ //HWC_FRAMEBUFFER are -1 already by SF, rest we close.
+ if(list->hwLayers[i].acquireFenceFd >= 0) {
+ close(list->hwLayers[i].acquireFenceFd);
+ list->hwLayers[i].acquireFenceFd = -1;
+ }
+ }
+ //Writeback
+ if(list->outbufAcquireFenceFd >= 0) {
+ close(list->outbufAcquireFenceFd);
+ list->outbufAcquireFenceFd = -1;
+ }
+ }
+}
+
+int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy,
+ int fd) {
+ ATRACE_CALL();
+ int ret = 0;
+ int acquireFd[MAX_NUM_APP_LAYERS];
+ int count = 0;
+ int releaseFd = -1;
+ int retireFd = -1;
+ int fbFd = -1;
+ bool swapzero = false;
+
+ struct mdp_buf_sync data;
+ memset(&data, 0, sizeof(data));
+ data.acq_fen_fd = acquireFd;
+ data.rel_fen_fd = &releaseFd;
+ data.retire_fen_fd = &retireFd;
+ data.flags = MDP_BUF_SYNC_FLAG_RETIRE_FENCE;
+
+ char property[PROPERTY_VALUE_MAX];
+ if(property_get("debug.egl.swapinterval", property, "1") > 0) {
+ if(atoi(property) == 0)
+ swapzero = true;
+ }
+
+ bool isExtAnimating = false;
+ if(dpy)
+ isExtAnimating = ctx->listStats[dpy].isDisplayAnimating;
+
+ //Send acquireFenceFds to rotator
+ for(uint32_t i = 0; i < ctx->mLayerRotMap[dpy]->getCount(); i++) {
+ int rotFd = ctx->mRotMgr->getRotDevFd();
+ int rotReleaseFd = -1;
+ overlay::Rotator* currRot = ctx->mLayerRotMap[dpy]->getRot(i);
+ hwc_layer_1_t* currLayer = ctx->mLayerRotMap[dpy]->getLayer(i);
+ if((currRot == NULL) || (currLayer == NULL)) {
+ continue;
+ }
+ struct mdp_buf_sync rotData;
+ memset(&rotData, 0, sizeof(rotData));
+ rotData.acq_fen_fd =
+ &currLayer->acquireFenceFd;
+ rotData.rel_fen_fd = &rotReleaseFd; //driver to populate this
+ rotData.session_id = currRot->getSessId();
+ if(currLayer->acquireFenceFd >= 0) {
+ rotData.acq_fen_fd_cnt = 1; //1 ioctl call per rot session
+ }
+ int ret = 0;
+ if(LIKELY(!swapzero) and (not ctx->mLayerRotMap[dpy]->isRotCached(i)))
+ ret = ioctl(rotFd, MSMFB_BUFFER_SYNC, &rotData);
+
+ if(ret < 0) {
+ ALOGE("%s: ioctl MSMFB_BUFFER_SYNC failed for rot sync, err=%s",
+ __FUNCTION__, strerror(errno));
+ close(rotReleaseFd);
+ } else {
+ close(currLayer->acquireFenceFd);
+ //For MDP to wait on.
+ currLayer->acquireFenceFd =
+ dup(rotReleaseFd);
+ //A buffer is free to be used by producer as soon as its copied to
+ //rotator
+ currLayer->releaseFenceFd =
+ rotReleaseFd;
+ }
+ }
+
+ //Accumulate acquireFenceFds for MDP Overlays
+ if(list->outbufAcquireFenceFd >= 0) {
+ //Writeback output buffer
+ if(LIKELY(!swapzero) )
+ acquireFd[count++] = list->outbufAcquireFenceFd;
+ }
+
+ for(uint32_t i = 0; i < list->numHwLayers; i++) {
+ if(((isAbcInUse(ctx)== true ) ||
+ (list->hwLayers[i].compositionType == HWC_OVERLAY)) &&
+ list->hwLayers[i].acquireFenceFd >= 0) {
+ if(LIKELY(!swapzero) ) {
+ // if ABC is enabled for more than one layer.
+ // renderBufIndexforABC will work as FB.Hence
+ // set the acquireFD from fd - which is coming from copybit
+ if(fd >= 0 && (isAbcInUse(ctx) == true)) {
+ if(ctx->listStats[dpy].renderBufIndexforABC ==(int32_t)i)
+ acquireFd[count++] = fd;
+ else
+ continue;
+ } else
+ acquireFd[count++] = list->hwLayers[i].acquireFenceFd;
+ }
+ }
+ if(list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) {
+ if(LIKELY(!swapzero) ) {
+ if(fd >= 0) {
+ //set the acquireFD from fd - which is coming from c2d
+ acquireFd[count++] = fd;
+ // Buffer sync IOCTL should be async when using c2d fence is
+ // used
+ data.flags &= ~MDP_BUF_SYNC_FLAG_WAIT;
+ } else if(list->hwLayers[i].acquireFenceFd >= 0)
+ acquireFd[count++] = list->hwLayers[i].acquireFenceFd;
+ }
+ }
+ }
+
+ if ((fd >= 0) && !dpy && ctx->mPtorInfo.isActive()) {
+ // Acquire c2d fence of Overlap render buffer
+ if(LIKELY(!swapzero) )
+ acquireFd[count++] = fd;
+ }
+
+ data.acq_fen_fd_cnt = count;
+ fbFd = ctx->dpyAttr[dpy].fd;
+
+ //Waits for acquire fences, returns a release fence
+ if(LIKELY(!swapzero)) {
+ ret = ioctl(fbFd, MSMFB_BUFFER_SYNC, &data);
+ }
+
+ if(ret < 0) {
+ ALOGE("%s: ioctl MSMFB_BUFFER_SYNC failed, err=%s",
+ __FUNCTION__, strerror(errno));
+ ALOGE("%s: acq_fen_fd_cnt=%d flags=%d fd=%d dpy=%d numHwLayers=%zu",
+ __FUNCTION__, data.acq_fen_fd_cnt, data.flags, fbFd,
+ dpy, list->numHwLayers);
+ close(releaseFd);
+ releaseFd = -1;
+ close(retireFd);
+ retireFd = -1;
+ }
+
+ for(uint32_t i = 0; i < list->numHwLayers; i++) {
+ if(list->hwLayers[i].compositionType == HWC_OVERLAY ||
+#ifdef QTI_BSP
+ list->hwLayers[i].compositionType == HWC_BLIT ||
+#endif
+ list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) {
+ //Populate releaseFenceFds.
+ if(UNLIKELY(swapzero)) {
+ list->hwLayers[i].releaseFenceFd = -1;
+ } else if(isExtAnimating) {
+ // Release all the app layer fds immediately,
+ // if animation is in progress.
+ list->hwLayers[i].releaseFenceFd = -1;
+ } else if(list->hwLayers[i].releaseFenceFd < 0 ) {
+#ifdef QTI_BSP
+ //If rotator has not already populated this field
+ // & if it's a not VPU layer
+
+ // if ABC is enabled for more than one layer
+ if(fd >= 0 && (isAbcInUse(ctx) == true) &&
+ ctx->listStats[dpy].renderBufIndexforABC !=(int32_t)i){
+ list->hwLayers[i].releaseFenceFd = dup(fd);
+ } else if((list->hwLayers[i].compositionType == HWC_BLIT)&&
+ (isAbcInUse(ctx) == false)){
+ //For Blit, the app layers should be released when the Blit
+ //is complete. This fd was passed from copybit->draw
+ list->hwLayers[i].releaseFenceFd = dup(fd);
+ } else
+#endif
+ {
+ list->hwLayers[i].releaseFenceFd = dup(releaseFd);
+ }
+ }
+ }
+ }
+
+ if(fd >= 0) {
+ close(fd);
+ fd = -1;
+ }
+
+ if (ctx->mCopyBit[dpy]) {
+ if (!dpy && ctx->mPtorInfo.isActive())
+ ctx->mCopyBit[dpy]->setReleaseFdSync(releaseFd);
+ else
+ ctx->mCopyBit[dpy]->setReleaseFd(releaseFd);
+ }
+
+ //Signals when MDP finishes reading rotator buffers.
+ ctx->mLayerRotMap[dpy]->setReleaseFd(releaseFd);
+ close(releaseFd);
+ releaseFd = -1;
+
+ if(UNLIKELY(swapzero)) {
+ list->retireFenceFd = -1;
+ } else {
+ list->retireFenceFd = retireFd;
+ }
+ return ret;
+}
+
+void setMdpFlags(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ ovutils::eMdpFlags &mdpFlags,
+ int rotDownscale, int transform) {
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ MetaData_t *metadata = hnd ? (MetaData_t *)hnd->base_metadata : NULL;
+
+ if(layer->blending == HWC_BLENDING_PREMULT) {
+ ovutils::setMdpFlags(mdpFlags,
+ ovutils::OV_MDP_BLEND_FG_PREMULT);
+ }
+
+ if(metadata && (metadata->operation & PP_PARAM_INTERLACED) &&
+ metadata->interlaced) {
+ ovutils::setMdpFlags(mdpFlags,
+ ovutils::OV_MDP_DEINTERLACE);
+ }
+
+ // Mark MDP flags with SECURE_OVERLAY_SESSION for driver
+ if(isSecureBuffer(hnd)) {
+ ovutils::setMdpFlags(mdpFlags,
+ ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
+ }
+
+ if(isSecureDisplayBuffer(hnd)) {
+ // Mark MDP flags with SECURE_DISPLAY_OVERLAY_SESSION for driver
+ ovutils::setMdpFlags(mdpFlags,
+ ovutils::OV_MDP_SECURE_DISPLAY_OVERLAY_SESSION);
+ }
+
+ //Pre-rotation will be used using rotator.
+ if(has90Transform(layer) && isRotationDoable(ctx, hnd)) {
+ ovutils::setMdpFlags(mdpFlags,
+ ovutils::OV_MDP_SOURCE_ROTATED_90);
+ }
+ //No 90 component and no rot-downscale then flips done by MDP
+ //If we use rot then it might as well do flips
+ if(!(transform & HWC_TRANSFORM_ROT_90) && !rotDownscale) {
+ if(transform & HWC_TRANSFORM_FLIP_H) {
+ ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_FLIP_H);
+ }
+
+ if(transform & HWC_TRANSFORM_FLIP_V) {
+ ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_FLIP_V);
+ }
+ }
+
+ if(metadata &&
+ ((metadata->operation & PP_PARAM_HSIC)
+ || (metadata->operation & PP_PARAM_IGC)
+ || (metadata->operation & PP_PARAM_SHARP2))) {
+ ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_PP_EN);
+ }
+}
+
+int configRotator(Rotator *rot, Whf& whf,
+ hwc_rect_t& crop, const eMdpFlags& mdpFlags,
+ const eTransform& orient, const int& downscale) {
+
+ // Fix alignments for TILED format
+ if(whf.format == MDP_Y_CRCB_H2V2_TILE ||
+ whf.format == MDP_Y_CBCR_H2V2_TILE) {
+ whf.w = utils::alignup(whf.w, 64);
+ whf.h = utils::alignup(whf.h, 32);
+ }
+ rot->setSource(whf);
+
+ if (qdutils::MDPVersion::getInstance().getMDPVersion() >=
+ qdutils::MDSS_V5) {
+ Dim rotCrop(crop.left, crop.top, crop.right - crop.left,
+ crop.bottom - crop.top);
+ rot->setCrop(rotCrop);
+ }
+
+ rot->setFlags(mdpFlags);
+ rot->setTransform(orient);
+ rot->setDownscale(downscale);
+ if(!rot->commit()) return -1;
+ return 0;
+}
+
+int configMdp(Overlay *ov, const PipeArgs& parg,
+ const eTransform& orient, const hwc_rect_t& crop,
+ const hwc_rect_t& pos, const MetaData_t *metadata,
+ const eDest& dest) {
+ ov->setSource(parg, dest);
+ ov->setTransform(orient, dest);
+
+ int crop_w = crop.right - crop.left;
+ int crop_h = crop.bottom - crop.top;
+ Dim dcrop(crop.left, crop.top, crop_w, crop_h);
+ ov->setCrop(dcrop, dest);
+
+ int posW = pos.right - pos.left;
+ int posH = pos.bottom - pos.top;
+ Dim position(pos.left, pos.top, posW, posH);
+ ov->setPosition(position, dest);
+
+ if (metadata)
+ ov->setVisualParams(*metadata, dest);
+
+ if (!ov->commit(dest)) {
+ return -1;
+ }
+ return 0;
+}
+
+int configColorLayer(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ const int& dpy, eMdpFlags& mdpFlags, eZorder& z,
+ const eDest& dest) {
+
+ hwc_rect_t dst = layer->displayFrame;
+ trimLayer(ctx, dpy, 0, dst, dst);
+
+ int w = ctx->dpyAttr[dpy].xres;
+ int h = ctx->dpyAttr[dpy].yres;
+ int dst_w = dst.right - dst.left;
+ int dst_h = dst.bottom - dst.top;
+ uint32_t color = layer->transform;
+ Whf whf(w, h, getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888), 0);
+
+ ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_SOLID_FILL);
+ if (layer->blending == HWC_BLENDING_PREMULT)
+ ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_BLEND_FG_PREMULT);
+
+ PipeArgs parg(mdpFlags, whf, z, static_cast<eRotFlags>(0),
+ layer->planeAlpha,
+ (ovutils::eBlending) getBlending(layer->blending));
+
+ // Configure MDP pipe for Color layer
+ Dim pos(dst.left, dst.top, dst_w, dst_h);
+ ctx->mOverlay->setSource(parg, dest);
+ ctx->mOverlay->setColor(color, dest);
+ ctx->mOverlay->setTransform(0, dest);
+ ctx->mOverlay->setCrop(pos, dest);
+ ctx->mOverlay->setPosition(pos, dest);
+
+ if (!ctx->mOverlay->commit(dest)) {
+ ALOGE("%s: Configure color layer failed!", __FUNCTION__);
+ return -1;
+ }
+ return 0;
+}
+
+void updateSource(eTransform& orient, Whf& whf,
+ hwc_rect_t& crop, Rotator *rot) {
+ Dim transformedCrop(crop.left, crop.top,
+ crop.right - crop.left,
+ crop.bottom - crop.top);
+ if (qdutils::MDPVersion::getInstance().getMDPVersion() >=
+ qdutils::MDSS_V5) {
+ //B-family rotator internally could modify destination dimensions if
+ //downscaling is supported
+ whf = rot->getDstWhf();
+ transformedCrop = rot->getDstDimensions();
+ } else {
+ //A-family rotator rotates entire buffer irrespective of crop, forcing
+ //us to recompute the crop based on transform
+ orient = static_cast<eTransform>(ovutils::getMdpOrient(orient));
+ preRotateSource(orient, whf, transformedCrop);
+ }
+
+ crop.left = transformedCrop.x;
+ crop.top = transformedCrop.y;
+ crop.right = transformedCrop.x + transformedCrop.w;
+ crop.bottom = transformedCrop.y + transformedCrop.h;
+}
+
+int getRotDownscale(hwc_context_t *ctx, const hwc_layer_1_t *layer) {
+ if(not qdutils::MDPVersion::getInstance().isRotDownscaleEnabled()) {
+ return 0;
+ }
+
+ int downscale = 0;
+ hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+ hwc_rect_t dst = layer->displayFrame;
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+
+ if(not hnd) {
+ return 0;
+ }
+
+ MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+ bool isInterlaced = metadata && (metadata->operation & PP_PARAM_INTERLACED)
+ && metadata->interlaced;
+ int transform = layer->transform;
+ uint32_t format = ovutils::getMdpFormat(hnd->format, isTileRendered(hnd));
+
+ if(isYuvBuffer(hnd)) {
+ if(ctx->mMDP.version >= qdutils::MDP_V4_2 &&
+ ctx->mMDP.version < qdutils::MDSS_V5) {
+ downscale = Rotator::getDownscaleFactor(crop.right - crop.left,
+ crop.bottom - crop.top, dst.right - dst.left,
+ dst.bottom - dst.top, format, isInterlaced);
+ } else {
+ Dim adjCrop(crop.left, crop.top, crop.right - crop.left,
+ crop.bottom - crop.top);
+ Dim pos(dst.left, dst.top, dst.right - dst.left,
+ dst.bottom - dst.top);
+ if(transform & HAL_TRANSFORM_ROT_90) {
+ swap(adjCrop.w, adjCrop.h);
+ }
+ downscale = Rotator::getDownscaleFactor(adjCrop.w, adjCrop.h, pos.w,
+ pos.h, format, isInterlaced);
+ }
+ }
+ return downscale;
+}
+
+bool isZoomModeEnabled(hwc_rect_t crop) {
+ // This does not work for zooming in top left corner of the image
+ return(crop.top > 0 || crop.left > 0);
+}
+
+void updateCropAIVVideoMode(hwc_context_t *ctx, hwc_rect_t& crop, int dpy) {
+ ALOGD_IF(HWC_UTILS_DEBUG, "dpy %d Source crop [%d %d %d %d]", dpy,
+ crop.left, crop.top, crop.right, crop.bottom);
+ if(isZoomModeEnabled(crop)) {
+ Dim srcCrop(crop.left, crop.top,
+ crop.right - crop.left,
+ crop.bottom - crop.top);
+ int extW = ctx->dpyAttr[dpy].xres;
+ int extH = ctx->dpyAttr[dpy].yres;
+ //Crop the original video in order to fit external display aspect ratio
+ if(srcCrop.w * extH < extW * srcCrop.h) {
+ int offset = (srcCrop.h - ((srcCrop.w * extH) / extW)) / 2;
+ crop.top += offset;
+ crop.bottom -= offset;
+ } else {
+ int offset = (srcCrop.w - ((extW * srcCrop.h) / extH)) / 2;
+ crop.left += offset;
+ crop.right -= offset;
+ }
+ ALOGD_IF(HWC_UTILS_DEBUG, "External Resolution [%d %d] dpy %d Modified"
+ " source crop [%d %d %d %d]", extW, extH, dpy,
+ crop.left, crop.top, crop.right, crop.bottom);
+ }
+}
+
+void updateDestAIVVideoMode(hwc_context_t *ctx, hwc_rect_t crop,
+ hwc_rect_t& dst, int dpy) {
+ ALOGD_IF(HWC_UTILS_DEBUG, "dpy %d Destination position [%d %d %d %d]", dpy,
+ dst.left, dst.top, dst.right, dst.bottom);
+ Dim srcCrop(crop.left, crop.top,
+ crop.right - crop.left,
+ crop.bottom - crop.top);
+ int extW = ctx->dpyAttr[dpy].xres;
+ int extH = ctx->dpyAttr[dpy].yres;
+ // Set the destination coordinates of external display to full screen,
+ // when zoom in mode is enabled or the ratio between video aspect ratio
+ // and external display aspect ratio is below the minimum tolerance level
+ // and above maximum tolerance level
+ float videoAspectRatio = ((float)srcCrop.w / (float)srcCrop.h);
+ float extDisplayAspectRatio = ((float)extW / (float)extH);
+ float videoToExternalRatio = videoAspectRatio / extDisplayAspectRatio;
+ if((fabs(1.0f - videoToExternalRatio) <= ctx->mAspectRatioToleranceLevel) ||
+ (isZoomModeEnabled(crop))) {
+ dst.left = 0;
+ dst.top = 0;
+ dst.right = extW;
+ dst.bottom = extH;
+ }
+ ALOGD_IF(HWC_UTILS_DEBUG, "External Resolution [%d %d] dpy %d Modified"
+ " Destination position [%d %d %d %d] Source crop [%d %d %d %d]",
+ extW, extH, dpy, dst.left, dst.top, dst.right, dst.bottom,
+ crop.left, crop.top, crop.right, crop.bottom);
+}
+
+void updateCoordinates(hwc_context_t *ctx, hwc_rect_t& crop,
+ hwc_rect_t& dst, int dpy) {
+ updateCropAIVVideoMode(ctx, crop, dpy);
+ updateDestAIVVideoMode(ctx, crop, dst, dpy);
+}
+
+int configureNonSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ const int& dpy, eMdpFlags& mdpFlags, eZorder& z,
+ const eDest& dest, Rotator **rot) {
+
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+
+ if(!hnd) {
+ if (layer->flags & HWC_COLOR_FILL) {
+ // Configure Color layer
+ return configColorLayer(ctx, layer, dpy, mdpFlags, z, dest);
+ }
+ ALOGE("%s: layer handle is NULL", __FUNCTION__);
+ return -1;
+ }
+
+ MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+
+ hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+ hwc_rect_t dst = layer->displayFrame;
+ int transform = layer->transform;
+ eTransform orient = static_cast<eTransform>(transform);
+ int rotFlags = ovutils::ROT_FLAGS_NONE;
+ uint32_t format = ovutils::getMdpFormat(hnd->format, isTileRendered(hnd));
+ Whf whf(getWidth(hnd), getHeight(hnd), format, (uint32_t)hnd->size);
+
+ // Handle R/B swap
+ if (layer->flags & HWC_FORMAT_RB_SWAP) {
+ if (hnd->format == HAL_PIXEL_FORMAT_RGBA_8888)
+ whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRA_8888);
+ else if (hnd->format == HAL_PIXEL_FORMAT_RGBX_8888)
+ whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRX_8888);
+ }
+ // update source crop and destination position of AIV video layer.
+ if(ctx->listStats[dpy].mAIVVideoMode && isYuvBuffer(hnd)) {
+ updateCoordinates(ctx, crop, dst, dpy);
+ }
+ calcExtDisplayPosition(ctx, hnd, dpy, crop, dst, transform, orient);
+ int downscale = getRotDownscale(ctx, layer);
+ setMdpFlags(ctx, layer, mdpFlags, downscale, transform);
+
+ //if 90 component or downscale, use rot
+ if((has90Transform(layer) or downscale) and isRotationDoable(ctx, hnd)) {
+ *rot = ctx->mRotMgr->getNext();
+ if(*rot == NULL) return -1;
+ ctx->mLayerRotMap[dpy]->add(layer, *rot);
+ // BWC is not tested for other formats So enable it only for YUV format
+ if(!dpy && isYuvBuffer(hnd))
+ BwcPM::setBwc(crop, dst, transform, downscale, mdpFlags);
+ //Configure rotator for pre-rotation
+ if(configRotator(*rot, whf, crop, mdpFlags, orient, downscale) < 0) {
+ ALOGE("%s: configRotator failed!", __FUNCTION__);
+ return -1;
+ }
+ updateSource(orient, whf, crop, *rot);
+ rotFlags |= ROT_PREROTATED;
+ }
+
+ //For the mdp, since either we are pre-rotating or MDP does flips
+ orient = OVERLAY_TRANSFORM_0;
+ transform = 0;
+ PipeArgs parg(mdpFlags, whf, z,
+ static_cast<eRotFlags>(rotFlags), layer->planeAlpha,
+ (ovutils::eBlending) getBlending(layer->blending));
+
+ if(configMdp(ctx->mOverlay, parg, orient, crop, dst, metadata, dest) < 0) {
+ ALOGE("%s: commit failed for low res panel", __FUNCTION__);
+ return -1;
+ }
+ return 0;
+}
+
+//Helper to 1) Ensure crops dont have gaps 2) Ensure L and W are even
+void sanitizeSourceCrop(hwc_rect_t& cropL, hwc_rect_t& cropR,
+ private_handle_t *hnd) {
+ if(cropL.right - cropL.left) {
+ if(isYuvBuffer(hnd)) {
+ //Always safe to even down left
+ ovutils::even_floor(cropL.left);
+ //If right is even, automatically width is even, since left is
+ //already even
+ ovutils::even_floor(cropL.right);
+ }
+ //Make sure there are no gaps between left and right splits if the layer
+ //is spread across BOTH halves
+ if(cropR.right - cropR.left) {
+ cropR.left = cropL.right;
+ }
+ }
+
+ if(cropR.right - cropR.left) {
+ if(isYuvBuffer(hnd)) {
+ //Always safe to even down left
+ ovutils::even_floor(cropR.left);
+ //If right is even, automatically width is even, since left is
+ //already even
+ ovutils::even_floor(cropR.right);
+ }
+ }
+}
+
+int configureSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ const int& dpy, eMdpFlags& mdpFlagsL, eZorder& z,
+ const eDest& lDest, const eDest& rDest,
+ Rotator **rot) {
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(!hnd) {
+ ALOGE("%s: layer handle is NULL", __FUNCTION__);
+ return -1;
+ }
+
+ MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+
+ int hw_w = ctx->dpyAttr[dpy].xres;
+ int hw_h = ctx->dpyAttr[dpy].yres;
+ hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+ hwc_rect_t dst = layer->displayFrame;
+ int transform = layer->transform;
+ eTransform orient = static_cast<eTransform>(transform);
+ int rotFlags = ROT_FLAGS_NONE;
+ uint32_t format = ovutils::getMdpFormat(hnd->format, isTileRendered(hnd));
+ Whf whf(getWidth(hnd), getHeight(hnd), format, (uint32_t)hnd->size);
+
+ // Handle R/B swap
+ if (layer->flags & HWC_FORMAT_RB_SWAP) {
+ if (hnd->format == HAL_PIXEL_FORMAT_RGBA_8888)
+ whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRA_8888);
+ else if (hnd->format == HAL_PIXEL_FORMAT_RGBX_8888)
+ whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRX_8888);
+ }
+
+ // update source crop and destination position of AIV video layer.
+ if(ctx->listStats[dpy].mAIVVideoMode && isYuvBuffer(hnd)) {
+ updateCoordinates(ctx, crop, dst, dpy);
+ }
+
+ /* Calculate the external display position based on MDP downscale,
+ ActionSafe, and extorientation features. */
+ calcExtDisplayPosition(ctx, hnd, dpy, crop, dst, transform, orient);
+ int downscale = getRotDownscale(ctx, layer);
+ setMdpFlags(ctx, layer, mdpFlagsL, downscale, transform);
+
+ if(lDest != OV_INVALID && rDest != OV_INVALID) {
+ //Enable overfetch
+ setMdpFlags(mdpFlagsL, OV_MDSS_MDP_DUAL_PIPE);
+ }
+
+ //Will do something only if feature enabled and conditions suitable
+ //hollow call otherwise
+ if(ctx->mAD->prepare(ctx, crop, whf, hnd)) {
+ overlay::Writeback *wb = overlay::Writeback::getInstance();
+ whf.format = wb->getOutputFormat();
+ }
+
+ if((has90Transform(layer) or downscale) and isRotationDoable(ctx, hnd)) {
+ (*rot) = ctx->mRotMgr->getNext();
+ if((*rot) == NULL) return -1;
+ ctx->mLayerRotMap[dpy]->add(layer, *rot);
+ //Configure rotator for pre-rotation
+ if(configRotator(*rot, whf, crop, mdpFlagsL, orient, downscale) < 0) {
+ ALOGE("%s: configRotator failed!", __FUNCTION__);
+ return -1;
+ }
+ updateSource(orient, whf, crop, *rot);
+ rotFlags |= ROT_PREROTATED;
+ }
+
+ eMdpFlags mdpFlagsR = mdpFlagsL;
+ setMdpFlags(mdpFlagsR, OV_MDSS_MDP_RIGHT_MIXER);
+
+ hwc_rect_t tmp_cropL = {0}, tmp_dstL = {0};
+ hwc_rect_t tmp_cropR = {0}, tmp_dstR = {0};
+
+ const int lSplit = getLeftSplit(ctx, dpy);
+
+ // Calculate Left rects
+ if(dst.left < lSplit) {
+ tmp_cropL = crop;
+ tmp_dstL = dst;
+ hwc_rect_t scissor = {0, 0, lSplit, hw_h };
+ scissor = getIntersection(ctx->mViewFrame[dpy], scissor);
+ qhwc::calculate_crop_rects(tmp_cropL, tmp_dstL, scissor, 0);
+ }
+
+ // Calculate Right rects
+ if(dst.right > lSplit) {
+ tmp_cropR = crop;
+ tmp_dstR = dst;
+ hwc_rect_t scissor = {lSplit, 0, hw_w, hw_h };
+ scissor = getIntersection(ctx->mViewFrame[dpy], scissor);
+ qhwc::calculate_crop_rects(tmp_cropR, tmp_dstR, scissor, 0);
+ }
+
+ sanitizeSourceCrop(tmp_cropL, tmp_cropR, hnd);
+
+ //When buffer is H-flipped, contents of mixer config also needs to swapped
+ //Not needed if the layer is confined to one half of the screen.
+ //If rotator has been used then it has also done the flips, so ignore them.
+ if((orient & OVERLAY_TRANSFORM_FLIP_H) && (dst.left < lSplit) &&
+ (dst.right > lSplit) && (*rot) == NULL) {
+ hwc_rect_t new_cropR;
+ new_cropR.left = tmp_cropL.left;
+ new_cropR.right = new_cropR.left + (tmp_cropR.right - tmp_cropR.left);
+
+ hwc_rect_t new_cropL;
+ new_cropL.left = new_cropR.right;
+ new_cropL.right = tmp_cropR.right;
+
+ tmp_cropL.left = new_cropL.left;
+ tmp_cropL.right = new_cropL.right;
+
+ tmp_cropR.left = new_cropR.left;
+ tmp_cropR.right = new_cropR.right;
+
+ }
+
+ //For the mdp, since either we are pre-rotating or MDP does flips
+ orient = OVERLAY_TRANSFORM_0;
+ transform = 0;
+
+ //configure left mixer
+ if(lDest != OV_INVALID) {
+ PipeArgs pargL(mdpFlagsL, whf, z,
+ static_cast<eRotFlags>(rotFlags), layer->planeAlpha,
+ (ovutils::eBlending) getBlending(layer->blending));
+
+ if(configMdp(ctx->mOverlay, pargL, orient,
+ tmp_cropL, tmp_dstL, metadata, lDest) < 0) {
+ ALOGE("%s: commit failed for left mixer config", __FUNCTION__);
+ return -1;
+ }
+ }
+
+ //configure right mixer
+ if(rDest != OV_INVALID) {
+ PipeArgs pargR(mdpFlagsR, whf, z,
+ static_cast<eRotFlags>(rotFlags),
+ layer->planeAlpha,
+ (ovutils::eBlending) getBlending(layer->blending));
+ tmp_dstR.right = tmp_dstR.right - lSplit;
+ tmp_dstR.left = tmp_dstR.left - lSplit;
+ if(configMdp(ctx->mOverlay, pargR, orient,
+ tmp_cropR, tmp_dstR, metadata, rDest) < 0) {
+ ALOGE("%s: commit failed for right mixer config", __FUNCTION__);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int configureSourceSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ const int& dpy, eMdpFlags& mdpFlagsL, eZorder& z,
+ const eDest& lDest, const eDest& rDest,
+ Rotator **rot) {
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if(!hnd) {
+ ALOGE("%s: layer handle is NULL", __FUNCTION__);
+ return -1;
+ }
+
+ MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+
+ hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);;
+ hwc_rect_t dst = layer->displayFrame;
+ int transform = layer->transform;
+ eTransform orient = static_cast<eTransform>(transform);
+ const int downscale = 0;
+ int rotFlags = ROT_FLAGS_NONE;
+ //Splitting only YUV layer on primary panel needs different zorders
+ //for both layers as both the layers are configured to single mixer
+ eZorder lz = z;
+ eZorder rz = (eZorder)(z + 1);
+
+ Whf whf(getWidth(hnd), getHeight(hnd),
+ getMdpFormat(hnd->format), (uint32_t)hnd->size);
+
+ // update source crop and destination position of AIV video layer.
+ if(ctx->listStats[dpy].mAIVVideoMode && isYuvBuffer(hnd)) {
+ updateCoordinates(ctx, crop, dst, dpy);
+ }
+
+ /* Calculate the external display position based on MDP downscale,
+ ActionSafe, and extorientation features. */
+ calcExtDisplayPosition(ctx, hnd, dpy, crop, dst, transform, orient);
+
+ setMdpFlags(ctx, layer, mdpFlagsL, 0, transform);
+ trimLayer(ctx, dpy, transform, crop, dst);
+
+ if(has90Transform(layer) && isRotationDoable(ctx, hnd)) {
+ (*rot) = ctx->mRotMgr->getNext();
+ if((*rot) == NULL) return -1;
+ ctx->mLayerRotMap[dpy]->add(layer, *rot);
+ // BWC is not tested for other formats So enable it only for YUV format
+ if(!dpy && isYuvBuffer(hnd))
+ BwcPM::setBwc(crop, dst, transform, downscale, mdpFlagsL);
+ //Configure rotator for pre-rotation
+ if(configRotator(*rot, whf, crop, mdpFlagsL, orient, downscale) < 0) {
+ ALOGE("%s: configRotator failed!", __FUNCTION__);
+ return -1;
+ }
+ updateSource(orient, whf, crop, *rot);
+ rotFlags |= ROT_PREROTATED;
+ }
+
+ eMdpFlags mdpFlagsR = mdpFlagsL;
+ int lSplit = dst.left + (dst.right - dst.left)/2;
+
+ hwc_rect_t tmp_cropL = {0}, tmp_dstL = {0};
+ hwc_rect_t tmp_cropR = {0}, tmp_dstR = {0};
+
+ if(lDest != OV_INVALID) {
+ tmp_cropL = crop;
+ tmp_dstL = dst;
+ hwc_rect_t scissor = {dst.left, dst.top, lSplit, dst.bottom };
+ qhwc::calculate_crop_rects(tmp_cropL, tmp_dstL, scissor, 0);
+ }
+ if(rDest != OV_INVALID) {
+ tmp_cropR = crop;
+ tmp_dstR = dst;
+ hwc_rect_t scissor = {lSplit, dst.top, dst.right, dst.bottom };
+ qhwc::calculate_crop_rects(tmp_cropR, tmp_dstR, scissor, 0);
+ }
+
+ sanitizeSourceCrop(tmp_cropL, tmp_cropR, hnd);
+
+ //When buffer is H-flipped, contents of mixer config also needs to swapped
+ //Not needed if the layer is confined to one half of the screen.
+ //If rotator has been used then it has also done the flips, so ignore them.
+ if((orient & OVERLAY_TRANSFORM_FLIP_H) && lDest != OV_INVALID
+ && rDest != OV_INVALID && (*rot) == NULL) {
+ hwc_rect_t new_cropR;
+ new_cropR.left = tmp_cropL.left;
+ new_cropR.right = new_cropR.left + (tmp_cropR.right - tmp_cropR.left);
+
+ hwc_rect_t new_cropL;
+ new_cropL.left = new_cropR.right;
+ new_cropL.right = tmp_cropR.right;
+
+ tmp_cropL.left = new_cropL.left;
+ tmp_cropL.right = new_cropL.right;
+
+ tmp_cropR.left = new_cropR.left;
+ tmp_cropR.right = new_cropR.right;
+
+ }
+
+ //For the mdp, since either we are pre-rotating or MDP does flips
+ orient = OVERLAY_TRANSFORM_0;
+ transform = 0;
+
+ //configure left half
+ if(lDest != OV_INVALID) {
+ PipeArgs pargL(mdpFlagsL, whf, lz,
+ static_cast<eRotFlags>(rotFlags), layer->planeAlpha,
+ (ovutils::eBlending) getBlending(layer->blending));
+
+ if(configMdp(ctx->mOverlay, pargL, orient,
+ tmp_cropL, tmp_dstL, metadata, lDest) < 0) {
+ ALOGE("%s: commit failed for left half config", __FUNCTION__);
+ return -1;
+ }
+ }
+
+ //configure right half
+ if(rDest != OV_INVALID) {
+ PipeArgs pargR(mdpFlagsR, whf, rz,
+ static_cast<eRotFlags>(rotFlags),
+ layer->planeAlpha,
+ (ovutils::eBlending) getBlending(layer->blending));
+ if(configMdp(ctx->mOverlay, pargR, orient,
+ tmp_cropR, tmp_dstR, metadata, rDest) < 0) {
+ ALOGE("%s: commit failed for right half config", __FUNCTION__);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+bool canUseRotator(hwc_context_t *ctx, int dpy) {
+ if(ctx->mOverlay->isDMAMultiplexingSupported() &&
+ isSecondaryConnected(ctx) &&
+ !ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isPause) {
+ /* mdss driver on certain targets support multiplexing of DMA pipe
+ * in LINE and BLOCK modes for writeback panels.
+ */
+ if(dpy == HWC_DISPLAY_PRIMARY)
+ return false;
+ }
+ if((ctx->mMDP.version == qdutils::MDP_V3_0_4)
+ ||(ctx->mMDP.version == qdutils::MDP_V3_0_5))
+ return false;
+ return true;
+}
+
+int getLeftSplit(hwc_context_t *ctx, const int& dpy) {
+ //Default even split for all displays with high res
+ int lSplit = ctx->dpyAttr[dpy].xres / 2;
+ if(dpy == HWC_DISPLAY_PRIMARY &&
+ qdutils::MDPVersion::getInstance().getLeftSplit()) {
+ //Override if split published by driver for primary
+ lSplit = qdutils::MDPVersion::getInstance().getLeftSplit();
+ }
+ return lSplit;
+}
+
+bool isDisplaySplit(hwc_context_t* ctx, int dpy) {
+ qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance();
+ if(ctx->dpyAttr[dpy].xres > mdpHw.getMaxMixerWidth()) {
+ return true;
+ }
+ //For testing we could split primary via device tree values
+ if(dpy == HWC_DISPLAY_PRIMARY && mdpHw.getRightSplit()) {
+ return true;
+ }
+ return false;
+}
+
+//clear prev layer prop flags and realloc for current frame
+void reset_layer_prop(hwc_context_t* ctx, int dpy, int numAppLayers) {
+ if(ctx->layerProp[dpy]) {
+ delete[] ctx->layerProp[dpy];
+ ctx->layerProp[dpy] = NULL;
+ }
+ ctx->layerProp[dpy] = new LayerProp[numAppLayers];
+}
+
+bool isAbcInUse(hwc_context_t *ctx){
+ return (ctx->enableABC && ctx->listStats[0].renderBufIndexforABC == 0);
+}
+
+void dumpBuffer(private_handle_t *ohnd, char *bufferName) {
+ if (ohnd != NULL && ohnd->base) {
+ char dumpFilename[PATH_MAX];
+ bool bResult = false;
+ int width = getWidth(ohnd);
+ int height = getHeight(ohnd);
+ int format = ohnd->format;
+ //dummy aligned w & h.
+ int alW = 0, alH = 0;
+ int size = getBufferSizeAndDimensions(width, height, format, alW, alH);
+ snprintf(dumpFilename, sizeof(dumpFilename), "/data/%s.%s.%dx%d.raw",
+ bufferName,
+ overlay::utils::getFormatString(utils::getMdpFormat(format)),
+ width, height);
+ FILE* fp = fopen(dumpFilename, "w+");
+ if (NULL != fp) {
+ bResult = (bool) fwrite((void*)ohnd->base, size, 1, fp);
+ fclose(fp);
+ }
+ ALOGD("Buffer[%s] Dump to %s: %s",
+ bufferName, dumpFilename, bResult ? "Success" : "Fail");
+ }
+}
+
+bool isGLESComp(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+ int numAppLayers = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers;
+ for(int index = 0; index < numAppLayers; index++) {
+ hwc_layer_1_t* layer = &(list->hwLayers[index]);
+ if(layer->compositionType == HWC_FRAMEBUFFER)
+ return true;
+ }
+ return false;
+}
+
+void setGPUHint(hwc_context_t* ctx, hwc_display_contents_1_t* list) {
+#ifdef QTI_BSP
+ struct gpu_hint_info *gpuHint = &ctx->mGPUHintInfo;
+ if(!gpuHint->mGpuPerfModeEnable || !ctx || !list)
+ return;
+
+ /* Set the GPU hint flag to high for MIXED/GPU composition only for
+ first frame after MDP -> GPU/MIXED mode transition. Set the GPU
+ hint to default if the previous composition is GPU or current GPU
+ composition is due to idle fallback */
+ if(!gpuHint->mEGLDisplay || !gpuHint->mEGLContext) {
+ gpuHint->mEGLDisplay = (*(ctx->mpfn_eglGetCurrentDisplay))();
+ if(!gpuHint->mEGLDisplay) {
+ ALOGW("%s Warning: EGL current display is NULL", __FUNCTION__);
+ return;
+ }
+ gpuHint->mEGLContext = (*(ctx->mpfn_eglGetCurrentContext))();
+ if(!gpuHint->mEGLContext) {
+ ALOGW("%s Warning: EGL current context is NULL", __FUNCTION__);
+ return;
+ }
+ }
+ if(isGLESComp(ctx, list)) {
+ if(gpuHint->mCompositionState != COMPOSITION_STATE_GPU
+ && !MDPComp::isIdleFallback()) {
+ EGLint attr_list[] = {EGL_GPU_HINT_1,
+ EGL_GPU_LEVEL_3,
+ EGL_NONE };
+ if((gpuHint->mCurrGPUPerfMode != EGL_GPU_LEVEL_3) &&
+ !((*(ctx->mpfn_eglGpuPerfHintQCOM))(gpuHint->mEGLDisplay,
+ gpuHint->mEGLContext, attr_list))) {
+ ALOGW("eglGpuPerfHintQCOM failed for Built in display");
+ } else {
+ gpuHint->mCurrGPUPerfMode = EGL_GPU_LEVEL_3;
+ gpuHint->mCompositionState = COMPOSITION_STATE_GPU;
+ }
+ } else {
+ EGLint attr_list[] = {EGL_GPU_HINT_1,
+ EGL_GPU_LEVEL_0,
+ EGL_NONE };
+ if((gpuHint->mCurrGPUPerfMode != EGL_GPU_LEVEL_0) &&
+ !((*(ctx->mpfn_eglGpuPerfHintQCOM))(gpuHint->mEGLDisplay,
+ gpuHint->mEGLContext, attr_list))) {
+ ALOGW("eglGpuPerfHintQCOM failed for Built in display");
+ } else {
+ gpuHint->mCurrGPUPerfMode = EGL_GPU_LEVEL_0;
+ }
+ if(MDPComp::isIdleFallback()) {
+ gpuHint->mCompositionState = COMPOSITION_STATE_IDLE_FALLBACK;
+ }
+ }
+ } else {
+ /* set the GPU hint flag to default for MDP composition */
+ EGLint attr_list[] = {EGL_GPU_HINT_1,
+ EGL_GPU_LEVEL_0,
+ EGL_NONE };
+ if((gpuHint->mCurrGPUPerfMode != EGL_GPU_LEVEL_0) &&
+ !((*(ctx->mpfn_eglGpuPerfHintQCOM))(gpuHint->mEGLDisplay,
+ gpuHint->mEGLContext, attr_list))) {
+ ALOGW("eglGpuPerfHintQCOM failed for Built in display");
+ } else {
+ gpuHint->mCurrGPUPerfMode = EGL_GPU_LEVEL_0;
+ }
+ gpuHint->mCompositionState = COMPOSITION_STATE_MDP;
+ }
+#endif
+}
+
+bool isPeripheral(const hwc_rect_t& rect1, const hwc_rect_t& rect2) {
+ // To be peripheral, 3 boundaries should match.
+ uint8_t eqBounds = 0;
+ if (rect1.left == rect2.left)
+ eqBounds++;
+ if (rect1.top == rect2.top)
+ eqBounds++;
+ if (rect1.right == rect2.right)
+ eqBounds++;
+ if (rect1.bottom == rect2.bottom)
+ eqBounds++;
+ return (eqBounds == 3);
+}
+
+void processBootAnimCompleted(hwc_context_t *ctx) {
+ char value[PROPERTY_VALUE_MAX];
+ int ret = -1;
+
+ // Applying default mode after bootanimation is finished
+ property_get("init.svc.bootanim", value, "running");
+
+ if (!strncmp(value,"stopped",strlen("stopped"))) {
+ ctx->mBootAnimCompleted = true;
+
+ //one-shot action check if bootanimation completed then apply
+ //default display mode.
+ qdcmApplyDefaultAfterBootAnimationDone(ctx);
+ }
+}
+
+void BwcPM::setBwc(const hwc_rect_t& crop, const hwc_rect_t& dst,
+ const int& transform,const int& downscale,
+ ovutils::eMdpFlags& mdpFlags) {
+ //BWC not supported with rot-downscale
+ if(downscale) return;
+
+ //Target doesnt support Bwc
+ qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance();
+ if(!mdpHw.supportsBWC()) {
+ return;
+ }
+ int src_w = crop.right - crop.left;
+ int src_h = crop.bottom - crop.top;
+ int dst_w = dst.right - dst.left;
+ int dst_h = dst.bottom - dst.top;
+ if(transform & HAL_TRANSFORM_ROT_90) {
+ swap(src_w, src_h);
+ }
+ //src width > MAX mixer supported dim
+ if(src_w > (int) qdutils::MDPVersion::getInstance().getMaxMixerWidth()) {
+ return;
+ }
+ //Decimation necessary, cannot use BWC. H/W requirement.
+ if(qdutils::MDPVersion::getInstance().supportsDecimation()) {
+ uint8_t horzDeci = 0;
+ uint8_t vertDeci = 0;
+ ovutils::getDecimationFactor(src_w, src_h, dst_w, dst_h, horzDeci,
+ vertDeci);
+ if(horzDeci || vertDeci) return;
+ }
+ //Property
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.disable.bwc", value, "0");
+ if(atoi(value)) return;
+
+ ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDSS_MDP_BWC_EN);
+}
+
+void LayerRotMap::add(hwc_layer_1_t* layer, Rotator *rot) {
+ if(mCount >= RotMgr::MAX_ROT_SESS) return;
+ mLayer[mCount] = layer;
+ mRot[mCount] = rot;
+ mCount++;
+}
+
+void LayerRotMap::reset() {
+ for (int i = 0; i < RotMgr::MAX_ROT_SESS; i++) {
+ mLayer[i] = 0;
+ mRot[i] = 0;
+ }
+ mCount = 0;
+}
+
+void LayerRotMap::clear() {
+ RotMgr::getInstance()->markUnusedTop(mCount);
+ reset();
+}
+
+bool LayerRotMap::isRotCached(uint32_t index) const {
+ overlay::Rotator* rot = getRot(index);
+ hwc_layer_1_t* layer = getLayer(index);
+
+ if(rot and layer and layer->handle) {
+ private_handle_t *hnd = (private_handle_t *)(layer->handle);
+ return (rot->isRotCached(hnd->fd,(uint32_t)(hnd->offset)));
+ }
+ return false;
+}
+
+void LayerRotMap::setReleaseFd(const int& fence) {
+ for(uint32_t i = 0; i < mCount; i++) {
+ if(mRot[i] and mLayer[i] and mLayer[i]->handle) {
+ /* Ensure that none of the above (Rotator-instance,
+ * layer and layer-handle) are NULL*/
+ if(isRotCached(i))
+ mRot[i]->setPrevBufReleaseFd(dup(fence));
+ else
+ mRot[i]->setCurrBufReleaseFd(dup(fence));
+ }
+ }
+}
+
+void resetROI(hwc_context_t *ctx, const int dpy) {
+ const int fbXRes = (int)ctx->dpyAttr[dpy].xres;
+ const int fbYRes = (int)ctx->dpyAttr[dpy].yres;
+ if(isDisplaySplit(ctx, dpy)) {
+ const int lSplit = getLeftSplit(ctx, dpy);
+ ctx->listStats[dpy].lRoi = (struct hwc_rect){0, 0, lSplit, fbYRes};
+ ctx->listStats[dpy].rRoi = (struct hwc_rect){lSplit, 0, fbXRes, fbYRes};
+ } else {
+ ctx->listStats[dpy].lRoi = (struct hwc_rect){0, 0,fbXRes, fbYRes};
+ ctx->listStats[dpy].rRoi = (struct hwc_rect){0, 0, 0, 0};
+ }
+}
+
+hwc_rect_t getSanitizeROI(struct hwc_rect roi, hwc_rect boundary)
+{
+ if(!isValidRect(roi))
+ return roi;
+
+ struct hwc_rect t_roi = roi;
+
+ const int LEFT_ALIGN = qdutils::MDPVersion::getInstance().getLeftAlign();
+ const int WIDTH_ALIGN = qdutils::MDPVersion::getInstance().getWidthAlign();
+ const int TOP_ALIGN = qdutils::MDPVersion::getInstance().getTopAlign();
+ const int HEIGHT_ALIGN = qdutils::MDPVersion::getInstance().getHeightAlign();
+ const int MIN_WIDTH = qdutils::MDPVersion::getInstance().getMinROIWidth();
+ const int MIN_HEIGHT = qdutils::MDPVersion::getInstance().getMinROIHeight();
+
+ /* Align to minimum width recommended by the panel */
+ if((t_roi.right - t_roi.left) < MIN_WIDTH) {
+ if((t_roi.left + MIN_WIDTH) > boundary.right)
+ t_roi.left = t_roi.right - MIN_WIDTH;
+ else
+ t_roi.right = t_roi.left + MIN_WIDTH;
+ }
+
+ /* Align to minimum height recommended by the panel */
+ if((t_roi.bottom - t_roi.top) < MIN_HEIGHT) {
+ if((t_roi.top + MIN_HEIGHT) > boundary.bottom)
+ t_roi.top = t_roi.bottom - MIN_HEIGHT;
+ else
+ t_roi.bottom = t_roi.top + MIN_HEIGHT;
+ }
+
+ /* Align left and width to meet panel restrictions */
+ if(LEFT_ALIGN)
+ t_roi.left = t_roi.left - (t_roi.left % LEFT_ALIGN);
+
+ if(WIDTH_ALIGN) {
+ int width = t_roi.right - t_roi.left;
+ width = WIDTH_ALIGN * ((width + (WIDTH_ALIGN - 1)) / WIDTH_ALIGN);
+ t_roi.right = t_roi.left + width;
+
+ if(t_roi.right > boundary.right) {
+ t_roi.right = boundary.right;
+ t_roi.left = t_roi.right - width;
+
+ if(LEFT_ALIGN)
+ t_roi.left = t_roi.left - (t_roi.left % LEFT_ALIGN);
+ }
+ }
+
+
+ /* Align top and height to meet panel restrictions */
+ if(TOP_ALIGN)
+ t_roi.top = t_roi.top - (t_roi.top % TOP_ALIGN);
+
+ if(HEIGHT_ALIGN) {
+ int height = t_roi.bottom - t_roi.top;
+ height = HEIGHT_ALIGN * ((height + (HEIGHT_ALIGN - 1)) / HEIGHT_ALIGN);
+ t_roi.bottom = t_roi.top + height;
+
+ if(t_roi.bottom > boundary.bottom) {
+ t_roi.bottom = boundary.bottom;
+ t_roi.top = t_roi.bottom - height;
+
+ if(TOP_ALIGN)
+ t_roi.top = t_roi.top - (t_roi.top % TOP_ALIGN);
+ }
+ }
+
+
+ return t_roi;
+}
+
+void handle_pause(hwc_context_t* ctx, int dpy) {
+ if(ctx->dpyAttr[dpy].connected) {
+ ctx->mDrawLock.lock();
+ ctx->dpyAttr[dpy].isActive = true;
+ ctx->dpyAttr[dpy].isPause = true;
+ ctx->mDrawLock.unlock();
+ ctx->proc->invalidate(ctx->proc);
+
+ usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+ * 2 / 1000);
+
+ // At this point all the pipes used by External have been
+ // marked as UNSET.
+ ctx->mDrawLock.lock();
+ // Perform commit to unstage the pipes.
+ if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ ALOGE("%s: display commit fail! for %d dpy",
+ __FUNCTION__, dpy);
+ }
+ ctx->mDrawLock.unlock();
+ ctx->proc->invalidate(ctx->proc);
+ }
+ return;
+}
+
+void handle_resume(hwc_context_t* ctx, int dpy) {
+ if(ctx->dpyAttr[dpy].connected) {
+ ctx->mDrawLock.lock();
+ ctx->dpyAttr[dpy].isConfiguring = true;
+ ctx->dpyAttr[dpy].isActive = true;
+ ctx->mDrawLock.unlock();
+ ctx->proc->invalidate(ctx->proc);
+
+ usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+ * 2 / 1000);
+
+ //At this point external has all the pipes it would need.
+ ctx->mDrawLock.lock();
+ ctx->dpyAttr[dpy].isPause = false;
+ ctx->mDrawLock.unlock();
+ ctx->proc->invalidate(ctx->proc);
+ }
+ return;
+}
+
+void clearPipeResources(hwc_context_t* ctx, int dpy) {
+ if(ctx->mOverlay) {
+ ctx->mOverlay->configBegin();
+ ctx->mOverlay->configDone();
+ }
+ if(ctx->mRotMgr) {
+ ctx->mRotMgr->clear();
+ }
+ // Call a display commit to ensure that pipes and associated
+ // fd's are cleaned up.
+ if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ ALOGE("%s: display commit failed for %d", __FUNCTION__, dpy);
+ }
+}
+
+// Handles online events when HDMI is the primary display. In particular,
+// online events for hdmi connected before AND after boot up and HWC init.
+void handle_online(hwc_context_t* ctx, int dpy) {
+ // Close the current fd if it was opened earlier on when HWC
+ // was initialized.
+ if (ctx->dpyAttr[dpy].fd >= 0) {
+ close(ctx->dpyAttr[dpy].fd);
+ ctx->dpyAttr[dpy].fd = -1;
+ }
+ // TODO: If HDMI is connected after the display has booted up,
+ // and the best configuration is different from the default
+ // then we need to deal with this appropriately.
+ ctx->mHDMIDisplay->configure();
+ updateDisplayInfo(ctx, dpy);
+ initCompositionResources(ctx, dpy);
+ ctx->dpyAttr[dpy].connected = true;
+}
+
+// Handles offline events for HDMI. This can be used for offline events
+// initiated by the HDMI driver and the CEC framework.
+void handle_offline(hwc_context_t* ctx, int dpy) {
+ destroyCompositionResources(ctx, dpy);
+ // Clear all pipe resources and call a display commit to ensure
+ // that all the fd's are closed. This will ensure that the HDMI
+ // core turns off and that we receive an event the next time the
+ // cable is connected.
+ if (ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) {
+ clearPipeResources(ctx, dpy);
+ }
+ ctx->mHDMIDisplay->teardown();
+ resetDisplayInfo(ctx, dpy);
+ ctx->dpyAttr[dpy].connected = false;
+ ctx->dpyAttr[dpy].isActive = false;
+}
+
+bool loadEglLib(hwc_context_t* ctx) {
+ bool success = false;
+#ifdef QTI_BSP
+ const char* error;
+ dlerror();
+
+ ctx->mEglLib = dlopen("libEGL_adreno.so", RTLD_NOW);
+ if(ctx->mEglLib) {
+ *(void **)&(ctx->mpfn_eglGpuPerfHintQCOM) = dlsym(ctx->mEglLib, "eglGpuPerfHintQCOM");
+ *(void **)&(ctx->mpfn_eglGetCurrentDisplay) = dlsym(ctx->mEglLib,"eglGetCurrentDisplay");
+ *(void **)&(ctx->mpfn_eglGetCurrentContext) = dlsym(ctx->mEglLib,"eglGetCurrentContext");
+ if (!ctx->mpfn_eglGpuPerfHintQCOM ||
+ !ctx->mpfn_eglGetCurrentDisplay ||
+ !ctx->mpfn_eglGetCurrentContext) {
+ ALOGE("Failed to load symbols from libEGL");
+ dlclose(ctx->mEglLib);
+ ctx->mEglLib = NULL;
+ return false;
+ }
+ success = true;
+ ALOGI("Successfully Loaded GPUPerfHint APIs");
+ } else {
+ ALOGE("Couldn't load libEGL: %s", dlerror());
+ }
+#endif
+ return success;
+}
+
+};//namespace qhwc
diff --git a/msm8909/libhwcomposer/hwc_utils.h b/msm8909/libhwcomposer/hwc_utils.h
new file mode 100644
index 0000000..235681a
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_utils.h
@@ -0,0 +1,718 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C)2012-2015, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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
+
+#define DEBUG_MDPDOWNSCALE 0
+#define HWC_REMOVE_DEPRECATED_VERSIONS 1
+
+#include <fcntl.h>
+#include <math.h>
+#include <hardware/hwcomposer.h>
+#include <gr.h>
+#include <gralloc_priv.h>
+#include <utils/String8.h>
+#include "qdMetaData.h"
+#include "mdp_version.h"
+#include <overlayUtils.h>
+#include <overlayRotator.h>
+#include <EGL/egl.h>
+
+
+#define ALIGN_TO(x, align) (((x) + ((align)-1)) & ~((align)-1))
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+#define MAX_NUM_APP_LAYERS 32
+#define MIN_DISPLAY_XRES 200
+#define MIN_DISPLAY_YRES 200
+#define HWC_WFDDISPSYNC_LOG 0
+#define STR(f) #f;
+// Max number of PTOR layers handled
+#define MAX_PTOR_LAYERS 2
+
+#ifdef QTI_BSP
+#include <exhwcomposer_defs.h>
+#endif
+
+//Fwrd decls
+struct hwc_context_t;
+
+namespace ovutils = overlay::utils;
+
+namespace qmode {
+class ModeManager;
+}
+
+namespace overlay {
+class Overlay;
+class Rotator;
+class RotMgr;
+}
+
+namespace qhwc {
+//fwrd decl
+class QueuedBufferStore;
+class HDMIDisplay;
+class VirtualDisplay;
+class IFBUpdate;
+class IVideoOverlay;
+class MDPComp;
+class CopyBit;
+class HwcDebug;
+class AssertiveDisplay;
+class HWCVirtualVDS;
+
+
+struct MDPInfo {
+ int version;
+ char panel;
+ bool hasOverlay;
+};
+
+struct DisplayAttributes {
+ uint32_t refreshRate;
+ uint32_t dynRefreshRate;
+ uint32_t vsync_period; //nanos
+ uint32_t xres;
+ uint32_t yres;
+ uint32_t stride;
+ float xdpi;
+ float ydpi;
+ uint32_t fbformat;
+ int fd;
+ bool connected; //Applies only to pluggable disp.
+ //Connected does not mean it ready to use.
+ //It should be active also. (UNBLANKED)
+ bool isActive;
+ // In pause state, composition is bypassed
+ // used for WFD displays and in QDCM calibration mode
+ bool isPause;
+ // To trigger padding round to clean up mdp
+ // pipes
+ bool isConfiguring;
+ // Indicates whether external/virtual display is in MDP scaling mode
+ bool mMDPScalingMode;
+ // Ext dst Rect
+ hwc_rect_t mDstRect;
+ //Action safe attributes
+ // Flag to indicate the presence of action safe dimensions for external
+ bool mActionSafePresent;
+ int mAsWidthRatio;
+ int mAsHeightRatio;
+
+ //If property fbsize set via adb shell debug.hwc.fbsize = XRESxYRES
+ //following fields are used.
+ bool customFBSize;
+ uint32_t xres_new;
+ uint32_t yres_new;
+
+};
+
+struct ListStats {
+ int numAppLayers; //Total - 1, excluding FB layer.
+ int skipCount;
+ int fbLayerIndex; //Always last for now. = numAppLayers
+ //Video specific
+ int yuvCount;
+ int yuvIndices[MAX_NUM_APP_LAYERS];
+ bool preMultipliedAlpha;
+ int yuv4k2kIndices[MAX_NUM_APP_LAYERS];
+ int yuv4k2kCount;
+ // Notifies hwcomposer about the start and end of animation
+ // This will be set to true during animation, otherwise false.
+ bool isDisplayAnimating;
+ bool secureUI; // Secure display layer
+ bool isSecurePresent;
+ hwc_rect_t lRoi; //left ROI
+ hwc_rect_t rRoi; //right ROI. Unused in single DSI panels.
+ //App Buffer Composition index
+ int renderBufIndexforABC;
+ // Secure RGB specific
+ int secureRGBCount;
+ int secureRGBIndices[MAX_NUM_APP_LAYERS];
+ //dyn refresh rate-Client requested refreshrate
+ uint32_t refreshRateRequest;
+ // Flag related to windowboxing feature
+ bool mAIVVideoMode;
+};
+
+//PTOR Comp info
+struct PtorInfo {
+ int count;
+ int layerIndex[MAX_PTOR_LAYERS];
+ hwc_rect_t displayFrame[MAX_PTOR_LAYERS];
+ bool isActive() { return (count>0); }
+ int getPTORArrayIndex(int index) {
+ int idx = -1;
+ for(int i = 0; i < count; i++) {
+ if(index == layerIndex[i])
+ idx = i;
+ }
+ return idx;
+ }
+};
+
+struct LayerProp {
+ uint32_t mFlags; //qcom specific layer flags
+ LayerProp():mFlags(0){};
+};
+
+struct VsyncState {
+ bool enable;
+ bool fakevsync;
+ bool debug;
+};
+
+struct BwcPM {
+ static void setBwc(const hwc_rect_t& crop, const hwc_rect_t& dst,
+ const int& transform, const int& downscale,
+ ovutils::eMdpFlags& mdpFlags);
+};
+
+// LayerProp::flag values
+enum {
+ HWC_MDPCOMP = 0x00000001,
+ HWC_COPYBIT = 0x00000002,
+};
+
+// AIV specific flags
+enum {
+ HWC_AIV_VIDEO = 0x80000000,
+ HWC_AIV_CC = 0x40000000,
+};
+
+// HAL specific features
+enum {
+ HWC_COLOR_FILL = 0x00000008,
+ HWC_FORMAT_RB_SWAP = 0x00000040,
+};
+
+/* External Display states */
+enum {
+ EXTERNAL_OFFLINE = 0,
+ EXTERNAL_ONLINE,
+ EXTERNAL_PAUSE,
+ EXTERNAL_RESUME,
+ EXTERNAL_MAXSTATES
+};
+
+class LayerRotMap {
+public:
+ LayerRotMap() { reset(); }
+ void add(hwc_layer_1_t* layer, overlay::Rotator *rot);
+ //Resets the mapping of layer to rotator
+ void reset();
+ //Clears mappings and existing rotator fences
+ //Intended to be used during errors
+ void clear();
+ uint32_t getCount() const;
+ hwc_layer_1_t* getLayer(uint32_t index) const;
+ overlay::Rotator* getRot(uint32_t index) const;
+ bool isRotCached(uint32_t index) const;
+ void setReleaseFd(const int& fence);
+private:
+ hwc_layer_1_t* mLayer[overlay::RotMgr::MAX_ROT_SESS];
+ overlay::Rotator* mRot[overlay::RotMgr::MAX_ROT_SESS];
+ uint32_t mCount;
+};
+
+inline uint32_t LayerRotMap::getCount() const {
+ return mCount;
+}
+
+inline hwc_layer_1_t* LayerRotMap::getLayer(uint32_t index) const {
+ if(index >= mCount) return NULL;
+ return mLayer[index];
+}
+
+inline overlay::Rotator* LayerRotMap::getRot(uint32_t index) const {
+ if(index >= mCount) return NULL;
+ return mRot[index];
+}
+
+inline hwc_rect_t integerizeSourceCrop(const hwc_frect_t& cropF) {
+ hwc_rect_t cropI = {0,0,0,0};
+ cropI.left = int(ceilf(cropF.left));
+ cropI.top = int(ceilf(cropF.top));
+ cropI.right = int(floorf(cropF.right));
+ cropI.bottom = int(floorf(cropF.bottom));
+ return cropI;
+}
+
+inline bool isNonIntegralSourceCrop(const hwc_frect_t& cropF) {
+ if(cropF.left - roundf(cropF.left) ||
+ cropF.top - roundf(cropF.top) ||
+ cropF.right - roundf(cropF.right) ||
+ cropF.bottom - roundf(cropF.bottom))
+ return true;
+ else
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+// Utility functions - implemented in hwc_utils.cpp
+void dumpLayer(hwc_layer_1_t const* l);
+void setListStats(hwc_context_t *ctx, hwc_display_contents_1_t *list,
+ int dpy);
+void initContext(hwc_context_t *ctx);
+void closeContext(hwc_context_t *ctx);
+//Crops source buffer against destination and FB boundaries
+void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst,
+ const hwc_rect_t& scissor, int orient);
+void getNonWormholeRegion(hwc_display_contents_1_t* list,
+ hwc_rect_t& nwr);
+bool isSecuring(hwc_context_t* ctx, hwc_layer_1_t const* layer);
+bool isSecureModePolicy(int mdpVersion);
+// Returns true, if the input layer format is supported by rotator
+bool isRotatorSupportedFormat(private_handle_t *hnd);
+//Returns true, if the layer is YUV or the layer has been rendered by CPU
+bool isRotationDoable(hwc_context_t *ctx, private_handle_t *hnd);
+bool isExternalActive(hwc_context_t* ctx);
+bool isAlphaScaled(hwc_layer_1_t const* layer);
+bool needsScaling(hwc_layer_1_t const* layer);
+bool isDownscaleRequired(hwc_layer_1_t const* layer);
+bool needsScalingWithSplit(hwc_context_t* ctx, hwc_layer_1_t const* layer,
+ const int& dpy);
+void sanitizeSourceCrop(hwc_rect_t& cropL, hwc_rect_t& cropR,
+ private_handle_t *hnd);
+bool isAlphaPresent(hwc_layer_1_t const* layer);
+bool isAlphaPresentinFB(hwc_context_t* ctx, int dpy);
+int hwc_vsync_control(hwc_context_t* ctx, int dpy, int enable);
+int getBlending(int blending);
+bool isGLESOnlyComp(hwc_context_t *ctx, const int& dpy);
+void reset_layer_prop(hwc_context_t* ctx, int dpy, int numAppLayers);
+bool isAbcInUse(hwc_context_t *ctx);
+
+void dumpBuffer(private_handle_t *ohnd, char *bufferName);
+void updateDisplayInfo(hwc_context_t* ctx, int dpy);
+void resetDisplayInfo(hwc_context_t* ctx, int dpy);
+void initCompositionResources(hwc_context_t* ctx, int dpy);
+void destroyCompositionResources(hwc_context_t* ctx, int dpy);
+void clearPipeResources(hwc_context_t* ctx, int dpy);
+
+//Helper function to dump logs
+void dumpsys_log(android::String8& buf, const char* fmt, ...);
+
+int getExtOrientation(hwc_context_t* ctx);
+bool isValidRect(const hwc_rect_t& rect);
+hwc_rect_t deductRect(const hwc_rect_t& rect1, const hwc_rect_t& rect2);
+bool isSameRect(const hwc_rect& rect1, const hwc_rect& rect2);
+hwc_rect_t moveRect(const hwc_rect_t& rect, const int& x_off, const int& y_off);
+hwc_rect_t getIntersection(const hwc_rect_t& rect1, const hwc_rect_t& rect2);
+hwc_rect_t getUnion(const hwc_rect_t& rect1, const hwc_rect_t& rect2);
+void optimizeLayerRects(const hwc_display_contents_1_t *list);
+bool areLayersIntersecting(const hwc_layer_1_t* layer1,
+ const hwc_layer_1_t* layer2);
+bool operator ==(const hwc_rect_t& lhs, const hwc_rect_t& rhs);
+bool layerUpdating(const hwc_layer_1_t* layer);
+/* Calculates the dirtyRegion for the given layer */
+hwc_rect_t calculateDirtyRect(const hwc_layer_1_t* layer,
+ hwc_rect_t& scissor);
+
+
+// returns true if Action safe dimensions are set and target supports Actionsafe
+bool isActionSafePresent(hwc_context_t *ctx, int dpy);
+
+/* Calculates the destination position based on the action safe rectangle */
+void getActionSafePosition(hwc_context_t *ctx, int dpy, hwc_rect_t& dst);
+
+void getAspectRatioPosition(hwc_context_t* ctx, int dpy, int extOrientation,
+ hwc_rect_t& inRect, hwc_rect_t& outRect);
+
+uint32_t getRefreshRate(hwc_context_t* ctx, uint32_t requestedRefreshRate);
+
+uint32_t roundOff(uint32_t refreshRate);
+
+void setRefreshRate(hwc_context_t *ctx, int dpy, uint32_t refreshRate);
+
+bool isPrimaryPortrait(hwc_context_t *ctx);
+
+bool isOrientationPortrait(hwc_context_t *ctx);
+
+void calcExtDisplayPosition(hwc_context_t *ctx,
+ private_handle_t *hnd,
+ int dpy,
+ hwc_rect_t& sourceCrop,
+ hwc_rect_t& displayFrame,
+ int& transform,
+ ovutils::eTransform& orient);
+
+// Returns the orientation that needs to be set on external for
+// BufferMirrirMode(Sidesync)
+int getMirrorModeOrientation(hwc_context_t *ctx);
+
+/* Get External State names */
+const char* getExternalDisplayState(uint32_t external_state);
+
+// Resets display ROI to full panel resoluion
+void resetROI(hwc_context_t *ctx, const int dpy);
+
+// Aligns updating ROI to panel restrictions
+hwc_rect_t getSanitizeROI(struct hwc_rect roi, hwc_rect boundary);
+
+// Handles wfd Pause and resume events
+void handle_pause(hwc_context_t *ctx, int dpy);
+void handle_resume(hwc_context_t *ctx, int dpy);
+
+// Handle ONLINE/OFFLINE for HDMI display
+void handle_online(hwc_context_t* ctx, int dpy);
+void handle_offline(hwc_context_t* ctx, int dpy);
+
+//Close acquireFenceFds of all layers of incoming list
+void closeAcquireFds(hwc_display_contents_1_t* list);
+
+//Sync point impl.
+int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy,
+ int fd);
+
+//Sets appropriate mdp flags for a layer.
+void setMdpFlags(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ ovutils::eMdpFlags &mdpFlags,
+ int rotDownscale, int transform);
+
+int configRotator(overlay::Rotator *rot, ovutils::Whf& whf,
+ hwc_rect_t& crop, const ovutils::eMdpFlags& mdpFlags,
+ const ovutils::eTransform& orient, const int& downscale);
+
+int configMdp(overlay::Overlay *ov, const ovutils::PipeArgs& parg,
+ const ovutils::eTransform& orient, const hwc_rect_t& crop,
+ const hwc_rect_t& pos, const MetaData_t *metadata,
+ const ovutils::eDest& dest);
+
+int configColorLayer(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
+ ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
+ const ovutils::eDest& dest);
+
+void updateSource(ovutils::eTransform& orient, ovutils::Whf& whf,
+ hwc_rect_t& crop, overlay::Rotator *rot);
+
+bool isZoomModeEnabled(hwc_rect_t crop);
+void updateCropAIVVideoMode(hwc_context_t *ctx, hwc_rect_t& crop, int dpy);
+void updateDestAIVVideoMode(hwc_context_t *ctx, hwc_rect_t& dst, int dpy);
+void updateCoordinates(hwc_context_t *ctx, hwc_rect_t& crop,
+ hwc_rect_t& dst, int dpy);
+
+//Routine to configure low resolution panels (<= 2048 width)
+int configureNonSplit(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
+ ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
+ const ovutils::eDest& dest,
+ overlay::Rotator **rot);
+
+//Routine to configure high resolution panels (> 2048 width)
+int configureSplit(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
+ ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
+ const ovutils::eDest& lDest,
+ const ovutils::eDest& rDest, overlay::Rotator **rot);
+
+//Routine to split and configure high resolution YUV layer (> 2048 width)
+int configureSourceSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
+ const int& dpy,
+ ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
+ const ovutils::eDest& lDest,
+ const ovutils::eDest& rDest, overlay::Rotator **rot);
+
+//On certain targets DMA pipes are used for rotation and they won't be available
+//for line operations. On a per-target basis we can restrict certain use cases
+//from using rotator, since we know before-hand that such scenarios can lead to
+//extreme unavailability of pipes. This can also be done via hybrid calculations
+//also involving many more variables like number of write-back interfaces etc,
+//but the variety of scenarios is too high to warrant that.
+bool canUseRotator(hwc_context_t *ctx, int dpy);
+
+int getLeftSplit(hwc_context_t *ctx, const int& dpy);
+
+bool isDisplaySplit(hwc_context_t* ctx, int dpy);
+
+int getRotDownscale(hwc_context_t *ctx, const hwc_layer_1_t *layer);
+
+// Set the GPU hint flag to high for MIXED/GPU composition only for
+// first frame after MDP to GPU/MIXED mode transition.
+// Set the GPU hint to default if the current composition type is GPU
+// due to idle fallback or MDP composition.
+void setGPUHint(hwc_context_t* ctx, hwc_display_contents_1_t* list);
+
+bool loadEglLib(hwc_context_t* ctx);
+
+// Returns true if rect1 is peripheral to rect2, false otherwise.
+bool isPeripheral(const hwc_rect_t& rect1, const hwc_rect_t& rect2);
+
+// Checks if boot animation has completed and applies default mode
+void processBootAnimCompleted(hwc_context_t *ctx);
+
+// Inline utility functions
+static inline bool isSkipLayer(const hwc_layer_1_t* l) {
+ return (UNLIKELY(l && (l->flags & HWC_SKIP_LAYER)));
+}
+
+static inline bool isAIVVideoLayer(const hwc_layer_1_t* l) {
+ return (UNLIKELY(l && (l->flags & HWC_AIV_VIDEO)));
+}
+
+static inline bool isAIVCCLayer(const hwc_layer_1_t* l) {
+ return (UNLIKELY(l && (l->flags & HWC_AIV_CC)));
+}
+
+// Returns true if the buffer is yuv
+static inline bool isYuvBuffer(const private_handle_t* hnd) {
+ return (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO));
+}
+
+// Returns true if the buffer is yuv and exceeds the mixer width
+static inline bool isYUVSplitNeeded(const private_handle_t* hnd) {
+ int maxMixerWidth = qdutils::MDPVersion::getInstance().getMaxMixerWidth();
+ return (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO) &&
+ (hnd->width > maxMixerWidth));
+}
+
+// Returns true if the buffer is secure
+static inline bool isSecureBuffer(const private_handle_t* hnd) {
+ return (hnd && (private_handle_t::PRIV_FLAGS_SECURE_BUFFER & hnd->flags));
+}
+
+static inline bool isTileRendered(const private_handle_t* hnd) {
+ return (hnd && (private_handle_t::PRIV_FLAGS_TILE_RENDERED & hnd->flags));
+}
+
+static inline bool isCPURendered(const private_handle_t* hnd) {
+ return (hnd && (private_handle_t::PRIV_FLAGS_CPU_RENDERED & hnd->flags));
+}
+
+//Return true if the buffer is intended for Secure Display
+static inline bool isSecureDisplayBuffer(const private_handle_t* hnd) {
+ return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY));
+}
+
+static inline int getWidth(const private_handle_t* hnd) {
+ MetaData_t *metadata = reinterpret_cast<MetaData_t*>(hnd->base_metadata);
+ if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) {
+ return metadata->bufferDim.sliceWidth;
+ }
+ return hnd->width;
+}
+
+static inline int getHeight(const private_handle_t* hnd) {
+ MetaData_t *metadata = reinterpret_cast<MetaData_t*>(hnd->base_metadata);
+ if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) {
+ return metadata->bufferDim.sliceHeight;
+ }
+ return hnd->height;
+}
+
+template<typename T> inline T max(T a, T b) { return (a > b) ? a : b; }
+template<typename T> inline T min(T a, T b) { return (a < b) ? a : b; }
+
+// Initialize uevent thread
+void init_uevent_thread(hwc_context_t* ctx);
+// Initialize vsync thread
+void init_vsync_thread(hwc_context_t* ctx);
+
+inline void getLayerResolution(const hwc_layer_1_t* layer,
+ int& width, int& height) {
+ hwc_rect_t displayFrame = layer->displayFrame;
+ width = displayFrame.right - displayFrame.left;
+ height = displayFrame.bottom - displayFrame.top;
+}
+
+static inline int openFb(int dpy) {
+ int fd = -1;
+ const char *devtmpl = "/dev/graphics/fb%u";
+ char name[64] = {0};
+ snprintf(name, 64, devtmpl, dpy);
+ fd = open(name, O_RDWR);
+ return fd;
+}
+
+template <class T>
+inline void swap(T& a, T& b) {
+ T tmp = a;
+ a = b;
+ b = tmp;
+}
+
+}; //qhwc namespace
+
+enum eAnimationState{
+ ANIMATION_STOPPED,
+ ANIMATION_STARTED,
+};
+
+enum eCompositionState {
+ COMPOSITION_STATE_MDP = 0, // Set if composition type is MDP
+ COMPOSITION_STATE_GPU, // Set if composition type is GPU or MIXED
+ COMPOSITION_STATE_IDLE_FALLBACK, // Set if it is idlefallback
+};
+
+// Structure holds the information about the GPU hint.
+struct gpu_hint_info {
+ // system level flag to enable gpu_perf_mode
+ bool mGpuPerfModeEnable;
+ // Stores the current GPU performance mode DEFAULT/HIGH
+ bool mCurrGPUPerfMode;
+ // Stores the compositon state GPU, MDP or IDLE_FALLBACK
+ bool mCompositionState;
+ // Stores the EGLContext of current process
+ EGLContext mEGLContext;
+ // Stores the EGLDisplay of current process
+ EGLDisplay mEGLDisplay;
+};
+
+//struct holds the information about libmm-qdcm.so
+struct qdcm_info {
+ qmode::ModeManager *mQdcmMode;
+ void *mQdcmLib;
+ bool mBootAnimCompleted;
+};
+
+// -----------------------------------------------------------------------------
+// HWC context
+// This structure contains overall state
+struct hwc_context_t {
+ hwc_composer_device_1_t device;
+ const hwc_procs_t* proc;
+
+ //CopyBit objects
+ qhwc::CopyBit *mCopyBit[HWC_NUM_DISPLAY_TYPES];
+
+ //Overlay object - NULL for non overlay devices
+ overlay::Overlay *mOverlay;
+ //Holds a few rot objects
+ overlay::RotMgr *mRotMgr;
+
+ //Primary and external FB updater
+ qhwc::IFBUpdate *mFBUpdate[HWC_NUM_DISPLAY_TYPES];
+ // HDMI display related object. Used to configure/teardown
+ // HDMI when it is connected as primary or external.
+ qhwc::HDMIDisplay *mHDMIDisplay;
+ qhwc::MDPInfo mMDP;
+ qhwc::VsyncState vstate;
+ qhwc::DisplayAttributes dpyAttr[HWC_NUM_DISPLAY_TYPES];
+ qhwc::ListStats listStats[HWC_NUM_DISPLAY_TYPES];
+ qhwc::LayerProp *layerProp[HWC_NUM_DISPLAY_TYPES];
+ qhwc::MDPComp *mMDPComp[HWC_NUM_DISPLAY_TYPES];
+ qhwc::HwcDebug *mHwcDebug[HWC_NUM_DISPLAY_TYPES];
+ hwc_rect_t mViewFrame[HWC_NUM_DISPLAY_TYPES];
+ qhwc::AssertiveDisplay *mAD;
+ eAnimationState mAnimationState[HWC_NUM_DISPLAY_TYPES];
+ qhwc::HWCVirtualVDS *mHWCVirtual;
+
+ // stores the #numHwLayers of the previous frame
+ // for each display device
+ int mPrevHwLayerCount[HWC_NUM_DISPLAY_TYPES];
+
+ // stores the primary device orientation
+ int deviceOrientation;
+ //Securing in progress indicator
+ bool mSecuring;
+ //Display in secure mode indicator
+ bool mSecureMode;
+ //Lock to protect drawing data structures
+ mutable Locker mDrawLock;
+ //Drawing round when we use GPU
+ bool isPaddingRound;
+ // External Orientation
+ int mExtOrientation;
+ //Flags the transition of a video session
+ bool mVideoTransFlag;
+ //Used for SideSync feature
+ //which overrides the mExtOrientation
+ bool mBufferMirrorMode;
+ // Used to synchronize between WFD and Display modules
+ mutable Locker mWfdSyncLock;
+
+ qhwc::LayerRotMap *mLayerRotMap[HWC_NUM_DISPLAY_TYPES];
+ // Panel reset flag will be set if BTA check fails
+ bool mPanelResetStatus;
+ // number of active Displays
+ int numActiveDisplays;
+#ifdef QTI_BSP
+ void *mEglLib;
+ EGLBoolean (*mpfn_eglGpuPerfHintQCOM)(EGLDisplay, EGLContext, EGLint *);
+ EGLDisplay (*mpfn_eglGetCurrentDisplay)();
+ EGLContext (*mpfn_eglGetCurrentContext)();
+ struct gpu_hint_info mGPUHintInfo;
+#endif
+ //App Buffer Composition
+ bool enableABC;
+ // PTOR Info
+ qhwc::PtorInfo mPtorInfo;
+ //Running in Thermal burst mode
+ bool mThermalBurstMode;
+ //Layers out of ROI
+ bool copybitDrop[MAX_NUM_APP_LAYERS];
+ // Flag related to windowboxing feature
+ bool mWindowboxFeature;
+ // This denotes the tolerance between video layer and external display
+ // aspect ratio
+ float mAspectRatioToleranceLevel;
+ //Used to notify that boot has completed
+ bool mBootAnimCompleted;
+ // Provides a way for OEM's to disable setting dynfps via metadata.
+ bool mUseMetaDataRefreshRate;
+ //struct holds the information about display tuning service library.
+ struct qdcm_info mQdcmInfo;
+};
+
+namespace qhwc {
+static inline bool isSkipPresent (hwc_context_t *ctx, int dpy) {
+ return ctx->listStats[dpy].skipCount;
+}
+
+static inline bool isYuvPresent (hwc_context_t *ctx, int dpy) {
+ return ctx->listStats[dpy].yuvCount;
+}
+
+static inline bool has90Transform(hwc_layer_1_t const* layer) {
+ return ((layer->transform & HWC_TRANSFORM_ROT_90) &&
+ !(layer->flags & HWC_COLOR_FILL));
+}
+
+inline bool isSecurePresent(hwc_context_t *ctx, int dpy) {
+ return ctx->listStats[dpy].isSecurePresent;
+}
+
+static inline bool isSecondaryConfiguring(hwc_context_t* ctx) {
+ return (ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isConfiguring ||
+ ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isConfiguring);
+}
+
+static inline bool isSecondaryConnected(hwc_context_t* ctx) {
+ return (ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected ||
+ ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected);
+}
+
+static inline bool isSecondaryAnimating(hwc_context_t* ctx) {
+ return (ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected &&
+ (!ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isPause) &&
+ ctx->listStats[HWC_DISPLAY_EXTERNAL].isDisplayAnimating)
+ ||
+ (ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected &&
+ (!ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isPause) &&
+ ctx->listStats[HWC_DISPLAY_VIRTUAL].isDisplayAnimating);
+}
+
+/* Return Virtual Display connection status */
+static inline bool isVDConnected(hwc_context_t* ctx) {
+ return ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected;
+}
+
+};
+
+#endif //HWC_UTILS_H
diff --git a/msm8909/libhwcomposer/hwc_virtual.cpp b/msm8909/libhwcomposer/hwc_virtual.cpp
new file mode 100644
index 0000000..2bfb5e7
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_virtual.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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 <fcntl.h>
+#include <errno.h>
+
+#include <cutils/log.h>
+#include <overlayWriteback.h>
+#include "hwc_utils.h"
+#include "hwc_fbupdate.h"
+#include "hwc_mdpcomp.h"
+#include "hwc_dump_layers.h"
+#include "hwc_copybit.h"
+#include "hwc_virtual.h"
+#include "sync/sync.h"
+#include <utils/Trace.h>
+
+#define HWCVIRTUAL_LOG 0
+
+using namespace qhwc;
+using namespace overlay;
+
+bool HWCVirtualVDS::sVDDumpEnabled = false;
+
+void HWCVirtualVDS::init(hwc_context_t *ctx) {
+ const int dpy = HWC_DISPLAY_VIRTUAL;
+ mScalingWidth = 0, mScalingHeight = 0;
+ initCompositionResources(ctx, dpy);
+
+ if(ctx->mFBUpdate[dpy])
+ ctx->mFBUpdate[dpy]->reset();
+ if(ctx->mMDPComp[dpy])
+ ctx->mMDPComp[dpy]->reset();
+}
+
+void HWCVirtualVDS::destroy(hwc_context_t *ctx, size_t /*numDisplays*/,
+ hwc_display_contents_1_t** displays) {
+ int dpy = HWC_DISPLAY_VIRTUAL;
+
+ //Cleanup virtual display objs, since there is no explicit disconnect
+ if(ctx->dpyAttr[dpy].connected && (displays[dpy] == NULL)) {
+ ctx->dpyAttr[dpy].connected = false;
+ ctx->dpyAttr[dpy].isPause = false;
+
+ destroyCompositionResources(ctx, dpy);
+
+ // signal synclock to indicate successful wfd teardown
+ ctx->mWfdSyncLock.lock();
+ ctx->mWfdSyncLock.signal();
+ ctx->mWfdSyncLock.unlock();
+ }
+}
+
+int HWCVirtualVDS::prepare(hwc_composer_device_1 *dev,
+ hwc_display_contents_1_t *list) {
+ ATRACE_CALL();
+ //XXX: Fix when framework support is added
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
+ const int dpy = HWC_DISPLAY_VIRTUAL;
+
+ if (list && list->outbuf && list->numHwLayers > 0) {
+ reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1);
+ uint32_t last = (uint32_t)list->numHwLayers - 1;
+ hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+ int fbWidth = 0, fbHeight = 0;
+ getLayerResolution(fbLayer, fbWidth, fbHeight);
+ ctx->dpyAttr[dpy].xres = fbWidth;
+ ctx->dpyAttr[dpy].yres = fbHeight;
+
+ if(ctx->dpyAttr[dpy].connected == false) {
+ ctx->dpyAttr[dpy].connected = true;
+ ctx->dpyAttr[dpy].isPause = false;
+ // We set the vsync period to the primary refresh rate, leaving
+ // it up to the consumer to decide how fast to consume frames.
+ ctx->dpyAttr[dpy].vsync_period
+ = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period;
+ ctx->dpyAttr[dpy].fbformat = HAL_PIXEL_FORMAT_RGBA_8888;
+ init(ctx);
+ // Do one padding round for cases where primary has all pipes
+ // The virtual composition falls back to GPU in such cases.
+ ctx->isPaddingRound = true;
+ }
+ if(!ctx->dpyAttr[dpy].isPause) {
+ ctx->dpyAttr[dpy].isConfiguring = false;
+ ctx->dpyAttr[dpy].fd = Writeback::getInstance()->getFbFd();
+ private_handle_t *ohnd = (private_handle_t *)list->outbuf;
+
+ setMDPScalingMode(ctx, ohnd, dpy);
+
+ mScalingWidth = getWidth(ohnd);
+ mScalingHeight = getHeight(ohnd);
+
+ Writeback::getInstance()->configureDpyInfo(mScalingWidth,
+ mScalingHeight);
+ setListStats(ctx, list, dpy);
+
+ if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
+ const int fbZ = 0;
+ if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ))
+ {
+ ctx->mOverlay->clear(dpy);
+ ctx->mLayerRotMap[dpy]->clear();
+ }
+ }
+ } else {
+ /* Virtual Display is in Pause state.
+ * Mark all application layers as OVERLAY so that
+ * GPU will not compose.
+ */
+ Writeback::getInstance(); //Ensure that WB is active during pause
+ for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
+ hwc_layer_1_t *layer = &list->hwLayers[i];
+ layer->compositionType = HWC_OVERLAY;
+ }
+ }
+ }
+ return 0;
+}
+
+int HWCVirtualVDS::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
+ ATRACE_CALL();
+ int ret = 0;
+ const int dpy = HWC_DISPLAY_VIRTUAL;
+
+ if (list && list->outbuf && list->numHwLayers > 0) {
+ uint32_t last = (uint32_t)list->numHwLayers - 1;
+ hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+
+ if(ctx->dpyAttr[dpy].connected
+ && (!ctx->dpyAttr[dpy].isPause))
+ {
+ private_handle_t *ohnd = (private_handle_t *)list->outbuf;
+ int format = ohnd->format;
+ if (format == HAL_PIXEL_FORMAT_RGBA_8888)
+ format = HAL_PIXEL_FORMAT_RGBX_8888;
+ Writeback::getInstance()->setOutputFormat(
+ utils::getMdpFormat(format));
+
+ // Configure WB secure mode based on output buffer handle
+ if(! Writeback::getInstance()->setSecure(isSecureBuffer(ohnd)))
+ {
+ ALOGE("Failed to set WB secure mode: %d for virtual display",
+ isSecureBuffer(ohnd));
+ return false;
+ }
+
+ int fd = -1; //FenceFD from the Copybit
+ hwc_sync(ctx, list, dpy, fd);
+
+ // Dump the layers for virtual
+ if(ctx->mHwcDebug[dpy])
+ ctx->mHwcDebug[dpy]->dumpLayers(list);
+
+ if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
+ ALOGE("%s: MDPComp draw failed", __FUNCTION__);
+ ret = -1;
+ }
+ // We need an FB layer handle check to cater for this usecase:
+ // Video is playing in landscape on primary, then launch
+ // ScreenRecord app.
+ // In this scenario, the first VDS draw call will have HWC
+ // composition and VDS does nit involve GPU to get eglSwapBuffer
+ // to get valid fb handle.
+ if (fbLayer->handle && !ctx->mFBUpdate[dpy]->draw(ctx,
+ (private_handle_t *)fbLayer->handle)) {
+ ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
+ ret = -1;
+ }
+
+ Writeback::getInstance()->queueBuffer(ohnd->fd,
+ (uint32_t)ohnd->offset);
+ if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ ALOGE("%s: display commit fail!", __FUNCTION__);
+ ret = -1;
+ }
+
+ if(sVDDumpEnabled) {
+ char bufferName[128];
+ // Dumping frame buffer
+ sync_wait(fbLayer->acquireFenceFd, 1000);
+ snprintf(bufferName, sizeof(bufferName), "vds.fb");
+ dumpBuffer((private_handle_t *)fbLayer->handle, bufferName);
+ // Dumping WB output for non-secure session
+ if(!isSecureBuffer(ohnd)) {
+ sync_wait(list->retireFenceFd, 1000);
+ snprintf(bufferName, sizeof(bufferName), "vds.wb");
+ dumpBuffer(ohnd, bufferName);
+ }
+ }
+ } else if(list->outbufAcquireFenceFd >= 0) {
+ //If we dont handle the frame, set retireFenceFd to outbufFenceFd,
+ //which will make sure, the framework waits on it and closes it.
+ //The other way is to wait on outbufFenceFd ourselves, close it and
+ //set retireFenceFd to -1. Since we want hwc to be async, choosing
+ //the former.
+ //Also dup because, the closeAcquireFds() will close the outbufFence
+ list->retireFenceFd = dup(list->outbufAcquireFenceFd);
+ }
+ }
+
+ closeAcquireFds(list);
+ return ret;
+}
+
+/* We set scaling mode on the VD if the output handle width and height
+ differs from the virtual frame buffer width and height. */
+void HWCVirtualVDS::setMDPScalingMode(hwc_context_t* ctx,
+ private_handle_t* ohnd, int dpy) {
+ bool scalingMode = false;
+ int fbWidth = ctx->dpyAttr[dpy].xres;
+ int fbHeight = ctx->dpyAttr[dpy].yres;
+ if((getWidth(ohnd) != fbWidth) || (getHeight(ohnd) != fbHeight)) {
+ scalingMode = true;
+ }
+ ctx->dpyAttr[dpy].mMDPScalingMode = scalingMode;
+
+ ALOGD_IF(HWCVIRTUAL_LOG, "%s fb(%dx%d) outputBuffer(%dx%d) scalingMode=%d",
+ __FUNCTION__, fbWidth, fbHeight,
+ getWidth(ohnd), getHeight(ohnd), scalingMode);
+}
diff --git a/msm8909/libhwcomposer/hwc_virtual.h b/msm8909/libhwcomposer/hwc_virtual.h
new file mode 100644
index 0000000..bd1833c
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_virtual.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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_VIRTUAL
+#define HWC_VIRTUAL
+
+#include <hwc_utils.h>
+
+namespace qhwc {
+
+class HWCVirtualVDS {
+public:
+ HWCVirtualVDS(){};
+ ~HWCVirtualVDS(){};
+ // Chooses composition type and configures pipe for each layer in virtual
+ // display list
+ int prepare(hwc_composer_device_1 *dev,
+ hwc_display_contents_1_t* list);
+ // Queues the buffer for each layer in virtual display list and call display
+ // commit.
+ int set(hwc_context_t *ctx, hwc_display_contents_1_t *list);
+ // instantiates mdpcomp, copybit and fbupdate objects and initialize those
+ // objects for virtual display during virtual display connect.
+ void init(hwc_context_t *ctx);
+ // Destroys mdpcomp, copybit and fbupdate objects and for virtual display
+ // during virtual display disconnect.
+ void destroy(hwc_context_t *ctx, size_t numDisplays,
+ hwc_display_contents_1_t** displays);
+ int getScalingHeight() const { return mScalingHeight; };
+ int getScalingWidth() const { return mScalingWidth; };
+ // We can dump the frame buffer and WB
+ // output buffer by dynamically enabling
+ // dumping via a binder call:
+ // adb shell service call display.qservice 15 i32 3 i32 1
+ static bool sVDDumpEnabled;
+ static void dynamicDebug(bool enable) {sVDDumpEnabled = enable;};
+
+private:
+ // These variables store the resolution that WB is being configured to
+ // in the current draw cycle.
+ int mScalingWidth, mScalingHeight;
+ void setMDPScalingMode(hwc_context_t* ctx,
+ private_handle_t* ohnd, int dpy);
+};
+
+}; //namespace
+#endif
diff --git a/msm8909/libhwcomposer/hwc_vsync.cpp b/msm8909/libhwcomposer/hwc_vsync.cpp
new file mode 100644
index 0000000..b876e0f
--- /dev/null
+++ b/msm8909/libhwcomposer/hwc_vsync.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are
+ * retained for attribution purposes only.
+
+ * 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 <cutils/properties.h>
+#include <utils/Log.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/msm_mdp.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
+#include <poll.h>
+#include "hwc_utils.h"
+#include "hdmi.h"
+#include "qd_utils.h"
+#include "string.h"
+#include "overlay.h"
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
+
+using namespace qdutils;
+namespace qhwc {
+
+#define HWC_VSYNC_THREAD_NAME "hwcVsyncThread"
+#define PANEL_ON_STR "panel_power_on ="
+#define ARRAY_LENGTH(array) (sizeof((array))/sizeof((array)[0]))
+#define MAX_THERMAL_LEVEL 3
+const int MAX_DATA = 64;
+
+int hwc_vsync_control(hwc_context_t* ctx, int dpy, int enable)
+{
+ int ret = 0;
+ if(!ctx->vstate.fakevsync &&
+ ioctl(ctx->dpyAttr[dpy].fd, MSMFB_OVERLAY_VSYNC_CTRL,
+ &enable) < 0) {
+ ALOGE("%s: vsync control failed. Dpy=%d, enable=%d : %s",
+ __FUNCTION__, dpy, enable, strerror(errno));
+ ret = -errno;
+ }
+ return ret;
+}
+
+static void handle_vsync_event(hwc_context_t* ctx, int dpy, char *data)
+{
+ // extract timestamp
+ uint64_t timestamp = 0;
+ if (!strncmp(data, "VSYNC=", strlen("VSYNC="))) {
+ timestamp = strtoull(data + strlen("VSYNC="), NULL, 0);
+ }
+ // send timestamp to SurfaceFlinger
+ ALOGD_IF (ctx->vstate.debug, "%s: timestamp %" PRIu64 " sent to SF for dpy=%d",
+ __FUNCTION__, timestamp, dpy);
+ ctx->proc->vsync(ctx->proc, dpy, timestamp);
+}
+
+static void handle_blank_event(hwc_context_t* ctx, int dpy, char *data)
+{
+ if (!strncmp(data, PANEL_ON_STR, strlen(PANEL_ON_STR))) {
+ unsigned long int poweron = strtoul(data + strlen(PANEL_ON_STR), NULL, 0);
+ ALOGI("%s: dpy:%d panel power state: %ld", __FUNCTION__, dpy, poweron);
+ if (!ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) {
+ ctx->dpyAttr[dpy].isActive = poweron ? true: false;
+ }
+ }
+}
+
+static void handle_thermal_event(hwc_context_t* ctx, int dpy, char *data)
+{
+ // extract thermal level
+ uint64_t thermalLevel = 0;
+ if (!strncmp(data, "thermal_level=", strlen("thermal_level="))) {
+ thermalLevel = strtoull(data + strlen("thermal_level="), NULL, 0);
+ }
+
+ if (thermalLevel >= MAX_THERMAL_LEVEL) {
+ ALOGD("%s: dpy:%d thermal_level=%" PRIu64 "",__FUNCTION__,dpy,thermalLevel);
+ ctx->mThermalBurstMode = true;
+ } else
+ ctx->mThermalBurstMode = false;
+}
+
+struct event {
+ const char* name;
+ void (*callback)(hwc_context_t* ctx, int dpy, char *data);
+};
+
+struct event event_list[] = {
+ { "vsync_event", handle_vsync_event },
+ { "show_blank_event", handle_blank_event },
+ { "msm_fb_thermal_level", handle_thermal_event },
+};
+
+#define num_events ARRAY_LENGTH(event_list)
+
+static void *vsync_loop(void *param)
+{
+ hwc_context_t * ctx = reinterpret_cast<hwc_context_t *>(param);
+
+ char thread_name[64] = HWC_VSYNC_THREAD_NAME;
+ prctl(PR_SET_NAME, (unsigned long) &thread_name, 0, 0, 0);
+ setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY +
+ android::PRIORITY_MORE_FAVORABLE);
+
+ char vdata[MAX_DATA];
+ //Number of physical displays
+ //We poll on all the nodes.
+ int num_displays = HWC_NUM_DISPLAY_TYPES - 1;
+ struct pollfd pfd[num_displays][num_events];
+
+ char property[PROPERTY_VALUE_MAX];
+ if(property_get("debug.hwc.fakevsync", property, NULL) > 0) {
+ if(atoi(property) == 1)
+ ctx->vstate.fakevsync = true;
+ }
+
+ char node_path[MAX_SYSFS_FILE_PATH];
+
+ for (int dpy = HWC_DISPLAY_PRIMARY; dpy < num_displays; dpy++) {
+ for(size_t ev = 0; ev < num_events; ev++) {
+ snprintf(node_path, sizeof(node_path),
+ "/sys/class/graphics/fb%d/%s",
+ dpy == HWC_DISPLAY_PRIMARY ? 0 :
+ overlay::Overlay::getInstance()->
+ getFbForDpy(HWC_DISPLAY_EXTERNAL),
+ event_list[ev].name);
+
+ ALOGI("%s: Reading event %zu for dpy %d from %s", __FUNCTION__,
+ ev, dpy, node_path);
+ pfd[dpy][ev].fd = open(node_path, O_RDONLY);
+
+ if (dpy == HWC_DISPLAY_PRIMARY && pfd[dpy][ev].fd < 0) {
+ // Make sure fb device is opened before starting
+ // this thread so this never happens.
+ ALOGE ("%s:unable to open event node for dpy=%d event=%zu, %s",
+ __FUNCTION__, dpy, ev, strerror(errno));
+ if (ev == 0) {
+ ctx->vstate.fakevsync = true;
+ //XXX: Blank events don't work with fake vsync,
+ //but we shouldn't be running on fake vsync anyway.
+ break;
+ }
+ }
+
+ memset(&vdata, '\0', sizeof(vdata));
+ // Read once from the fds to clear the first notify
+ pread(pfd[dpy][ev].fd, vdata , MAX_DATA - 1, 0);
+ if (pfd[dpy][ev].fd >= 0)
+ pfd[dpy][ev].events = POLLPRI | POLLERR;
+ }
+ }
+
+ if (LIKELY(!ctx->vstate.fakevsync)) {
+ do {
+ int err = poll(*pfd, (int)(num_displays * num_events), -1);
+ if(err > 0) {
+ for (int dpy = HWC_DISPLAY_PRIMARY; dpy < num_displays; dpy++) {
+ for(size_t ev = 0; ev < num_events; ev++) {
+ if (pfd[dpy][ev].revents & POLLPRI) {
+ // Clear vdata before writing into it
+ memset(&vdata, '\0', sizeof(vdata));
+ ssize_t len = pread(pfd[dpy][ev].fd, vdata,
+ MAX_DATA - 1, 0);
+ if (UNLIKELY(len < 0)) {
+ // If the read was just interrupted - it is not
+ // a fatal error. Just continue in this case
+ ALOGE ("%s: Unable to read event:%zu for \
+ dpy=%d : %s",
+ __FUNCTION__, ev, dpy, strerror(errno));
+ continue;
+ }
+ vdata[len] = '\0';
+ event_list[ev].callback(ctx, dpy, vdata);
+ }
+ }
+ }
+ } else {
+ ALOGE("%s: poll failed errno: %s", __FUNCTION__,
+ strerror(errno));
+ continue;
+ }
+ } while (true);
+
+ } else {
+
+ //Fake vsync is used only when set explicitly through a property or when
+ //the vsync timestamp node cannot be opened at bootup. There is no
+ //fallback to fake vsync from the true vsync loop, ever, as the
+ //condition can easily escape detection.
+ //Also, fake vsync is delivered only for the primary display.
+ do {
+ usleep(16666);
+ uint64_t timestamp = systemTime();
+ ctx->proc->vsync(ctx->proc, HWC_DISPLAY_PRIMARY, timestamp);
+
+ } while (true);
+ }
+
+ for (int dpy = HWC_DISPLAY_PRIMARY; dpy <= HWC_DISPLAY_EXTERNAL; dpy++ ) {
+ for( size_t event = 0; event < num_events; event++) {
+ if(pfd[dpy][event].fd >= 0)
+ close (pfd[dpy][event].fd);
+ }
+ }
+
+ return NULL;
+}
+
+void init_vsync_thread(hwc_context_t* ctx)
+{
+ int ret;
+ pthread_t vsync_thread;
+ ALOGI("Initializing VSYNC Thread");
+ ret = pthread_create(&vsync_thread, NULL, vsync_loop, (void*) ctx);
+ if (ret) {
+ ALOGE("%s: failed to create %s: %s", __FUNCTION__,
+ HWC_VSYNC_THREAD_NAME, strerror(ret));
+ }
+}
+
+}; //namespace
diff --git a/msm8909/liblight/Android.mk b/msm8909/liblight/Android.mk
new file mode 100644
index 0000000..977fc55
--- /dev/null
+++ b/msm8909/liblight/Android.mk
@@ -0,0 +1,27 @@
+# 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 stored in
+# hw/<COPYPIX_HARDWARE_MODULE_ID>.<ro.board.platform>.so
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := lights.c
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdlights\"
+LOCAL_MODULE := lights.$(TARGET_BOARD_PLATFORM)
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/msm8909/liblight/NOTICE b/msm8909/liblight/NOTICE
new file mode 100644
index 0000000..7340b9e
--- /dev/null
+++ b/msm8909/liblight/NOTICE
@@ -0,0 +1,190 @@
+
+ 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/msm8909/liblight/lights.c b/msm8909/liblight/lights.c
new file mode 100644
index 0000000..cf24d50
--- /dev/null
+++ b/msm8909/liblight/lights.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2014 The Linux Foundation. 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_NDEBUG 0
+
+#include <cutils/log.h>
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+#include <hardware/lights.h>
+
+/******************************************************************************/
+
+static pthread_once_t g_init = PTHREAD_ONCE_INIT;
+static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
+static struct light_state_t g_notification;
+static struct light_state_t g_battery;
+static int g_attention = 0;
+
+char const*const RED_LED_FILE
+ = "/sys/class/leds/red/brightness";
+
+char const*const GREEN_LED_FILE
+ = "/sys/class/leds/green/brightness";
+
+char const*const BLUE_LED_FILE
+ = "/sys/class/leds/blue/brightness";
+
+char const*const BLUETOOTH_LED_FILE
+ = "/sys/class/leds/bt/brightness";
+
+char const*const LCD_FILE
+ = "/sys/class/leds/lcd-backlight/brightness";
+
+char const*const BUTTON_FILE
+ = "/sys/class/leds/button-backlight/brightness";
+
+char const*const RED_BLINK_FILE
+ = "/sys/class/leds/red/blink";
+
+char const*const GREEN_BLINK_FILE
+ = "/sys/class/leds/green/blink";
+
+char const*const BLUE_BLINK_FILE
+ = "/sys/class/leds/blue/blink";
+
+/**
+ * device methods
+ */
+
+void init_globals(void)
+{
+ // init the mutex
+ pthread_mutex_init(&g_lock, NULL);
+}
+
+static int
+write_int(char const* path, int value)
+{
+ int fd;
+ static int already_warned = 0;
+
+ fd = open(path, O_RDWR);
+ if (fd >= 0) {
+ char buffer[20];
+ int bytes = snprintf(buffer, sizeof(buffer), "%d\n", value);
+ ssize_t amt = write(fd, buffer, (size_t)bytes);
+ close(fd);
+ return amt == -1 ? -errno : 0;
+ } else {
+ if (already_warned == 0) {
+ ALOGE("write_int failed to open %s\n", path);
+ already_warned = 1;
+ }
+ return -errno;
+ }
+}
+
+static int
+is_lit(struct light_state_t const* state)
+{
+ return state->color & 0x00ffffff;
+}
+
+static int
+rgb_to_brightness(struct light_state_t const* state)
+{
+ int color = state->color & 0x00ffffff;
+ return ((77*((color>>16)&0x00ff))
+ + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
+}
+
+static int
+set_light_backlight(struct light_device_t* dev,
+ struct light_state_t const* state)
+{
+ int err = 0;
+ int brightness = rgb_to_brightness(state);
+ if(!dev) {
+ return -1;
+ }
+ pthread_mutex_lock(&g_lock);
+ err = write_int(LCD_FILE, brightness);
+ pthread_mutex_unlock(&g_lock);
+ return err;
+}
+
+static int
+set_speaker_light_locked(struct light_device_t* dev,
+ struct light_state_t const* state)
+{
+ int red, green, blue;
+ int blink;
+ int onMS, offMS;
+ unsigned int colorRGB;
+
+ if(!dev) {
+ return -1;
+ }
+
+ switch (state->flashMode) {
+ case LIGHT_FLASH_TIMED:
+ onMS = state->flashOnMS;
+ offMS = state->flashOffMS;
+ break;
+ case LIGHT_FLASH_NONE:
+ default:
+ onMS = 0;
+ offMS = 0;
+ break;
+ }
+
+ colorRGB = state->color;
+
+#if 0
+ ALOGD("set_speaker_light_locked mode %d, colorRGB=%08X, onMS=%d, offMS=%d\n",
+ state->flashMode, colorRGB, onMS, offMS);
+#endif
+
+ red = (colorRGB >> 16) & 0xFF;
+ green = (colorRGB >> 8) & 0xFF;
+ blue = colorRGB & 0xFF;
+
+ if (onMS > 0 && offMS > 0) {
+ /*
+ * if ON time == OFF time
+ * use blink mode 2
+ * else
+ * use blink mode 1
+ */
+ if (onMS == offMS)
+ blink = 2;
+ else
+ blink = 1;
+ } else {
+ blink = 0;
+ }
+
+ if (blink) {
+ if (red) {
+ if (write_int(RED_BLINK_FILE, blink))
+ write_int(RED_LED_FILE, 0);
+ }
+ if (green) {
+ if (write_int(GREEN_BLINK_FILE, blink))
+ write_int(GREEN_LED_FILE, 0);
+ }
+ if (blue) {
+ if (write_int(BLUE_BLINK_FILE, blink))
+ write_int(BLUE_LED_FILE, 0);
+ }
+ } else {
+ write_int(RED_LED_FILE, red);
+ write_int(GREEN_LED_FILE, green);
+ write_int(BLUE_LED_FILE, blue);
+ }
+
+ return 0;
+}
+
+static void
+handle_speaker_battery_locked(struct light_device_t* dev)
+{
+ if (is_lit(&g_battery)) {
+ set_speaker_light_locked(dev, &g_battery);
+ } else {
+ set_speaker_light_locked(dev, &g_notification);
+ }
+}
+
+static int
+set_light_battery(struct light_device_t* dev,
+ struct light_state_t const* state)
+{
+ pthread_mutex_lock(&g_lock);
+ g_battery = *state;
+ handle_speaker_battery_locked(dev);
+ pthread_mutex_unlock(&g_lock);
+ return 0;
+}
+
+static int
+set_light_notifications(struct light_device_t* dev,
+ struct light_state_t const* state)
+{
+ pthread_mutex_lock(&g_lock);
+ g_notification = *state;
+ handle_speaker_battery_locked(dev);
+ pthread_mutex_unlock(&g_lock);
+ return 0;
+}
+
+static int
+set_light_attention(struct light_device_t* dev,
+ struct light_state_t const* state)
+{
+ pthread_mutex_lock(&g_lock);
+ if (state->flashMode == LIGHT_FLASH_HARDWARE) {
+ g_attention = state->flashOnMS;
+ } else if (state->flashMode == LIGHT_FLASH_NONE) {
+ g_attention = 0;
+ }
+ handle_speaker_battery_locked(dev);
+ pthread_mutex_unlock(&g_lock);
+ return 0;
+}
+
+static int
+set_light_buttons(struct light_device_t* dev,
+ struct light_state_t const* state)
+{
+ int err = 0;
+ if(!dev) {
+ return -1;
+ }
+ pthread_mutex_lock(&g_lock);
+ err = write_int(BUTTON_FILE, state->color & 0xFF);
+ pthread_mutex_unlock(&g_lock);
+ return err;
+}
+
+static int
+set_light_bluetooth(struct light_device_t* dev,
+ struct light_state_t const* state)
+{
+ int err = 0;
+ if(!dev) {
+ return -1;
+ }
+ pthread_mutex_lock(&g_lock);
+ err = write_int(BLUETOOTH_LED_FILE, state->color & 0xFF);
+ pthread_mutex_unlock(&g_lock);
+ return err;
+}
+
+/** Close the lights device */
+static int
+close_lights(struct light_device_t *dev)
+{
+ if (dev) {
+ free(dev);
+ }
+ return 0;
+}
+
+
+/******************************************************************************/
+
+/**
+ * module methods
+ */
+
+/** Open a new instance of a lights device using name */
+static int open_lights(const struct hw_module_t* module, char const* name,
+ struct hw_device_t** device)
+{
+ int (*set_light)(struct light_device_t* dev,
+ struct light_state_t const* state);
+
+ if (0 == strcmp(LIGHT_ID_BACKLIGHT, name))
+ set_light = set_light_backlight;
+ else if (0 == strcmp(LIGHT_ID_BATTERY, name))
+ set_light = set_light_battery;
+ else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name))
+ set_light = set_light_notifications;
+ else if (0 == strcmp(LIGHT_ID_BUTTONS, name))
+ set_light = set_light_buttons;
+ else if (0 == strcmp(LIGHT_ID_ATTENTION, name))
+ set_light = set_light_attention;
+ else if (0 == strcmp(LIGHT_ID_BLUETOOTH, name))
+ set_light = set_light_bluetooth;
+ else
+ return -EINVAL;
+
+ pthread_once(&g_init, init_globals);
+
+ struct light_device_t *dev = malloc(sizeof(struct light_device_t));
+
+ if(!dev)
+ return -ENOMEM;
+
+ memset(dev, 0, sizeof(*dev));
+
+ dev->common.tag = HARDWARE_DEVICE_TAG;
+ dev->common.version = 0;
+ dev->common.module = (struct hw_module_t*)module;
+ dev->common.close = (int (*)(struct hw_device_t*))close_lights;
+ dev->set_light = set_light;
+
+ *device = (struct hw_device_t*)dev;
+ return 0;
+}
+
+static struct hw_module_methods_t lights_module_methods = {
+ .open = open_lights,
+};
+
+/*
+ * The lights Module
+ */
+struct hw_module_t HAL_MODULE_INFO_SYM = {
+ .tag = HARDWARE_MODULE_TAG,
+ .version_major = 1,
+ .version_minor = 0,
+ .id = LIGHTS_HARDWARE_MODULE_ID,
+ .name = "lights Module",
+ .author = "Google, Inc.",
+ .methods = &lights_module_methods,
+};
diff --git a/msm8909/libmemtrack/Android.mk b/msm8909/libmemtrack/Android.mk
new file mode 100644
index 0000000..3ed37a3
--- /dev/null
+++ b/msm8909/libmemtrack/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2013 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 stored in
+# hw/<POWERS_HARDWARE_MODULE_ID>.<ro.hardware>.so
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_C_INCLUDES += hardware/libhardware/include
+LOCAL_CFAGS := -Wconversion -Wall -Werror
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SRC_FILES := memtrack_msm.c kgsl.c
+LOCAL_MODULE := memtrack.$(TARGET_BOARD_PLATFORM)
+include $(BUILD_SHARED_LIBRARY)
diff --git a/msm8909/libmemtrack/kgsl.c b/msm8909/libmemtrack/kgsl.c
new file mode 100644
index 0000000..22bd0c2
--- /dev/null
+++ b/msm8909/libmemtrack/kgsl.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2013 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 <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include <hardware/memtrack.h>
+
+#include "memtrack_msm.h"
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#define min(x, y) ((x) < (y) ? (x) : (y))
+
+struct memtrack_record record_templates[] = {
+ {
+ .flags = MEMTRACK_FLAG_SMAPS_ACCOUNTED |
+ MEMTRACK_FLAG_PRIVATE |
+ MEMTRACK_FLAG_NONSECURE,
+ },
+ {
+ .flags = MEMTRACK_FLAG_SMAPS_UNACCOUNTED |
+ MEMTRACK_FLAG_PRIVATE |
+ MEMTRACK_FLAG_NONSECURE,
+ },
+};
+
+int kgsl_memtrack_get_memory(pid_t pid, enum memtrack_type type,
+ struct memtrack_record *records,
+ size_t *num_records)
+{
+ size_t allocated_records = min(*num_records, ARRAY_SIZE(record_templates));
+ int i;
+ FILE *fp;
+ char line[1024];
+ char tmp[128];
+ bool is_surfaceflinger = false;
+ size_t accounted_size = 0;
+ size_t unaccounted_size = 0;
+ unsigned long smaps_addr = 0;
+
+ *num_records = ARRAY_SIZE(record_templates);
+
+ /* fastpath to return the necessary number of records */
+ if (allocated_records == 0) {
+ return 0;
+ }
+
+ snprintf(tmp, sizeof(tmp), "/proc/%d/cmdline", pid);
+ fp = fopen(tmp, "r");
+ if (fp != NULL) {
+ if (fgets(line, sizeof(line), fp)) {
+ if (strcmp(line, "/system/bin/surfaceflinger") == 0)
+ is_surfaceflinger = true;
+ }
+ fclose(fp);
+ }
+
+ memcpy(records, record_templates,
+ sizeof(struct memtrack_record) * allocated_records);
+
+ snprintf(tmp, sizeof(tmp), "/d/kgsl/proc/%d/mem", pid);
+ fp = fopen(tmp, "r");
+ if (fp == NULL) {
+ return -errno;
+ }
+
+ /* Go through each line of <pid>/mem file and for every entry of type "gpumem"
+ * check if the gpubuffer entry is usermapped or not. If the entry is usermapped
+ * count the entry as accounted else count the entry as unaccounted.
+ */
+ while (1) {
+ unsigned long size;
+ char line_type[7];
+ char flags[7];
+ char line_usage[19];
+ int ret;
+
+ if (fgets(line, sizeof(line), fp) == NULL) {
+ break;
+ }
+
+ /* Format:
+ * gpuaddr useraddr size id flags type usage sglen
+ * 545ba000 545ba000 4096 1 ----pY gpumem arraybuffer 1
+ */
+ ret = sscanf(line, "%*x %*x %lu %*d %6s %6s %18s %*d\n",
+ &size, flags, line_type, line_usage);
+ if (ret != 4) {
+ continue;
+ }
+
+ if (type == MEMTRACK_TYPE_GL && strcmp(line_type, "gpumem") == 0) {
+
+ if (flags[5] == 'Y')
+ accounted_size += size;
+ else
+ unaccounted_size += size;
+
+ } else if (type == MEMTRACK_TYPE_GRAPHICS && strcmp(line_type, "ion") == 0) {
+ if (!is_surfaceflinger || strcmp(line_usage, "egl_image") != 0) {
+ unaccounted_size += size;
+ }
+ }
+ }
+
+ if (allocated_records > 0) {
+ records[0].size_in_bytes = accounted_size;
+ }
+ if (allocated_records > 1) {
+ records[1].size_in_bytes = unaccounted_size;
+ }
+
+ fclose(fp);
+
+ return 0;
+}
diff --git a/msm8909/libmemtrack/memtrack_msm.c b/msm8909/libmemtrack/memtrack_msm.c
new file mode 100644
index 0000000..8adff96
--- /dev/null
+++ b/msm8909/libmemtrack/memtrack_msm.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2013 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 <errno.h>
+
+#include <hardware/memtrack.h>
+
+#include "memtrack_msm.h"
+
+int msm_memtrack_init(const struct memtrack_module *module)
+{
+ if(!module)
+ return -1;
+ return 0;
+}
+
+int msm_memtrack_get_memory(const struct memtrack_module *module,
+ pid_t pid,
+ int type,
+ struct memtrack_record *records,
+ size_t *num_records)
+{
+ if(!module)
+ return -1;
+ if (type == MEMTRACK_TYPE_GL || type == MEMTRACK_TYPE_GRAPHICS) {
+ return kgsl_memtrack_get_memory(pid, type, records, num_records);
+ }
+
+ return -EINVAL;
+}
+
+static struct hw_module_methods_t memtrack_module_methods = {
+ .open = NULL,
+};
+
+struct memtrack_module HAL_MODULE_INFO_SYM = {
+ common: {
+ tag: HARDWARE_MODULE_TAG,
+ module_api_version: MEMTRACK_MODULE_API_VERSION_0_1,
+ hal_api_version: HARDWARE_HAL_API_VERSION,
+ id: MEMTRACK_HARDWARE_MODULE_ID,
+ name: "MSM Memory Tracker HAL",
+ author: "The Android Open Source Project",
+ methods: &memtrack_module_methods,
+ },
+
+ init: msm_memtrack_init,
+ getMemory: msm_memtrack_get_memory,
+};
+
diff --git a/msm8909/libmemtrack/memtrack_msm.h b/msm8909/libmemtrack/memtrack_msm.h
new file mode 100644
index 0000000..74aa576
--- /dev/null
+++ b/msm8909/libmemtrack/memtrack_msm.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 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 _MEMTRACK_MSM_H_
+#define _MEMTRACK_MSM_H_
+
+int kgsl_memtrack_get_memory(pid_t pid, enum memtrack_type type,
+ struct memtrack_record *records,
+ size_t *num_records);
+
+#endif
diff --git a/msm8909/liboverlay/Android.mk b/msm8909/liboverlay/Android.mk
new file mode 100644
index 0000000..aa1ea24
--- /dev/null
+++ b/msm8909/liboverlay/Android.mk
@@ -0,0 +1,22 @@
+LOCAL_PATH := $(call my-dir)
+include $(LOCAL_PATH)/../common.mk
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := liboverlay
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
+LOCAL_SHARED_LIBRARIES := $(common_libs) libqdutils libmemalloc \
+ libsync libdl
+LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdoverlay\"
+LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
+LOCAL_SRC_FILES := \
+ overlay.cpp \
+ overlayUtils.cpp \
+ overlayMdp.cpp \
+ overlayRotator.cpp \
+ overlayMdpRot.cpp \
+ overlayMdssRot.cpp \
+ overlayWriteback.cpp \
+ pipes/overlayGenPipe.cpp
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/msm8909/liboverlay/mdpWrapper.h b/msm8909/liboverlay/mdpWrapper.h
new file mode 100644
index 0000000..f689e45
--- /dev/null
+++ b/msm8909/liboverlay/mdpWrapper.h
@@ -0,0 +1,388 @@
+/*
+* Copyright (c) 2011, The Linux Foundation. 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 The Linux Foundation 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
+
+#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
+
+/*
+* In order to make overlay::mdp_wrapper shorter, please do something like:
+* namespace mdpwrap = overlay::mdp_wrapper;
+* */
+
+#include <linux/msm_mdp.h>
+#include <linux/msm_rotator.h>
+#include <sys/ioctl.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <errno.h>
+#include "overlayUtils.h"
+#include "overlay.h"
+
+#define IOCTL_DEBUG 0
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+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);
+
+/* MSMFB_OVERLAY_PREPARE */
+int validateAndSet(const int& fd, mdp_overlay_list& list);
+
+/* 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_DISPLAY_COMMIT */
+bool displayCommit(int fd);
+
+/* MSMFB_WRITEBACK_INIT, MSMFB_WRITEBACK_START */
+bool wbInitStart(int fbfd);
+
+/* MSMFB_WRITEBACK_STOP, MSMFB_WRITEBACK_TERMINATE */
+bool wbStopTerminate(int fbfd);
+
+/* MSMFB_WRITEBACK_QUEUE_BUFFER */
+bool wbQueueBuffer(int fbfd, struct msmfb_data& fbData);
+
+/* MSMFB_WRITEBACK_DEQUEUE_BUFFER */
+bool wbDequeueBuffer(int fbfd, struct msmfb_data& fbData);
+
+/* 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 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) {
+ ATRACE_CALL();
+ if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) < 0) {
+ ALOGE("Failed to call ioctl FBIOGET_FSCREENINFO err=%s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+inline bool getVScreenInfo(int fd, fb_var_screeninfo& vinfo) {
+ ATRACE_CALL();
+ if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) < 0) {
+ ALOGE("Failed to call ioctl FBIOGET_VSCREENINFO err=%s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+inline bool setVScreenInfo(int fd, fb_var_screeninfo& vinfo) {
+ ATRACE_CALL();
+ if (ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo) < 0) {
+ ALOGE("Failed to call ioctl FBIOPUT_VSCREENINFO err=%s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+inline bool startRotator(int fd, msm_rotator_img_info& rot) {
+ ATRACE_CALL();
+ if (ioctl(fd, MSM_ROTATOR_IOCTL_START, &rot) < 0){
+ ALOGE("Failed to call ioctl MSM_ROTATOR_IOCTL_START err=%s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+inline bool rotate(int fd, msm_rotator_data_info& rot) {
+ ATRACE_CALL();
+ if (ioctl(fd, MSM_ROTATOR_IOCTL_ROTATE, &rot) < 0) {
+ ALOGE("Failed to call ioctl MSM_ROTATOR_IOCTL_ROTATE err=%s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+inline bool setOverlay(int fd, mdp_overlay& ov) {
+ ATRACE_CALL();
+ if (ioctl(fd, MSMFB_OVERLAY_SET, &ov) < 0) {
+ ALOGE("Failed to call ioctl MSMFB_OVERLAY_SET err=%s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+inline int validateAndSet(const int& fd, mdp_overlay_list& list) {
+ ATRACE_CALL();
+ uint32_t id = 0;
+ if(UNLIKELY(Overlay::isDebugPipeLifecycle())) {
+ for(uint32_t i = 0; i < list.num_overlays; i++) {
+ if(list.overlay_list[i]->id != (uint32_t)MSMFB_NEW_REQUEST) {
+ id |= list.overlay_list[i]->id;
+ }
+ }
+
+ ALOGD("%s Total pipes needed: %d, Exisiting pipe mask 0x%04x",
+ __FUNCTION__, list.num_overlays, id);
+ id = 0;
+ }
+
+ if (ioctl(fd, MSMFB_OVERLAY_PREPARE, &list) < 0) {
+ ALOGD_IF(IOCTL_DEBUG, "Failed to call ioctl MSMFB_OVERLAY_PREPARE "
+ "err=%s", strerror(errno));
+ return errno;
+ }
+
+ if(UNLIKELY(Overlay::isDebugPipeLifecycle())) {
+ for(uint32_t i = 0; i < list.num_overlays; i++) {
+ id |= list.overlay_list[i]->id;
+ }
+
+ ALOGD("%s Pipe mask after OVERLAY_PREPARE 0x%04x", __FUNCTION__, id);
+ }
+
+ return 0;
+}
+
+inline bool endRotator(int fd, uint32_t sessionId) {
+ ATRACE_CALL();
+ if (ioctl(fd, MSM_ROTATOR_IOCTL_FINISH, &sessionId) < 0) {
+ ALOGE("Failed to call ioctl MSM_ROTATOR_IOCTL_FINISH err=%s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+inline bool unsetOverlay(int fd, int ovId) {
+ ATRACE_CALL();
+ ALOGD_IF(Overlay::isDebugPipeLifecycle(), "%s Unsetting pipe 0x%04x",
+ __FUNCTION__, ovId);
+
+ if (ioctl(fd, MSMFB_OVERLAY_UNSET, &ovId) < 0) {
+ ALOGE("Failed to call ioctl MSMFB_OVERLAY_UNSET err=%s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+inline bool getOverlay(int fd, mdp_overlay& ov) {
+ ATRACE_CALL();
+ if (ioctl(fd, MSMFB_OVERLAY_GET, &ov) < 0) {
+ ALOGE("Failed to call ioctl MSMFB_OVERLAY_GET err=%s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+inline bool play(int fd, msmfb_overlay_data& od) {
+ ATRACE_CALL();
+ if (ioctl(fd, MSMFB_OVERLAY_PLAY, &od) < 0) {
+ ALOGE("Failed to call ioctl MSMFB_OVERLAY_PLAY err=%s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+inline bool displayCommit(int fd, mdp_display_commit& info) {
+ ATRACE_CALL();
+ ALOGD_IF(Overlay::isDebugPipeLifecycle(), "%s", __FUNCTION__);
+
+ if(ioctl(fd, MSMFB_DISPLAY_COMMIT, &info) == -1) {
+ ALOGE("Failed to call ioctl MSMFB_DISPLAY_COMMIT err=%s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+inline bool wbInitStart(int fbfd) {
+ ATRACE_CALL();
+ if(ioctl(fbfd, MSMFB_WRITEBACK_INIT, NULL) < 0) {
+ ALOGE("Failed to call ioctl MSMFB_WRITEBACK_INIT err=%s",
+ strerror(errno));
+ return false;
+ }
+ if(ioctl(fbfd, MSMFB_WRITEBACK_START, NULL) < 0) {
+ ALOGE("Failed to call ioctl MSMFB_WRITEBACK_START err=%s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+inline bool wbStopTerminate(int fbfd) {
+ ATRACE_CALL();
+ if(ioctl(fbfd, MSMFB_WRITEBACK_STOP, NULL) < 0) {
+ ALOGE("Failed to call ioctl MSMFB_WRITEBACK_STOP err=%s",
+ strerror(errno));
+ return false;
+ }
+ if(ioctl(fbfd, MSMFB_WRITEBACK_TERMINATE, NULL) < 0) {
+ ALOGE("Failed to call ioctl MSMFB_WRITEBACK_TERMINATE err=%s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+inline bool wbQueueBuffer(int fbfd, struct msmfb_data& fbData) {
+ ATRACE_CALL();
+ if(ioctl(fbfd, MSMFB_WRITEBACK_QUEUE_BUFFER, &fbData) < 0) {
+ ALOGE("Failed to call ioctl MSMFB_WRITEBACK_QUEUE_BUFFER err=%s",
+ strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+inline bool wbDequeueBuffer(int fbfd, struct msmfb_data& fbData) {
+ ATRACE_CALL();
+ if(ioctl(fbfd, MSMFB_WRITEBACK_DEQUEUE_BUFFER, &fbData) < 0) {
+ ALOGE("Failed to call ioctl MSMFB_WRITEBACK_DEQUEUE_BUFFER err=%s",
+ strerror(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 alpha=%d mask=%d flags=0x%x id=%d",
+ s, ov.z_order, 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);
+ /*
+ Commented off to prevent verbose logging, since user_data could have 8 or so
+ fields which are mostly 0
+ 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 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=%u dstx=%d dsty=%d rot=%d, ena=%d scale=%d",
+ s, rot.session_id, rot.dst_x, rot.dst_y,
+ rot.rotations, rot.enable, rot.downscale_ratio);
+ 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=%u 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/msm8909/liboverlay/overlay.cpp b/msm8909/liboverlay/overlay.cpp
new file mode 100644
index 0000000..1a4bf03
--- /dev/null
+++ b/msm8909/liboverlay/overlay.cpp
@@ -0,0 +1,582 @@
+/*
+* Copyright (c) 2011-2014, The Linux Foundation. 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 The Linux Foundation 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 <dlfcn.h>
+#include "overlay.h"
+#include "pipes/overlayGenPipe.h"
+#include "mdp_version.h"
+#include "qdMetaData.h"
+#include "qd_utils.h"
+
+namespace overlay {
+using namespace utils;
+using namespace qdutils;
+
+Overlay::Overlay() {
+ int numPipes = qdutils::MDPVersion::getInstance().getTotalPipes();
+ PipeBook::NUM_PIPES = (numPipes <= utils::OV_MAX)? numPipes : utils::OV_MAX;
+ for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+ mPipeBook[i].init();
+ }
+
+ initScalar();
+ setDMAMultiplexingSupported();
+}
+
+Overlay::~Overlay() {
+ for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+ mPipeBook[i].destroy();
+ }
+ destroyScalar();
+}
+
+void Overlay::configBegin() {
+ for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+ //Mark as available for this round.
+ PipeBook::resetUse(i);
+ PipeBook::resetAllocation(i);
+ }
+}
+
+void Overlay::configDone() {
+ for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+ if((PipeBook::isNotUsed(i) && !sessionInProgress((eDest)i)) ||
+ isSessionEnded((eDest)i)) {
+ //Forces UNSET on pipes, flushes rotator memory and session, closes
+ //fds
+ mPipeBook[i].destroy();
+ }
+ }
+ PipeBook::save();
+}
+
+int Overlay::getPipeId(utils::eDest dest) {
+ return mPipeBook[(int)dest].mPipe->getPipeId();
+}
+
+eDest Overlay::getDest(int pipeid) {
+ eDest dest = OV_INVALID;
+ // finding the dest corresponding to the given pipe
+ for(int i=0; i < PipeBook::NUM_PIPES; ++i) {
+ if(mPipeBook[i].valid() && mPipeBook[i].mPipe->getPipeId() == pipeid) {
+ return (eDest)i;
+ }
+ }
+ return dest;
+}
+
+eDest Overlay::reservePipe(int pipeid) {
+ eDest dest = getDest(pipeid);
+ PipeBook::setAllocation((int)dest);
+ return dest;
+}
+
+eDest Overlay::nextPipe(eMdpPipeType type, const PipeSpecs& pipeSpecs) {
+ eDest dest = OV_INVALID;
+ int dpy = pipeSpecs.dpy;
+ int mixer = pipeSpecs.mixer;
+ int formatType = pipeSpecs.formatClass;
+ for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+ if( (type == OV_MDP_PIPE_ANY || //Pipe type match
+ type == PipeBook::getPipeType((eDest)i)) &&
+ (mPipeBook[i].mDisplay == DPY_UNUSED || //Free or same display
+ mPipeBook[i].mDisplay == dpy) &&
+ (mPipeBook[i].mMixer == MIXER_UNUSED || //Free or same mixer
+ mPipeBook[i].mMixer == mixer) &&
+ (mPipeBook[i].mFormatType == FORMAT_NONE || //Free or same format
+ mPipeBook[i].mFormatType == formatType) &&
+ PipeBook::isNotAllocated(i) && //Free pipe
+ ( (sDMAMultiplexingSupported && dpy) ||
+ !(sDMAMode == DMA_BLOCK_MODE && //DMA pipe in Line mode
+ PipeBook::getPipeType((eDest)i) == OV_MDP_PIPE_DMA)) ){
+ //DMA-Multiplexing is only supported for WB on 8x26
+ dest = (eDest)i;
+ PipeBook::setAllocation(i);
+ break;
+ }
+ }
+
+ if(dest != OV_INVALID) {
+ int index = (int)dest;
+ mPipeBook[index].mDisplay = dpy;
+ mPipeBook[index].mMixer = mixer;
+ mPipeBook[index].mFormatType = formatType;
+ if(not mPipeBook[index].valid()) {
+ mPipeBook[index].mPipe = new GenericPipe(dpy);
+ mPipeBook[index].mSession = PipeBook::NONE;
+ }
+ }
+
+ return dest;
+}
+
+utils::eDest Overlay::getPipe(const PipeSpecs& pipeSpecs) {
+ if(MDPVersion::getInstance().is8x26()) {
+ return getPipe_8x26(pipeSpecs);
+ } else if(MDPVersion::getInstance().is8x16()) {
+ return getPipe_8x16(pipeSpecs);
+ } else if(MDPVersion::getInstance().is8x39()) {
+ return getPipe_8x39(pipeSpecs);
+ } else if(MDPVersion::getInstance().is8994()) {
+ return getPipe_8994(pipeSpecs);
+ }
+
+ eDest dest = OV_INVALID;
+
+ //The default behavior is to assume RGB and VG pipes have scalars
+ if(pipeSpecs.formatClass == FORMAT_YUV) {
+ return nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
+ } else if(pipeSpecs.fb == false) { //RGB App layers
+ if(not pipeSpecs.needsScaling) {
+ dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs);
+ }
+ if(dest == OV_INVALID) {
+ dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs);
+ }
+ if(dest == OV_INVALID) {
+ dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
+ }
+ } else { //FB layer
+ dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs);
+ if(dest == OV_INVALID) {
+ dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
+ }
+ //Some features can cause FB to have scaling as well.
+ //If we ever come to this block with FB needing scaling,
+ //the screen will be black for a frame, since the FB won't get a pipe
+ //but atleast this will prevent a hang
+ if(dest == OV_INVALID and (not pipeSpecs.needsScaling)) {
+ dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs);
+ }
+ }
+ return dest;
+}
+
+utils::eDest Overlay::getPipe_8x26(const PipeSpecs& pipeSpecs) {
+ //Use this to hide all the 8x26 requirements that cannot be humanly
+ //described in a generic way
+ eDest dest = OV_INVALID;
+ if(pipeSpecs.formatClass == FORMAT_YUV) { //video
+ return nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
+ } else if(pipeSpecs.fb == false) { //RGB app layers
+ if((not pipeSpecs.needsScaling) and
+ (not (pipeSpecs.numActiveDisplays > 1 &&
+ pipeSpecs.dpy == DPY_PRIMARY))) {
+ dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs);
+ }
+ if(dest == OV_INVALID) {
+ dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs);
+ }
+ if(dest == OV_INVALID) {
+ dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
+ }
+ } else { //FB layer
+ //For 8x26 Secondary we use DMA always for FB for inline rotation
+ if(pipeSpecs.dpy == DPY_PRIMARY) {
+ dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs);
+ if(dest == OV_INVALID) {
+ dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
+ }
+ }
+ if(dest == OV_INVALID and (not pipeSpecs.needsScaling) and
+ (not (pipeSpecs.numActiveDisplays > 1 &&
+ pipeSpecs.dpy == DPY_PRIMARY))) {
+ dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs);
+ }
+ }
+ return dest;
+}
+
+utils::eDest Overlay::getPipe_8x16(const PipeSpecs& pipeSpecs) {
+ //Having such functions help keeping the interface generic but code specific
+ //and rife with assumptions
+ eDest dest = OV_INVALID;
+ if(pipeSpecs.formatClass == FORMAT_YUV or pipeSpecs.needsScaling) {
+ return nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
+ } else {
+ //Since this is a specific func, we can assume stuff like RGB pipe not
+ //having scalar blocks
+ dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs);
+ if(dest == OV_INVALID) {
+ dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs);
+ }
+ if(dest == OV_INVALID) {
+ dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
+ }
+ }
+ return dest;
+}
+
+utils::eDest Overlay::getPipe_8x39(const PipeSpecs& pipeSpecs) {
+ //8x16 & 8x36 has same number of pipes, pipe-types & scaling capabilities.
+ //Rely on 8x16 until we see a need to change.
+ return getPipe_8x16(pipeSpecs);
+}
+
+utils::eDest Overlay::getPipe_8994(const PipeSpecs& pipeSpecs) {
+ //If DMA pipes need to be used in block mode for downscale, there could be
+ //cases where consecutive rounds need separate modes, which cannot be
+ //supported since we at least need 1 round in between where the DMA is
+ //unused
+ eDest dest = OV_INVALID;
+ if(pipeSpecs.formatClass == FORMAT_YUV) {
+ return nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
+ } else {
+ dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs);
+ if(dest == OV_INVALID) {
+ dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
+ }
+ if(dest == OV_INVALID and not pipeSpecs.needsScaling) {
+ dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs);
+ }
+ }
+ return dest;
+}
+
+void Overlay::endAllSessions() {
+ for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+ if(mPipeBook[i].valid() && mPipeBook[i].mSession==PipeBook::START)
+ mPipeBook[i].mSession = PipeBook::END;
+ }
+}
+
+bool Overlay::isPipeTypeAttached(eMdpPipeType type) {
+ for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+ if(type == PipeBook::getPipeType((eDest)i) &&
+ mPipeBook[i].mDisplay != DPY_UNUSED) {
+ return true;
+ }
+ }
+ return false;
+}
+
+int Overlay::comparePipePriority(utils::eDest pipe1Index,
+ utils::eDest pipe2Index) {
+ validate((int)pipe1Index);
+ validate((int)pipe2Index);
+ uint8_t pipe1Prio = mPipeBook[(int)pipe1Index].mPipe->getPriority();
+ uint8_t pipe2Prio = mPipeBook[(int)pipe2Index].mPipe->getPriority();
+ if(pipe1Prio > pipe2Prio)
+ return -1;
+ if(pipe1Prio < pipe2Prio)
+ return 1;
+ return 0;
+}
+
+bool Overlay::commit(utils::eDest dest) {
+ bool ret = false;
+ validate((int)dest);
+
+ if(mPipeBook[dest].mPipe->commit()) {
+ ret = true;
+ PipeBook::setUse((int)dest);
+ } else {
+ clear(mPipeBook[dest].mDisplay);
+ }
+ return ret;
+}
+
+bool Overlay::queueBuffer(int fd, uint32_t offset,
+ utils::eDest dest) {
+ bool ret = false;
+ validate((int)dest);
+ //Queue only if commit() has succeeded (and the bit set)
+ if(PipeBook::isUsed((int)dest)) {
+ ret = mPipeBook[dest].mPipe->queueBuffer(fd, offset);
+ }
+ return ret;
+}
+
+void Overlay::setCrop(const utils::Dim& d,
+ utils::eDest dest) {
+ validate((int)dest);
+ mPipeBook[dest].mPipe->setCrop(d);
+}
+
+void Overlay::setColor(const uint32_t color,
+ utils::eDest dest) {
+ validate((int)dest);
+ mPipeBook[dest].mPipe->setColor(color);
+}
+
+void Overlay::setPosition(const utils::Dim& d,
+ utils::eDest dest) {
+ validate((int)dest);
+ mPipeBook[dest].mPipe->setPosition(d);
+}
+
+void Overlay::setTransform(const int orient,
+ utils::eDest dest) {
+ validate((int)dest);
+
+ utils::eTransform transform =
+ static_cast<utils::eTransform>(orient);
+ mPipeBook[dest].mPipe->setTransform(transform);
+
+}
+
+void Overlay::setSource(const utils::PipeArgs args,
+ utils::eDest dest) {
+ validate((int)dest);
+
+ setPipeType(dest, PipeBook::getPipeType(dest));
+ mPipeBook[dest].mPipe->setSource(args);
+}
+
+void Overlay::setVisualParams(const MetaData_t& metadata, utils::eDest dest) {
+ validate((int)dest);
+ mPipeBook[dest].mPipe->setVisualParams(metadata);
+}
+
+void Overlay::setPipeType(utils::eDest pipeIndex,
+ const utils::eMdpPipeType pType) {
+ mPipeBook[pipeIndex].mPipe->setPipeType(pType);
+}
+
+Overlay* Overlay::getInstance() {
+ if(sInstance == NULL) {
+ sInstance = new Overlay();
+ }
+ return sInstance;
+}
+
+// Clears any VG pipes allocated to the fb devices
+// Generates a LUT for pipe types.
+int Overlay::initOverlay() {
+ int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion();
+ int numPipesXType[OV_MDP_PIPE_ANY] = {0};
+ numPipesXType[OV_MDP_PIPE_RGB] =
+ qdutils::MDPVersion::getInstance().getRGBPipes();
+ numPipesXType[OV_MDP_PIPE_VG] =
+ qdutils::MDPVersion::getInstance().getVGPipes();
+ numPipesXType[OV_MDP_PIPE_DMA] =
+ qdutils::MDPVersion::getInstance().getDMAPipes();
+
+ int index = 0;
+ for(int X = 0; X < (int)OV_MDP_PIPE_ANY; X++) { //iterate over types
+ for(int j = 0; j < numPipesXType[X]; j++) { //iterate over num
+ PipeBook::pipeTypeLUT[index] = (utils::eMdpPipeType)X;
+ index++;
+ }
+ }
+
+ if (mdpVersion < qdutils::MDSS_V5 && mdpVersion > qdutils::MDP_V3_0_5) {
+ msmfb_mixer_info_req req;
+ mdp_mixer_info *minfo = NULL;
+ char name[64];
+ int fd = -1;
+ for(int i = 0; i < MAX_FB_DEVICES; i++) {
+ snprintf(name, 64, FB_DEVICE_TEMPLATE, i);
+ ALOGD("initoverlay:: opening the device:: %s", name);
+ fd = ::open(name, O_RDWR, 0);
+ if(fd < 0) {
+ ALOGE("cannot open framebuffer(%d)", i);
+ return -1;
+ }
+ //Get the mixer configuration */
+ req.mixer_num = i;
+ if (ioctl(fd, MSMFB_MIXER_INFO, &req) == -1) {
+ ALOGE("ERROR: MSMFB_MIXER_INFO ioctl failed");
+ close(fd);
+ return -1;
+ }
+ minfo = req.info;
+ for (int j = 0; j < req.cnt; j++) {
+ ALOGD("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;
+ ALOGD("Unset overlay with index: %d at mixer %d", index, i);
+ if(ioctl(fd, MSMFB_OVERLAY_UNSET, &index) == -1) {
+ ALOGE("ERROR: MSMFB_OVERLAY_UNSET failed");
+ close(fd);
+ return -1;
+ }
+ }
+ minfo++;
+ }
+ close(fd);
+ fd = -1;
+ }
+ }
+
+ FILE *displayDeviceFP = NULL;
+ char fbType[MAX_FRAME_BUFFER_NAME_SIZE];
+ char msmFbTypePath[MAX_FRAME_BUFFER_NAME_SIZE];
+ const char *strDtvPanel = "dtv panel";
+ const char *strWbPanel = "writeback panel";
+
+ for(int num = 1; num < MAX_FB_DEVICES; num++) {
+ snprintf (msmFbTypePath, sizeof(msmFbTypePath),
+ "/sys/class/graphics/fb%d/msm_fb_type", num);
+ displayDeviceFP = fopen(msmFbTypePath, "r");
+
+ if(displayDeviceFP){
+ fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE,
+ displayDeviceFP);
+
+ if(strncmp(fbType, strDtvPanel, strlen(strDtvPanel)) == 0) {
+ sDpyFbMap[DPY_EXTERNAL] = num;
+ } else if(strncmp(fbType, strWbPanel, strlen(strWbPanel)) == 0) {
+ sDpyFbMap[DPY_WRITEBACK] = num;
+ }
+
+ fclose(displayDeviceFP);
+ }
+ }
+
+ return 0;
+}
+
+bool Overlay::displayCommit(const int& fd) {
+ utils::Dim lRoi, rRoi;
+ return displayCommit(fd, lRoi, rRoi);
+}
+
+bool Overlay::displayCommit(const int& fd, const utils::Dim& lRoi,
+ const utils::Dim& rRoi) {
+ //Commit
+ struct mdp_display_commit info;
+ memset(&info, 0, sizeof(struct mdp_display_commit));
+ info.flags = MDP_DISPLAY_COMMIT_OVERLAY;
+ info.l_roi.x = lRoi.x;
+ info.l_roi.y = lRoi.y;
+ info.l_roi.w = lRoi.w;
+ info.l_roi.h = lRoi.h;
+ info.r_roi.x = rRoi.x;
+ info.r_roi.y = rRoi.y;
+ info.r_roi.w = rRoi.w;
+ info.r_roi.h = rRoi.h;
+
+ if(!mdp_wrapper::displayCommit(fd, info)) {
+ ALOGE("%s: commit failed", __func__);
+ return false;
+ }
+ return true;
+}
+
+void Overlay::getDump(char *buf, size_t len) {
+ int totalPipes = 0;
+ const char *str = "\nOverlay State\n\n";
+ strlcat(buf, str, len);
+ for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+ if(mPipeBook[i].valid()) {
+ mPipeBook[i].mPipe->getDump(buf, len);
+ char str[64] = {'\0'};
+ snprintf(str, 64, "Display=%d\n\n", mPipeBook[i].mDisplay);
+ strlcat(buf, str, len);
+ totalPipes++;
+ }
+ }
+ char str_pipes[64] = {'\0'};
+ snprintf(str_pipes, 64, "Pipes=%d\n\n", totalPipes);
+ strlcat(buf, str_pipes, len);
+}
+
+void Overlay::clear(int dpy) {
+ for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+ if (mPipeBook[i].mDisplay == dpy) {
+ // Mark as available for this round
+ PipeBook::resetUse(i);
+ PipeBook::resetAllocation(i);
+ if(getPipeId((utils::eDest)i) == -1) {
+ mPipeBook[i].destroy();
+ }
+ }
+ }
+}
+
+bool Overlay::validateAndSet(const int& dpy, const int& fbFd) {
+ GenericPipe* pipeArray[PipeBook::NUM_PIPES];
+ memset(pipeArray, 0, sizeof(GenericPipe*)*(PipeBook::NUM_PIPES));
+
+ int num = 0;
+ for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+ if(PipeBook::isUsed(i) && mPipeBook[i].valid() &&
+ mPipeBook[i].mDisplay == dpy) {
+ pipeArray[num++] = mPipeBook[i].mPipe;
+ }
+ }
+
+ //Protect against misbehaving clients
+ return num ? GenericPipe::validateAndSet(pipeArray, num, fbFd) : true;
+}
+
+void Overlay::initScalar() {
+ if(sLibScaleHandle == NULL) {
+ sLibScaleHandle = dlopen("libscale.so", RTLD_NOW);
+ if(sLibScaleHandle) {
+ *(void **) &sFnProgramScale =
+ dlsym(sLibScaleHandle, "programScale");
+ }
+ }
+}
+
+void Overlay::destroyScalar() {
+ if(sLibScaleHandle) {
+ dlclose(sLibScaleHandle);
+ sLibScaleHandle = NULL;
+ }
+}
+
+void Overlay::PipeBook::init() {
+ mPipe = NULL;
+ mDisplay = DPY_UNUSED;
+ mMixer = MIXER_UNUSED;
+ mFormatType = FORMAT_NONE;
+}
+
+void Overlay::PipeBook::destroy() {
+ if(mPipe) {
+ delete mPipe;
+ mPipe = NULL;
+ }
+ mDisplay = DPY_UNUSED;
+ mMixer = MIXER_UNUSED;
+ mFormatType = FORMAT_NONE;
+ mSession = NONE;
+}
+
+Overlay* Overlay::sInstance = 0;
+int Overlay::sDpyFbMap[DPY_MAX] = {0, -1, -1, -1};
+int Overlay::sDMAMode = DMA_LINE_MODE;
+bool Overlay::sDMAMultiplexingSupported = false;
+bool Overlay::sDebugPipeLifecycle = false;
+int Overlay::PipeBook::NUM_PIPES = 0;
+int Overlay::PipeBook::sPipeUsageBitmap = 0;
+int Overlay::PipeBook::sLastUsageBitmap = 0;
+int Overlay::PipeBook::sAllocatedBitmap = 0;
+utils::eMdpPipeType Overlay::PipeBook::pipeTypeLUT[utils::OV_MAX] =
+ {utils::OV_MDP_PIPE_ANY};
+void *Overlay::sLibScaleHandle = NULL;
+int (*Overlay::sFnProgramScale)(struct mdp_overlay_list *) = NULL;
+
+}; // namespace overlay
diff --git a/msm8909/liboverlay/overlay.h b/msm8909/liboverlay/overlay.h
new file mode 100644
index 0000000..5c93b23
--- /dev/null
+++ b/msm8909/liboverlay/overlay.h
@@ -0,0 +1,428 @@
+/*
+* Copyright (c) 2011-2013, The Linux Foundation. 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 The Linux Foundation. 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 "mdp_version.h"
+#include "utils/threads.h"
+
+struct MetaData_t;
+
+namespace overlay {
+class GenericPipe;
+
+class Overlay : utils::NoCopy {
+public:
+ enum { DMA_BLOCK_MODE, DMA_LINE_MODE };
+ //Abstract Display types. Each backed by a LayerMixer,
+ //represented by a fb node.
+ //High res panels can be backed by 2 layer mixers and a single fb node.
+ enum { DPY_PRIMARY, DPY_EXTERNAL, DPY_TERTIARY, DPY_WRITEBACK, DPY_UNUSED };
+ enum { DPY_MAX = DPY_UNUSED };
+ enum { MIXER_LEFT, MIXER_RIGHT, MIXER_UNUSED };
+ enum { MIXER_DEFAULT = MIXER_LEFT, MIXER_MAX = MIXER_UNUSED };
+ enum { MAX_FB_DEVICES = DPY_MAX };
+ enum { FORMAT_YUV, FORMAT_RGB , FORMAT_NONE };
+
+ struct PipeSpecs {
+ PipeSpecs() : formatClass(FORMAT_RGB), needsScaling(false), fb(false),
+ dpy(DPY_PRIMARY), mixer(MIXER_DEFAULT), numActiveDisplays(1) {}
+ int formatClass;
+ bool needsScaling;
+ bool fb;
+ int dpy;
+ int mixer;
+ int numActiveDisplays;
+ };
+
+ /* dtor close */
+ ~Overlay();
+
+ /* Marks the beginning of a drawing round, resets usage bits on pipes
+ * Should be called when drawing begins before any pipe config is done.
+ */
+ void configBegin();
+
+ /* Marks the end of config for this drawing round
+ * Will do garbage collection of pipe objects and thus calling UNSETs,
+ * closing FDs, removing rotator objects and memory, if allocated.
+ * Should be called after all pipe configs are done.
+ */
+ void configDone();
+
+ /* Get a pipe that supported the specified format class (yuv, rgb) and has
+ * scaling capabilities.
+ */
+ utils::eDest getPipe(const PipeSpecs& pipeSpecs);
+ /* Returns the eDest corresponding to an already allocated pipeid.
+ * Useful for the reservation case, when libvpu reserves the pipe at its
+ * end, and expect the overlay to allocate a given pipe for a layer.
+ */
+ utils::eDest reservePipe(int pipeid);
+ /* getting dest for the given pipeid */
+ utils::eDest getDest(int pipeid);
+ /* getting overlay.pipeid for the given dest */
+ int getPipeId(utils::eDest dest);
+
+ void setSource(const utils::PipeArgs args, utils::eDest dest);
+ void setCrop(const utils::Dim& d, utils::eDest dest);
+ void setColor(const uint32_t color, utils::eDest dest);
+ void setTransform(const int orientation, utils::eDest dest);
+ void setPosition(const utils::Dim& dim, utils::eDest dest);
+ void setVisualParams(const MetaData_t& data, utils::eDest dest);
+ bool commit(utils::eDest dest);
+ bool queueBuffer(int fd, uint32_t offset, utils::eDest dest);
+
+ /* pipe reservation session is running */
+ bool sessionInProgress(utils::eDest dest);
+ /* pipe reservation session has ended*/
+ bool isSessionEnded(utils::eDest dest);
+ /* start session for the pipe reservation */
+ void startSession(utils::eDest dest);
+ /* end all started sesisons */
+ void endAllSessions();
+ /* Returns available ("unallocated") pipes for a display's mixer */
+ int availablePipes(int dpy, int mixer);
+ /* Returns available ("unallocated") pipes for a display */
+ int availablePipes(int dpy);
+ /* Returns available ("unallocated") pipe of given type for a display */
+ int availablePipes(int dpy, utils::eMdpPipeType type);
+ /* Returns if any of the requested pipe type is attached to any of the
+ * displays
+ */
+ bool isPipeTypeAttached(utils::eMdpPipeType type);
+ /* Compare pipe priorities and return
+ * 1 if 1st pipe has a higher priority
+ * 0 if both have the same priority
+ *-1 if 2nd pipe has a higher priority
+ */
+ int comparePipePriority(utils::eDest pipe1Index, utils::eDest pipe2Index);
+ /* Returns pipe dump. Expects a NULL terminated buffer of big enough size
+ * to populate.
+ */
+ /* Returns if DMA pipe multiplexing is supported by the mdss driver */
+ static bool isDMAMultiplexingSupported();
+ /* Returns if UI scaling on external is supported on the targets */
+ static bool isUIScalingOnExternalSupported();
+ void getDump(char *buf, size_t len);
+ /* Reset usage and allocation bits on all pipes for given display */
+ void clear(int dpy);
+ /* Validate the set of pipes for a display and set them in driver */
+ bool validateAndSet(const int& dpy, const int& fbFd);
+
+ /* Closes open pipes, called during startup */
+ static int initOverlay();
+ /* Returns the singleton instance of overlay */
+ static Overlay* getInstance();
+ static void setDMAMode(const int& mode);
+ static int getDMAMode();
+ /* Returns the framebuffer node backing up the display */
+ static int getFbForDpy(const int& dpy);
+
+ static bool displayCommit(const int& fd);
+ /* Overloads display commit with ROI's of each halves.
+ * Single interface panels will only update left ROI. */
+ static bool displayCommit(const int& fd, const utils::Dim& lRoi,
+ const utils::Dim& rRoi);
+ /* Logs pipe lifecycle events like set, unset, commit when enabled */
+ static void debugPipeLifecycle(const bool& enable);
+ /* Returns true if pipe life cycle logging is enabled */
+ static bool isDebugPipeLifecycle();
+
+private:
+ /* Ctor setup */
+ explicit Overlay();
+ /*Validate index range, abort if invalid */
+ void validate(int index);
+ static void setDMAMultiplexingSupported();
+ /* Returns an available pipe based on the type of pipe requested. When ANY
+ * is requested, the first available VG or RGB is returned. If no pipe is
+ * available for the display "dpy" then INV is returned. Note: If a pipe is
+ * assigned to a certain display, then it cannot be assigned to another
+ * display without being garbage-collected once. To add if a pipe is
+ * asisgned to a mixer within a display it cannot be reused for another
+ * mixer without being UNSET once*/
+ utils::eDest nextPipe(utils::eMdpPipeType, const PipeSpecs& pipeSpecs);
+ /* Helpers that enfore target specific policies while returning pipes */
+ utils::eDest getPipe_8x26(const PipeSpecs& pipeSpecs);
+ utils::eDest getPipe_8x16(const PipeSpecs& pipeSpecs);
+ utils::eDest getPipe_8x39(const PipeSpecs& pipeSpecs);
+ utils::eDest getPipe_8994(const PipeSpecs& pipeSpecs);
+
+ /* Returns the handle to libscale.so's programScale function */
+ static int (*getFnProgramScale())(struct mdp_overlay_list *);
+ /* Creates a scalar object using libscale.so */
+ static void initScalar();
+ /* Destroys the scalar object using libscale.so */
+ static void destroyScalar();
+ /* Sets the pipe type RGB/VG/DMA*/
+ void setPipeType(utils::eDest pipeIndex, const utils::eMdpPipeType pType);
+
+ /* Just like a Facebook for pipes, but much less profile info */
+ struct PipeBook {
+ void init();
+ void destroy();
+ /* Check if pipe exists and return true, false otherwise */
+ bool valid();
+
+ /* Hardware pipe wrapper */
+ GenericPipe *mPipe;
+ /* Display using this pipe. Refer to enums above */
+ int mDisplay;
+ /* Mixer within a split display this pipe is attached to */
+ int mMixer;
+ /* Format for which this pipe is attached to the mixer*/
+ int mFormatType;
+
+ /* operations on bitmap */
+ static bool pipeUsageUnchanged();
+ static void setUse(int index);
+ static void resetUse(int index);
+ static bool isUsed(int index);
+ static bool isNotUsed(int index);
+ static void save();
+
+ static void setAllocation(int index);
+ static void resetAllocation(int index);
+ static bool isAllocated(int index);
+ static bool isNotAllocated(int index);
+
+ static utils::eMdpPipeType getPipeType(utils::eDest dest);
+ static const char* getDestStr(utils::eDest dest);
+
+ static int NUM_PIPES;
+ static utils::eMdpPipeType pipeTypeLUT[utils::OV_MAX];
+ /* Session for reserved pipes */
+ enum Session {
+ NONE,
+ START,
+ END
+ };
+ Session mSession;
+
+ private:
+ //usage tracks if a successful commit happened. So a pipe could be
+ //allocated to a display, but it may not end up using it for various
+ //reasons. If one display actually uses a pipe then it amy not be
+ //used by another display, without an UNSET in between.
+ static int sPipeUsageBitmap;
+ static int sLastUsageBitmap;
+ //Tracks which pipe objects are allocated. This does not imply that they
+ //will actually be used. For example, a display might choose to acquire
+ //3 pipe objects in one shot and proceed with config only if it gets all
+ //3. The bitmap helps allocate different pipe objects on each request.
+ static int sAllocatedBitmap;
+ };
+
+ PipeBook mPipeBook[utils::OV_INVALID]; //Used as max
+
+ /* Singleton Instance*/
+ static Overlay *sInstance;
+ static int sDpyFbMap[DPY_MAX];
+ static int sDMAMode;
+ static bool sDMAMultiplexingSupported;
+ static void *sLibScaleHandle;
+ static int (*sFnProgramScale)(struct mdp_overlay_list *);
+ static bool sDebugPipeLifecycle;
+
+ friend class MdpCtrl;
+};
+
+inline void Overlay::validate(int index) {
+ OVASSERT(index >=0 && index < PipeBook::NUM_PIPES, \
+ "%s, Index out of bounds: %d", __FUNCTION__, index);
+ OVASSERT(mPipeBook[index].valid(), "Pipe does not exist %s",
+ PipeBook::getDestStr((utils::eDest)index));
+}
+
+inline int Overlay::availablePipes(int dpy, int mixer) {
+ int avail = 0;
+ for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+ if( (mPipeBook[i].mDisplay == DPY_UNUSED ||
+ mPipeBook[i].mDisplay == dpy) &&
+ (mPipeBook[i].mMixer == MIXER_UNUSED ||
+ mPipeBook[i].mMixer == mixer) &&
+ PipeBook::isNotAllocated(i) &&
+ !(Overlay::getDMAMode() == Overlay::DMA_BLOCK_MODE &&
+ PipeBook::getPipeType((utils::eDest)i) ==
+ utils::OV_MDP_PIPE_DMA)) {
+ avail++;
+ }
+ }
+ return avail;
+}
+
+inline int Overlay::availablePipes(int dpy) {
+ int avail = 0;
+ for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+ if( (mPipeBook[i].mDisplay == DPY_UNUSED ||
+ mPipeBook[i].mDisplay == dpy) &&
+ PipeBook::isNotAllocated(i) &&
+ !(Overlay::getDMAMode() == Overlay::DMA_BLOCK_MODE &&
+ PipeBook::getPipeType((utils::eDest)i) ==
+ utils::OV_MDP_PIPE_DMA)) {
+ avail++;
+ }
+ }
+ return avail;
+}
+
+inline int Overlay::availablePipes(int dpy, utils::eMdpPipeType type) {
+ int avail = 0;
+ for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+ if((mPipeBook[i].mDisplay == DPY_UNUSED ||
+ mPipeBook[i].mDisplay == dpy) &&
+ PipeBook::isNotAllocated(i) &&
+ type == PipeBook::getPipeType((utils::eDest)i)) {
+ avail++;
+ }
+ }
+ return avail;
+}
+
+inline void Overlay::setDMAMode(const int& mode) {
+ if(mode == DMA_LINE_MODE || mode == DMA_BLOCK_MODE)
+ sDMAMode = mode;
+}
+
+inline void Overlay::setDMAMultiplexingSupported() {
+ sDMAMultiplexingSupported = false;
+ if(qdutils::MDPVersion::getInstance().is8x26())
+ sDMAMultiplexingSupported = true;
+}
+
+inline bool Overlay::isDMAMultiplexingSupported() {
+ return sDMAMultiplexingSupported;
+}
+
+inline bool Overlay::isUIScalingOnExternalSupported() {
+ if(qdutils::MDPVersion::getInstance().is8x26() or
+ qdutils::MDPVersion::getInstance().is8x16() or
+ qdutils::MDPVersion::getInstance().is8x39()) {
+ return false;
+ }
+ return true;
+}
+
+inline int Overlay::getDMAMode() {
+ return sDMAMode;
+}
+
+inline int Overlay::getFbForDpy(const int& dpy) {
+ OVASSERT(dpy >= 0 && dpy < DPY_MAX, "Invalid dpy %d", dpy);
+ return sDpyFbMap[dpy];
+}
+
+inline int (*Overlay::getFnProgramScale())(struct mdp_overlay_list *) {
+ return sFnProgramScale;
+}
+
+inline void Overlay::debugPipeLifecycle(const bool& enable) {
+ sDebugPipeLifecycle = enable;
+}
+
+inline bool Overlay::isDebugPipeLifecycle() {
+ return sDebugPipeLifecycle;
+}
+
+inline bool Overlay::PipeBook::valid() {
+ return (mPipe != NULL);
+}
+
+inline bool Overlay::PipeBook::pipeUsageUnchanged() {
+ return (sPipeUsageBitmap == sLastUsageBitmap);
+}
+
+inline void Overlay::PipeBook::setUse(int index) {
+ sPipeUsageBitmap |= (1 << index);
+}
+
+inline void Overlay::PipeBook::resetUse(int index) {
+ sPipeUsageBitmap &= ~(1 << index);
+}
+
+inline bool Overlay::PipeBook::isUsed(int index) {
+ return sPipeUsageBitmap & (1 << index);
+}
+
+inline bool Overlay::PipeBook::isNotUsed(int index) {
+ return !isUsed(index);
+}
+
+inline void Overlay::PipeBook::save() {
+ sLastUsageBitmap = sPipeUsageBitmap;
+}
+
+inline void Overlay::PipeBook::setAllocation(int index) {
+ sAllocatedBitmap |= (1 << index);
+}
+
+inline void Overlay::PipeBook::resetAllocation(int index) {
+ sAllocatedBitmap &= ~(1 << index);
+}
+
+inline bool Overlay::PipeBook::isAllocated(int index) {
+ return sAllocatedBitmap & (1 << index);
+}
+
+inline bool Overlay::PipeBook::isNotAllocated(int index) {
+ return !isAllocated(index);
+}
+
+inline utils::eMdpPipeType Overlay::PipeBook::getPipeType(utils::eDest dest) {
+ return pipeTypeLUT[(int)dest];
+}
+
+inline void Overlay::startSession(utils::eDest dest) {
+ mPipeBook[(int)dest].mSession = PipeBook::START;
+}
+
+inline bool Overlay::sessionInProgress(utils::eDest dest) {
+ return (mPipeBook[(int)dest].mSession == PipeBook::START);
+}
+
+inline bool Overlay::isSessionEnded(utils::eDest dest) {
+ return (mPipeBook[(int)dest].mSession == PipeBook::END);
+}
+
+inline const char* Overlay::PipeBook::getDestStr(utils::eDest dest) {
+ switch(getPipeType(dest)) {
+ case utils::OV_MDP_PIPE_RGB: return "RGB";
+ case utils::OV_MDP_PIPE_VG: return "VG";
+ case utils::OV_MDP_PIPE_DMA: return "DMA";
+ default: return "Invalid";
+ }
+ return "Invalid";
+}
+
+}; // overlay
+
+#endif // OVERLAY_H
diff --git a/msm8909/liboverlay/overlayCtrlData.h b/msm8909/liboverlay/overlayCtrlData.h
new file mode 100644
index 0000000..2eec98c
--- /dev/null
+++ b/msm8909/liboverlay/overlayCtrlData.h
@@ -0,0 +1,249 @@
+/*
+* Copyright (c) 2012-2013, The Linux Foundation. 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 The Linux Foundation 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 {
+
+/*
+* Sequence to use:
+* init
+* start
+* setXXX
+* close
+* */
+class Ctrl : utils::NoCopy {
+public:
+
+ /* ctor */
+ explicit Ctrl(const int& dpy);
+ /* dtor close */
+ ~Ctrl();
+
+ /* set source using whf, orient and wait flag */
+ void setSource(const utils::PipeArgs& args);
+ /* set crop info and pass it down to mdp */
+ void setCrop(const utils::Dim& d);
+ /* set color for mdp pipe */
+ void setColor(const uint32_t color);
+ /* set orientation */
+ void setTransform(const utils::eTransform& p);
+ /* set mdp position using dim */
+ void setPosition(const utils::Dim& dim);
+ /* set mdp visual params using metadata */
+ bool setVisualParams(const MetaData_t &metadata);
+ /* set pipe type RGB/DMA/VG */
+ void setPipeType(const utils::eMdpPipeType& pType);
+ /* mdp set overlay/commit changes */
+ bool commit();
+
+ /* ctrl id */
+ int getPipeId() const;
+ /* ctrl fd */
+ int getFd() const;
+ /* retrieve crop data */
+ utils::Dim getCrop() const;
+ utils::Dim getPosition() const;
+ /* Update the src format based on rotator's dest */
+ void updateSrcFormat(const uint32_t& rotDstFormat);
+ /* return pipe priority */
+ uint8_t getPriority() const;
+ /* dump the state of the object */
+ void dump() const;
+ /* Return the dump in the specified buffer */
+ void getDump(char *buf, size_t len);
+
+ static bool validateAndSet(Ctrl* ctrlArray[], const int& count,
+ const int& fbFd);
+private:
+ // mdp ctrl struct(info e.g.)
+ MdpCtrl *mMdp;
+};
+
+
+class Data : utils::NoCopy {
+public:
+ /* init, reset */
+ explicit Data(const int& dpy);
+ /* calls close */
+ ~Data();
+ /* set overlay pipe id in the mdp struct */
+ void setPipeId(int id);
+ /* get overlay id in the mdp struct */
+ int getPipeId() const;
+ /* queue buffer to the overlay */
+ bool queueBuffer(int fd, uint32_t offset);
+ /* sump the state of the obj */
+ void dump() const;
+ /* Return the dump in the specified buffer */
+ void getDump(char *buf, size_t len);
+
+private:
+ // mdp data struct
+ MdpData *mMdp;
+};
+
+//-------------Inlines-------------------------------
+
+inline Ctrl::Ctrl(const int& dpy) : mMdp(new MdpCtrl(dpy)) {
+}
+
+inline Ctrl::~Ctrl() {
+ delete mMdp;
+}
+
+inline void Ctrl::setSource(const utils::PipeArgs& args)
+{
+ mMdp->setSource(args);
+}
+
+inline void Ctrl::setPosition(const utils::Dim& dim)
+{
+ mMdp->setPosition(dim);
+}
+
+inline void Ctrl::setTransform(const utils::eTransform& orient)
+{
+ mMdp->setTransform(orient);
+}
+
+inline void Ctrl::setCrop(const utils::Dim& d)
+{
+ mMdp->setCrop(d);
+}
+
+inline void Ctrl::setColor(const uint32_t color)
+{
+ mMdp->setColor(color);
+}
+
+inline bool Ctrl::setVisualParams(const MetaData_t &metadata)
+{
+ if (!mMdp->setVisualParams(metadata)) {
+ ALOGE("Ctrl setVisualParams failed in MDP setVisualParams");
+ return false;
+ }
+ return true;
+}
+
+inline void Ctrl::setPipeType(const utils::eMdpPipeType& pType)
+{
+ mMdp->setPipeType(pType);
+}
+
+inline void Ctrl::dump() const {
+ ALOGE("== Dump Ctrl start ==");
+ mMdp->dump();
+ ALOGE("== Dump Ctrl end ==");
+}
+
+inline bool Ctrl::commit() {
+ if(!mMdp->set()) {
+ ALOGE("Ctrl commit failed set overlay");
+ return false;
+ }
+ return true;
+}
+
+inline int Ctrl::getPipeId() const {
+ return mMdp->getPipeId();
+}
+
+inline int Ctrl::getFd() const {
+ return mMdp->getFd();
+}
+
+inline void Ctrl::updateSrcFormat(const uint32_t& rotDstFmt) {
+ mMdp->updateSrcFormat(rotDstFmt);
+}
+
+inline bool Ctrl::validateAndSet(Ctrl* ctrlArray[], const int& count,
+ const int& fbFd) {
+ MdpCtrl* mdpCtrlArray[count];
+ memset(&mdpCtrlArray, 0, sizeof(mdpCtrlArray));
+
+ for(int i = 0; i < count; i++) {
+ mdpCtrlArray[i] = ctrlArray[i]->mMdp;
+ }
+
+ bool ret = MdpCtrl::validateAndSet(mdpCtrlArray, count, fbFd);
+ return ret;
+}
+
+inline utils::Dim Ctrl::getCrop() const {
+ return mMdp->getSrcRectDim();
+}
+
+inline utils::Dim Ctrl::getPosition() const {
+ return mMdp->getDstRectDim();
+}
+
+inline uint8_t Ctrl::getPriority() const {
+ return mMdp->getPriority();
+}
+
+inline void Ctrl::getDump(char *buf, size_t len) {
+ mMdp->getDump(buf, len);
+}
+
+inline Data::Data(const int& dpy) : mMdp(new MdpData(dpy)) {
+}
+
+inline Data::~Data() {
+ delete mMdp;
+}
+
+inline void Data::setPipeId(int id) { mMdp->setPipeId(id); }
+
+inline int Data::getPipeId() const { return mMdp->getPipeId(); }
+
+inline bool Data::queueBuffer(int fd, uint32_t offset) {
+ return mMdp->play(fd, offset);
+}
+
+inline void Data::dump() const {
+ ALOGE("== Dump Data MDP start ==");
+ mMdp->dump();
+ ALOGE("== Dump Data MDP end ==");
+}
+
+inline void Data::getDump(char *buf, size_t len) {
+ mMdp->getDump(buf, len);
+}
+
+} // overlay
+
+#endif
diff --git a/msm8909/liboverlay/overlayMdp.cpp b/msm8909/liboverlay/overlayMdp.cpp
new file mode 100644
index 0000000..ee8d762
--- /dev/null
+++ b/msm8909/liboverlay/overlayMdp.cpp
@@ -0,0 +1,397 @@
+/*
+* Copyright (C) 2008 The Android Open Source Project
+* Copyright (c) 2010-2014, The Linux Foundation. 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 <math.h>
+#include <mdp_version.h>
+#include "overlayUtils.h"
+#include "overlayMdp.h"
+#include "mdp_version.h"
+#include <overlay.h>
+
+#define HSIC_SETTINGS_DEBUG 0
+
+using namespace qdutils;
+
+static inline bool isEqual(float f1, float f2) {
+ return ((int)(f1*100) == (int)(f2*100)) ? true : false;
+}
+
+namespace ovutils = overlay::utils;
+namespace overlay {
+
+bool MdpCtrl::init(const int& dpy) {
+ int fbnum = Overlay::getFbForDpy(dpy);
+ if( fbnum < 0 ) {
+ ALOGE("%s: Invalid FB for the display: %d",__FUNCTION__, dpy);
+ return false;
+ }
+
+ // FD init
+ if(!utils::openDev(mFd, fbnum,
+ Res::fbPath, O_RDWR)){
+ ALOGE("Ctrl failed to init fbnum=%d", fbnum);
+ return false;
+ }
+ mDpy = dpy;
+ return true;
+}
+
+void MdpCtrl::reset() {
+ utils::memset0(mOVInfo);
+ mOVInfo.id = MSMFB_NEW_REQUEST;
+ mOrientation = utils::OVERLAY_TRANSFORM_0;
+ mDpy = 0;
+#ifdef USES_POST_PROCESSING
+ memset(&mParams, 0, sizeof(struct compute_params));
+ mParams.params.conv_params.order = hsic_order_hsc_i;
+ mParams.params.conv_params.interface = interface_rec601;
+ mParams.params.conv_params.cc_matrix[0][0] = 1;
+ mParams.params.conv_params.cc_matrix[1][1] = 1;
+ mParams.params.conv_params.cc_matrix[2][2] = 1;
+#endif
+}
+
+bool MdpCtrl::close() {
+ bool result = true;
+ if(MSMFB_NEW_REQUEST != static_cast<int>(mOVInfo.id)) {
+ if(!mdp_wrapper::unsetOverlay(mFd.getFD(), mOVInfo.id)) {
+ ALOGE("MdpCtrl close error in unset");
+ result = false;
+ }
+ }
+#ifdef USES_POST_PROCESSING
+ /* free allocated memory in PP */
+ if (mOVInfo.overlay_pp_cfg.igc_cfg.c0_c1_data)
+ free(mOVInfo.overlay_pp_cfg.igc_cfg.c0_c1_data);
+#endif
+ reset();
+
+ if(!mFd.close()) {
+ result = false;
+ }
+
+ return result;
+}
+
+void MdpCtrl::setSource(const utils::PipeArgs& args) {
+ setSrcWhf(args.whf);
+
+ //TODO These are hardcoded. Can be moved out of setSource.
+ mOVInfo.transp_mask = 0xffffffff;
+
+ //TODO These calls should ideally be a part of setPipeParams API
+ setFlags(args.mdpFlags);
+ setZ(args.zorder);
+ setPlaneAlpha(args.planeAlpha);
+ setBlending(args.blending);
+}
+
+void MdpCtrl::setCrop(const utils::Dim& d) {
+ setSrcRectDim(d);
+}
+
+void MdpCtrl::setColor(const uint32_t color) {
+ mOVInfo.bg_color = color;
+}
+
+void MdpCtrl::setPosition(const overlay::utils::Dim& d) {
+ setDstRectDim(d);
+}
+
+void MdpCtrl::setTransform(const utils::eTransform& orient) {
+ int rot = utils::getMdpOrient(orient);
+ setUserData(rot);
+ mOrientation = static_cast<utils::eTransform>(rot);
+}
+
+void MdpCtrl::setPipeType(const utils::eMdpPipeType& pType){
+ switch((int) pType){
+ case utils::OV_MDP_PIPE_RGB:
+ mOVInfo.pipe_type = PIPE_TYPE_RGB;
+ break;
+ case utils::OV_MDP_PIPE_VG:
+ mOVInfo.pipe_type = PIPE_TYPE_VIG;
+ break;
+ case utils::OV_MDP_PIPE_DMA:
+ mOVInfo.pipe_type = PIPE_TYPE_DMA;
+ break;
+ default:
+ mOVInfo.pipe_type = PIPE_TYPE_AUTO;
+ break;
+ }
+}
+
+void MdpCtrl::doTransform() {
+ setRotationFlags();
+ utils::Whf whf = getSrcWhf();
+ utils::Dim dim = getSrcRectDim();
+ utils::preRotateSource(mOrientation, whf, dim);
+ setSrcWhf(whf);
+ setSrcRectDim(dim);
+}
+
+void MdpCtrl::doDownscale() {
+ if(MDPVersion::getInstance().supportsDecimation()) {
+ utils::getDecimationFactor(mOVInfo.src_rect.w, mOVInfo.src_rect.h,
+ mOVInfo.dst_rect.w, mOVInfo.dst_rect.h, mOVInfo.horz_deci,
+ mOVInfo.vert_deci);
+ }
+}
+
+bool MdpCtrl::set() {
+ int mdpVersion = MDPVersion::getInstance().getMDPVersion();
+ //deferred calcs, so APIs could be called in any order.
+ doTransform();
+ utils::Whf whf = getSrcWhf();
+ if(utils::isYuv(whf.format)) {
+ utils::normalizeCrop(mOVInfo.src_rect.x, mOVInfo.src_rect.w);
+ utils::normalizeCrop(mOVInfo.src_rect.y, mOVInfo.src_rect.h);
+ if(mdpVersion < MDSS_V5) {
+ utils::even_floor(mOVInfo.dst_rect.w);
+ utils::even_floor(mOVInfo.dst_rect.h);
+ } else if (mOVInfo.flags & MDP_DEINTERLACE) {
+ // For interlaced, crop.h should be 4-aligned
+ if (!(mOVInfo.flags & MDP_SOURCE_ROTATED_90) &&
+ (mOVInfo.src_rect.h % 4))
+ mOVInfo.src_rect.h = utils::aligndown(mOVInfo.src_rect.h, 4);
+ // For interlaced, width must be multiple of 4 when rotated 90deg.
+ else if ((mOVInfo.flags & MDP_SOURCE_ROTATED_90) &&
+ (mOVInfo.src_rect.w % 4))
+ mOVInfo.src_rect.w = utils::aligndown(mOVInfo.src_rect.w, 4);
+ }
+ } else {
+ // On 8974 and 8x26, there is a limitation of 1-pixel down-scaling
+ if (mdpVersion >= MDSS_V5) {
+ if(qdutils::MDPVersion::getInstance().is8x74v2() ||
+ qdutils::MDPVersion::getInstance().is8x26()) {
+ if (mOVInfo.src_rect.w - mOVInfo.dst_rect.w == 1)
+ mOVInfo.src_rect.w -= 1;
+ if (mOVInfo.src_rect.h - mOVInfo.dst_rect.h == 1)
+ mOVInfo.src_rect.h -= 1;
+ }
+ }
+ }
+
+ doDownscale();
+ return true;
+}
+
+//Update src format based on rotator's destination format.
+void MdpCtrl::updateSrcFormat(const uint32_t& rotDestFmt) {
+ utils::Whf whf = getSrcWhf();
+ whf.format = rotDestFmt;
+ setSrcWhf(whf);
+}
+
+void MdpCtrl::dump() const {
+ ALOGE("== Dump MdpCtrl start ==");
+ mFd.dump();
+ mdp_wrapper::dump("mOVInfo", mOVInfo);
+ ALOGE("== Dump MdpCtrl end ==");
+}
+
+void MdpCtrl::getDump(char *buf, size_t len) {
+ ovutils::getDump(buf, len, "Ctrl", mOVInfo);
+}
+
+void MdpData::dump() const {
+ ALOGE("== Dump MdpData start ==");
+ mFd.dump();
+ mdp_wrapper::dump("mOvData", mOvData);
+ ALOGE("== Dump MdpData end ==");
+}
+
+void MdpData::getDump(char *buf, size_t len) {
+ ovutils::getDump(buf, len, "Data", mOvData);
+}
+
+bool MdpCtrl::setVisualParams(const MetaData_t& data) {
+ ALOGD_IF(0, "In %s: data.operation = %d", __FUNCTION__, data.operation);
+
+ // Set Color Space for MDP to configure CSC matrix
+ mOVInfo.color_space = ITU_R_601;
+ if (data.operation & UPDATE_COLOR_SPACE) {
+ mOVInfo.color_space = data.colorSpace;
+ }
+
+#ifdef USES_POST_PROCESSING
+ bool needUpdate = false;
+ /* calculate the data */
+ if (data.operation & PP_PARAM_HSIC) {
+ if (mParams.params.pa_params.hue != data.hsicData.hue) {
+ ALOGD_IF(HSIC_SETTINGS_DEBUG,
+ "Hue has changed from %d to %d",
+ mParams.params.pa_params.hue,data.hsicData.hue);
+ needUpdate = true;
+ }
+
+ if (!isEqual(mParams.params.pa_params.sat,
+ data.hsicData.saturation)) {
+ ALOGD_IF(HSIC_SETTINGS_DEBUG,
+ "Saturation has changed from %f to %f",
+ mParams.params.pa_params.sat,
+ data.hsicData.saturation);
+ needUpdate = true;
+ }
+
+ if (mParams.params.pa_params.intensity != data.hsicData.intensity) {
+ ALOGD_IF(HSIC_SETTINGS_DEBUG,
+ "Intensity has changed from %d to %d",
+ mParams.params.pa_params.intensity,
+ data.hsicData.intensity);
+ needUpdate = true;
+ }
+
+ if (!isEqual(mParams.params.pa_params.contrast,
+ data.hsicData.contrast)) {
+ ALOGD_IF(HSIC_SETTINGS_DEBUG,
+ "Contrast has changed from %f to %f",
+ mParams.params.pa_params.contrast,
+ data.hsicData.contrast);
+ needUpdate = true;
+ }
+
+ if (needUpdate) {
+ mParams.params.pa_params.hue = data.hsicData.hue;
+ mParams.params.pa_params.sat = data.hsicData.saturation;
+ mParams.params.pa_params.intensity = data.hsicData.intensity;
+ mParams.params.pa_params.contrast = data.hsicData.contrast;
+ mParams.params.pa_params.ops = MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE;
+ mParams.operation |= PP_OP_PA;
+ }
+ }
+
+ if (data.operation & PP_PARAM_SHARP2) {
+ if (mParams.params.sharp_params.strength != data.Sharp2Data.strength) {
+ needUpdate = true;
+ }
+ if (mParams.params.sharp_params.edge_thr != data.Sharp2Data.edge_thr) {
+ needUpdate = true;
+ }
+ if (mParams.params.sharp_params.smooth_thr !=
+ data.Sharp2Data.smooth_thr) {
+ needUpdate = true;
+ }
+ if (mParams.params.sharp_params.noise_thr !=
+ data.Sharp2Data.noise_thr) {
+ needUpdate = true;
+ }
+
+ if (needUpdate) {
+ mParams.params.sharp_params.strength = data.Sharp2Data.strength;
+ mParams.params.sharp_params.edge_thr = data.Sharp2Data.edge_thr;
+ mParams.params.sharp_params.smooth_thr =
+ data.Sharp2Data.smooth_thr;
+ mParams.params.sharp_params.noise_thr = data.Sharp2Data.noise_thr;
+ mParams.params.sharp_params.ops =
+ MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE;
+ mParams.operation |= PP_OP_SHARP;
+ }
+ }
+
+ if (data.operation & PP_PARAM_IGC) {
+ if (mOVInfo.overlay_pp_cfg.igc_cfg.c0_c1_data == NULL){
+ uint32_t *igcData
+ = (uint32_t *)malloc(2 * MAX_IGC_LUT_ENTRIES * sizeof(uint32_t));
+ if (!igcData) {
+ ALOGE("IGC storage allocated failed");
+ return false;
+ }
+ mOVInfo.overlay_pp_cfg.igc_cfg.c0_c1_data = igcData;
+ mOVInfo.overlay_pp_cfg.igc_cfg.c2_data
+ = igcData + MAX_IGC_LUT_ENTRIES;
+ }
+
+ memcpy(mParams.params.igc_lut_params.c0,
+ data.igcData.c0, sizeof(uint16_t) * MAX_IGC_LUT_ENTRIES);
+ memcpy(mParams.params.igc_lut_params.c1,
+ data.igcData.c1, sizeof(uint16_t) * MAX_IGC_LUT_ENTRIES);
+ memcpy(mParams.params.igc_lut_params.c2,
+ data.igcData.c2, sizeof(uint16_t) * MAX_IGC_LUT_ENTRIES);
+
+ mParams.params.igc_lut_params.ops
+ = MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE;
+ mParams.operation |= PP_OP_IGC;
+ needUpdate = true;
+ }
+
+ if (data.operation & PP_PARAM_VID_INTFC) {
+ mParams.params.conv_params.interface =
+ (interface_type) data.video_interface;
+ needUpdate = true;
+ }
+
+ if (needUpdate) {
+ display_pp_compute_params(&mParams, &mOVInfo.overlay_pp_cfg);
+ }
+#endif
+ return true;
+}
+
+bool MdpCtrl::validateAndSet(MdpCtrl* mdpCtrlArray[], const int& count,
+ const int& fbFd) {
+ mdp_overlay* ovArray[count];
+ memset(&ovArray, 0, sizeof(ovArray));
+
+ for(int i = 0; i < count; i++) {
+ ovArray[i] = &mdpCtrlArray[i]->mOVInfo;
+ }
+
+ struct mdp_overlay_list list;
+ memset(&list, 0, sizeof(struct mdp_overlay_list));
+ list.num_overlays = count;
+ list.overlay_list = ovArray;
+
+ int (*fnProgramScale)(struct mdp_overlay_list *) =
+ Overlay::getFnProgramScale();
+ if(fnProgramScale) {
+ fnProgramScale(&list);
+ }
+
+ // Error value is based on file errno-base.h
+ // 0 - indicates no error.
+ int errVal = mdp_wrapper::validateAndSet(fbFd, list);
+ if(errVal) {
+ /* No dump for failure due to insufficient resource */
+ if(errVal != E2BIG) {
+ mdp_wrapper::dump("Bad ov dump: ",
+ *list.overlay_list[list.processed_overlays]);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+
+//// MdpData ////////////
+bool MdpData::init(const int& dpy) {
+ int fbnum = Overlay::getFbForDpy(dpy);
+ if( fbnum < 0 ) {
+ ALOGE("%s: Invalid FB for the display: %d",__FUNCTION__, dpy);
+ return false;
+ }
+
+ // FD init
+ if(!utils::openDev(mFd, fbnum, Res::fbPath, O_RDWR)){
+ ALOGE("Ctrl failed to init fbnum=%d", fbnum);
+ return false;
+ }
+ return true;
+}
+
+} // overlay
diff --git a/msm8909/liboverlay/overlayMdp.h b/msm8909/liboverlay/overlayMdp.h
new file mode 100644
index 0000000..d415b9d
--- /dev/null
+++ b/msm8909/liboverlay/overlayMdp.h
@@ -0,0 +1,317 @@
+/*
+* Copyright (C) 2008 The Android Open Source Project
+* Copyright (c) 2010-2013, The Linux Foundation. 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 <linux/msm_mdp.h>
+
+#include "overlayUtils.h"
+#include "mdpWrapper.h"
+#include "qdMetaData.h"
+#ifdef USES_POST_PROCESSING
+#include "lib-postproc.h"
+#endif
+
+namespace overlay{
+
+/*
+* Mdp Ctrl holds corresponding fd and MDP related struct.
+* It is simple wrapper to MDP services
+* */
+class MdpCtrl {
+public:
+ /* ctor reset */
+ explicit MdpCtrl(const int& dpy);
+ /* dtor close */
+ ~MdpCtrl();
+ /* init underlying device using fbnum for dpy */
+ bool init(const int& dpy);
+ /* unset overlay, reset and close fd */
+ bool close();
+ /* reset and set ov id to -1 / MSMFB_NEW_REQUEST */
+ void reset();
+ /* 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();
+ /* Sets the source total width, height, format */
+ void setSource(const utils::PipeArgs& pargs);
+ /*
+ * Sets ROI, the unpadded region, for source buffer.
+ * Dim - ROI dimensions.
+ */
+ void setCrop(const utils::Dim& d);
+ /* set color for mdp pipe */
+ void setColor(const uint32_t color);
+ void setTransform(const utils::eTransform& orient);
+ /* given a dim and w/h, set overlay dim */
+ void setPosition(const utils::Dim& dim);
+ /* using user_data, sets/unsets roationvalue in mdp flags */
+ void setRotationFlags();
+ /* Update the src format with rotator's dest*/
+ void updateSrcFormat(const uint32_t& rotDstFormat);
+ /* dump state of the object */
+ void dump() const;
+ /* Return the dump in the specified buffer */
+ void getDump(char *buf, size_t len);
+ /* returns session id */
+ int getPipeId() const;
+ /* returns the fd associated to ctrl*/
+ int getFd() const;
+ /* returns a copy ro dst rect dim */
+ utils::Dim getDstRectDim() const;
+ /* returns a copy to src rect dim */
+ utils::Dim getSrcRectDim() const;
+ /* return pipe priority */
+ uint8_t getPriority() const;
+ /* setVisualParam */
+ bool setVisualParams(const MetaData_t& data);
+ /* sets pipe type RGB/DMA/VG */
+ void setPipeType(const utils::eMdpPipeType& pType);
+
+ static bool validateAndSet(MdpCtrl* mdpCtrlArray[], const int& count,
+ const int& fbFd);
+private:
+ /* Perform transformation calculations */
+ void doTransform();
+ void doDownscale();
+ /* get orient / user_data[0] */
+ int getOrient() const;
+ /* returns flags from mdp structure */
+ int getFlags() const;
+ /* set flags to mdp structure */
+ void setFlags(int f);
+ /* set z order */
+ void setZ(utils::eZorder z);
+ /* return a copy of src whf*/
+ utils::Whf getSrcWhf() const;
+ /* set plane alpha */
+ void setPlaneAlpha(int planeAlpha);
+ /* set blending method */
+ void setBlending(overlay::utils::eBlending blending);
+
+ /* set src whf */
+ void setSrcWhf(const utils::Whf& whf);
+ /* set src/dst rect dim */
+ void setSrcRectDim(const utils::Dim d);
+ void setDstRectDim(const utils::Dim d);
+ /* returns user_data[0]*/
+ int getUserData() const;
+ /* sets user_data[0] */
+ void setUserData(int v);
+
+ utils::eTransform mOrientation; //Holds requested orientation
+ /* Actual overlay mdp structure */
+ mdp_overlay mOVInfo;
+ /* FD for the mdp fbnum */
+ OvFD mFd;
+ int mDpy;
+
+#ifdef USES_POST_PROCESSING
+ /* PP Compute Params */
+ struct compute_params mParams;
+#endif
+};
+
+/* MDP data */
+class MdpData {
+public:
+ /* ctor reset data */
+ explicit MdpData(const int& dpy);
+ /* dtor close*/
+ ~MdpData();
+ /* init FD */
+ bool init(const int& dpy);
+ /* memset0 the underlying mdp object */
+ void reset();
+ /* close fd, and reset */
+ bool close();
+ /* set id of mdp data */
+ void setPipeId(int id);
+ /* return ses id of data */
+ int getPipeId() const;
+ /* get underlying fd*/
+ int getFd() const;
+ /* get memory_id */
+ int getSrcMemoryId() const;
+ /* calls wrapper play */
+ bool play(int fd, uint32_t offset);
+ /* dump state of the object */
+ void dump() const;
+ /* Return the dump in the specified buffer */
+ void getDump(char *buf, size_t len);
+
+private:
+
+ /* actual overlay mdp data */
+ msmfb_overlay_data mOvData;
+ /* fd to mdp fbnum */
+ OvFD mFd;
+};
+
+//--------------Inlines---------------------------------
+
+///// MdpCtrl //////
+
+inline MdpCtrl::MdpCtrl(const int& dpy) {
+ reset();
+ init(dpy);
+}
+
+inline MdpCtrl::~MdpCtrl() {
+ close();
+}
+
+inline int MdpCtrl::getOrient() const {
+ return getUserData();
+}
+
+inline int MdpCtrl::getPipeId() 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::setPlaneAlpha(int planeAlpha) {
+ mOVInfo.alpha = planeAlpha;
+}
+
+inline void MdpCtrl::setBlending(overlay::utils::eBlending blending) {
+ switch((int) blending) {
+ case utils::OVERLAY_BLENDING_OPAQUE:
+ mOVInfo.blend_op = BLEND_OP_OPAQUE;
+ break;
+ case utils::OVERLAY_BLENDING_PREMULT:
+ mOVInfo.blend_op = BLEND_OP_PREMULTIPLIED;
+ break;
+ case utils::OVERLAY_BLENDING_COVERAGE:
+ default:
+ mOVInfo.blend_op = BLEND_OP_COVERAGE;
+ }
+}
+
+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)
+ mOVInfo.flags |= MDP_SOURCE_ROTATED_90;
+}
+
+inline uint8_t MdpCtrl::getPriority() const {
+ return mOVInfo.priority;
+}
+
+/////// MdpData //////
+
+inline MdpData::MdpData(const int& dpy) {
+ reset();
+ init(dpy);
+}
+
+inline MdpData::~MdpData() { close(); }
+
+inline void MdpData::reset() {
+ overlay::utils::memset0(mOvData);
+ mOvData.data.memory_id = -1;
+}
+
+inline bool MdpData::close() {
+ reset();
+ return mFd.close();
+}
+
+inline int MdpData::getSrcMemoryId() const { return mOvData.data.memory_id; }
+
+inline void MdpData::setPipeId(int id) { mOvData.id = id; }
+
+inline int MdpData::getPipeId() const { return mOvData.id; }
+
+inline int MdpData::getFd() const { return mFd.getFD(); }
+
+inline bool MdpData::play(int fd, uint32_t offset) {
+ mOvData.data.memory_id = fd;
+ mOvData.data.offset = offset;
+ if(!mdp_wrapper::play(mFd.getFD(), mOvData)){
+ ALOGE("MdpData failed to play");
+ dump();
+ return false;
+ }
+ return true;
+}
+
+} // overlay
+
+#endif // OVERLAY_MDP_H
diff --git a/msm8909/liboverlay/overlayMdpRot.cpp b/msm8909/liboverlay/overlayMdpRot.cpp
new file mode 100755
index 0000000..d322897
--- /dev/null
+++ b/msm8909/liboverlay/overlayMdpRot.cpp
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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 <math.h>
+#include "overlayUtils.h"
+#include "overlayRotator.h"
+#include "gr.h"
+
+namespace ovutils = overlay::utils;
+
+namespace overlay {
+
+MdpRot::MdpRot() {
+ reset();
+ init();
+}
+
+MdpRot::~MdpRot() { close(); }
+
+bool MdpRot::enabled() const { return mRotImgInfo.enable; }
+
+void MdpRot::setRotations(uint32_t r) { mRotImgInfo.rotations = (uint8_t)r; }
+
+int MdpRot::getSrcMemId() const {
+ return mRotDataInfo.src.memory_id;
+}
+
+int MdpRot::getDstMemId() const {
+ return mRotDataInfo.dst.memory_id;
+}
+
+uint32_t MdpRot::getSrcOffset() const {
+ return mRotDataInfo.src.offset;
+}
+
+uint32_t MdpRot::getDstOffset() const {
+ return mRotDataInfo.dst.offset;
+}
+
+uint32_t MdpRot::getDstFormat() const {
+ return mRotImgInfo.dst.format;
+}
+
+//Added for completeness. Not expected to be called.
+utils::Whf MdpRot::getDstWhf() const {
+ int alW = 0, alH = 0;
+ int halFormat = ovutils::getHALFormat(mRotImgInfo.dst.format);
+ getBufferSizeAndDimensions(mRotImgInfo.dst.width, mRotImgInfo.dst.height,
+ halFormat, alW, alH);
+ return utils::Whf(alW, alH, mRotImgInfo.dst.format);
+}
+
+//Added for completeness. Not expected to be called.
+utils::Dim MdpRot::getDstDimensions() const {
+ int alW = 0, alH = 0;
+ int halFormat = ovutils::getHALFormat(mRotImgInfo.dst.format);
+ getBufferSizeAndDimensions(mRotImgInfo.dst.width, mRotImgInfo.dst.height,
+ halFormat, alW, alH);
+ return utils::Dim(0, 0, alW, alH);
+}
+
+uint32_t MdpRot::getSessId() const { return mRotImgInfo.session_id; }
+
+void MdpRot::setDownscale(int ds) {
+ if ((utils::ROT_DS_EIGHTH == ds) && (mRotImgInfo.src_rect.h & 0xF)) {
+ // Ensure src_rect.h is a multiple of 16 for 1/8 downscaling.
+ // This is an undocumented MDP Rotator constraint.
+ mRotImgInfo.src_rect.h = utils::aligndown(mRotImgInfo.src_rect.h, 16);
+ }
+ mRotImgInfo.downscale_ratio = ds;
+}
+
+void MdpRot::save() {
+ mLSRotImgInfo = mRotImgInfo;
+}
+
+bool MdpRot::rotConfChanged() const {
+ // 0 means same
+ if(0 == ::memcmp(&mRotImgInfo, &mLSRotImgInfo,
+ sizeof (msm_rotator_img_info))) {
+ return false;
+ }
+ return true;
+}
+
+bool MdpRot::init()
+{
+ if(!mFd.open(Res::rotPath, O_RDWR)){
+ ALOGE("MdpRot failed to init %s", Res::rotPath);
+ return false;
+ }
+ return true;
+}
+
+void MdpRot::setSource(const overlay::utils::Whf& awhf) {
+ utils::Whf whf(awhf);
+ 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;
+}
+
+void MdpRot::setCrop(const utils::Dim& /*crop*/) {
+ // NO-OP for non-mdss rotator due to possible h/w limitations
+}
+
+void MdpRot::setFlags(const utils::eMdpFlags& flags) {
+ mRotImgInfo.secure = 0;
+ if(flags & utils::OV_MDP_SECURE_OVERLAY_SESSION)
+ mRotImgInfo.secure = 1;
+}
+
+void MdpRot::setTransform(const utils::eTransform& rot)
+{
+ int r = utils::getMdpOrient(rot);
+ setRotations(r);
+ mOrientation = static_cast<utils::eTransform>(r);
+ ALOGE_IF(DEBUG_OVERLAY, "%s: r=%d", __FUNCTION__, r);
+}
+
+void MdpRot::doTransform() {
+ if(mOrientation & utils::OVERLAY_TRANSFORM_ROT_90)
+ utils::swap(mRotImgInfo.dst.width, mRotImgInfo.dst.height);
+}
+
+bool MdpRot::commit() {
+ doTransform();
+ if(rotConfChanged()) {
+ mRotImgInfo.enable = 1;
+ if(!overlay::mdp_wrapper::startRotator(mFd.getFD(), mRotImgInfo)) {
+ ALOGE("MdpRot commit failed");
+ dump();
+ mRotImgInfo.enable = 0;
+ return false;
+ }
+ mRotDataInfo.session_id = mRotImgInfo.session_id;
+ }
+ return true;
+}
+
+uint32_t MdpRot::calcOutputBufSize() {
+ ovutils::Whf destWhf(mRotImgInfo.dst.width,
+ mRotImgInfo.dst.height, mRotImgInfo.dst.format);
+ return Rotator::calcOutputBufSize(destWhf);
+}
+
+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, mRotImgInfo.secure)){
+ ALOGE("%s: Failed to open", __func__);
+ mem.close();
+ return false;
+ }
+
+ OVASSERT(MAP_FAILED != mem.addr(), "MAP failed");
+ OVASSERT(mem.getFD() != -1, "getFd is -1");
+
+ mRotDataInfo.dst.memory_id = mem.getFD();
+ mRotDataInfo.dst.offset = 0;
+ mMem.mem = mem;
+ return true;
+}
+
+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=%u",
+ 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::remap(uint32_t numbufs) {
+ // if current size changed, remap
+ uint32_t opBufSize = calcOutputBufSize();
+ if(opBufSize == mMem.size()) {
+ ALOGE_IF(DEBUG_OVERLAY, "%s: same size %d", __FUNCTION__, opBufSize);
+ return true;
+ }
+
+ if(!mMem.close()) {
+ ALOGE("%s error in closing prev rot mem", __FUNCTION__);
+ return false;
+ }
+
+ ALOGE_IF(DEBUG_OVERLAY, "%s: size changed - remapping", __FUNCTION__);
+
+ if(!open_i(numbufs, opBufSize)) {
+ ALOGE("%s Error could not open", __FUNCTION__);
+ return false;
+ }
+
+ for (uint32_t i = 0; i < numbufs; ++i) {
+ mMem.mRotOffset[i] = i * opBufSize;
+ }
+
+ return true;
+}
+
+void MdpRot::reset() {
+ ovutils::memset0(mRotImgInfo);
+ ovutils::memset0(mLSRotImgInfo);
+ ovutils::memset0(mRotDataInfo);
+ ovutils::memset0(mMem.mRotOffset);
+ mMem.mCurrIndex = 0;
+ mOrientation = utils::OVERLAY_TRANSFORM_0;
+}
+
+bool MdpRot::queueBuffer(int fd, uint32_t offset) {
+ if(enabled() and (not isRotCached(fd,offset))) {
+ int prev_fd = getSrcMemId();
+ uint32_t prev_offset = getSrcOffset();
+
+ mRotDataInfo.src.memory_id = fd;
+ mRotDataInfo.src.offset = offset;
+
+ if(false == remap(RotMem::ROT_NUM_BUFS)) {
+ ALOGE("%s Remap failed, not queueing", __FUNCTION__);
+ return false;
+ }
+
+ mRotDataInfo.dst.offset =
+ mMem.mRotOffset[mMem.mCurrIndex];
+
+ if(!overlay::mdp_wrapper::rotate(mFd.getFD(), mRotDataInfo)) {
+ ALOGE("MdpRot failed rotate");
+ dump();
+ mRotDataInfo.src.memory_id = prev_fd;
+ mRotDataInfo.src.offset = prev_offset;
+ return false;
+ }
+ save();
+ mMem.mCurrIndex =
+ (mMem.mCurrIndex + 1) % mMem.mem.numBufs();
+ }
+ return true;
+}
+
+void MdpRot::dump() const {
+ ALOGE("== Dump MdpRot start ==");
+ mFd.dump();
+ mMem.mem.dump();
+ mdp_wrapper::dump("mRotImgInfo", mRotImgInfo);
+ mdp_wrapper::dump("mRotDataInfo", mRotDataInfo);
+ ALOGE("== Dump MdpRot end ==");
+}
+
+void MdpRot::getDump(char *buf, size_t len) const {
+ ovutils::getDump(buf, len, "MdpRotCtrl", mRotImgInfo);
+ ovutils::getDump(buf, len, "MdpRotData", mRotDataInfo);
+}
+
+int MdpRot::getDownscaleFactor(const int& src_w, const int& src_h,
+ const int& dst_w, const int& dst_h, const uint32_t& /*mdpFormat*/,
+ const bool& /*isInterlaced*/) {
+ int dscale_factor = utils::ROT_DS_NONE;
+ // We need this check to engage the rotator whenever possible to assist MDP
+ // in performing video downscale.
+ // This saves bandwidth and avoids causing the driver to make too many panel
+ // -mode switches between BLT (writeback) and non-BLT (Direct) modes.
+ // Use-case: Video playback [with downscaling and rotation].
+ if (dst_w && dst_h)
+ {
+ float fDscale = (float)(src_w * src_h) / (float)(dst_w * dst_h);
+ uint32_t dscale = (int)sqrtf(fDscale);
+
+ if(dscale < 2) {
+ // Down-scale to > 50% of orig.
+ dscale_factor = utils::ROT_DS_NONE;
+ } else if(dscale < 4) {
+ // Down-scale to between > 25% to <= 50% of orig.
+ dscale_factor = utils::ROT_DS_HALF;
+ } else if(dscale < 8) {
+ // Down-scale to between > 12.5% to <= 25% of orig.
+ dscale_factor = utils::ROT_DS_FOURTH;
+ } else {
+ // Down-scale to <= 12.5% of orig.
+ dscale_factor = utils::ROT_DS_EIGHTH;
+ }
+ }
+ return dscale_factor;
+}
+
+} // namespace overlay
diff --git a/msm8909/liboverlay/overlayMdssRot.cpp b/msm8909/liboverlay/overlayMdssRot.cpp
new file mode 100644
index 0000000..87e134a
--- /dev/null
+++ b/msm8909/liboverlay/overlayMdssRot.cpp
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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 <math.h>
+#include "overlayUtils.h"
+#include "overlayRotator.h"
+
+#define DEBUG_MDSS_ROT 0
+
+#ifdef VENUS_COLOR_FORMAT
+#include <media/msm_media_info.h>
+#else
+#define VENUS_BUFFER_SIZE(args...) 0
+#endif
+
+#ifndef MDSS_MDP_ROT_ONLY
+#define MDSS_MDP_ROT_ONLY 0x80
+#endif
+
+#define MDSS_ROT_MASK (MDP_ROT_90 | MDP_FLIP_UD | MDP_FLIP_LR)
+
+namespace ovutils = overlay::utils;
+
+namespace overlay {
+using namespace utils;
+
+MdssRot::MdssRot() {
+ reset();
+ init();
+}
+
+MdssRot::~MdssRot() { close(); }
+
+bool MdssRot::enabled() const { return mEnabled; }
+
+void MdssRot::setRotations(uint32_t flags) { mRotInfo.flags |= flags; }
+
+int MdssRot::getSrcMemId() const {
+ return mRotData.data.memory_id;
+}
+
+int MdssRot::getDstMemId() const {
+ return mRotData.dst_data.memory_id;
+}
+
+uint32_t MdssRot::getSrcOffset() const {
+ return mRotData.data.offset;
+}
+
+uint32_t MdssRot::getDstOffset() const {
+ return mRotData.dst_data.offset;
+}
+
+uint32_t MdssRot::getDstFormat() const {
+ //For mdss src and dst formats are same
+ return mRotInfo.src.format;
+}
+
+utils::Whf MdssRot::getDstWhf() const {
+ //For Mdss dst_rect itself represents buffer dimensions. We ignore actual
+ //aligned values during buffer allocation. Also the driver overwrites the
+ //src.format field if destination format is different.
+ //This implementation detail makes it possible to retrieve w,h even before
+ //buffer allocation, which happens in queueBuffer.
+ return utils::Whf(mRotInfo.dst_rect.w, mRotInfo.dst_rect.h,
+ mRotInfo.src.format);
+}
+
+utils::Dim MdssRot::getDstDimensions() const {
+ return utils::Dim(mRotInfo.dst_rect.x, mRotInfo.dst_rect.y,
+ mRotInfo.dst_rect.w, mRotInfo.dst_rect.h);
+}
+
+uint32_t MdssRot::getSessId() const { return mRotInfo.id; }
+
+void MdssRot::save() {
+ mLSRotInfo = mRotInfo;
+}
+
+bool MdssRot::rotConfChanged() const {
+ // 0 means same
+ if(0 == ::memcmp(&mRotInfo, &mLSRotInfo,
+ sizeof (mdp_overlay))) {
+ return false;
+ }
+ return true;
+}
+
+bool MdssRot::init() {
+ if(!utils::openDev(mFd, 0, Res::fbPath, O_RDWR)) {
+ ALOGE("MdssRot failed to init fb0");
+ return false;
+ }
+ return true;
+}
+
+void MdssRot::setSource(const overlay::utils::Whf& awhf) {
+ utils::Whf whf(awhf);
+
+ mRotInfo.src.format = whf.format;
+ mRotInfo.src.width = whf.w;
+ mRotInfo.src.height = whf.h;
+}
+
+void MdssRot::setCrop(const utils::Dim& crop) {
+ mRotInfo.src_rect.x = crop.x;
+ mRotInfo.src_rect.y = crop.y;
+ mRotInfo.src_rect.w = crop.w;
+ mRotInfo.src_rect.h = crop.h;
+}
+
+void MdssRot::setDownscale(int downscale) {
+ mDownscale = downscale;
+}
+
+void MdssRot::setFlags(const utils::eMdpFlags& flags) {
+ mRotInfo.flags = flags;
+}
+
+void MdssRot::setTransform(const utils::eTransform& rot)
+{
+ // reset rotation flags to avoid stale orientation values
+ mRotInfo.flags &= ~MDSS_ROT_MASK;
+ int flags = utils::getMdpOrient(rot);
+ if (flags != -1)
+ setRotations(flags);
+ mOrientation = static_cast<utils::eTransform>(flags);
+ ALOGE_IF(DEBUG_OVERLAY, "%s: rot=%d", __FUNCTION__, flags);
+}
+
+void MdssRot::doTransform() {
+ mRotInfo.flags |= mOrientation;
+ if(mOrientation & utils::OVERLAY_TRANSFORM_ROT_90)
+ utils::swap(mRotInfo.dst_rect.w, mRotInfo.dst_rect.h);
+}
+
+bool MdssRot::commit() {
+ Dim adjCrop(mRotInfo.src_rect.x,mRotInfo.src_rect.y,
+ mRotInfo.src_rect.w,mRotInfo.src_rect.h);
+ adjCrop = getFormatAdjustedCrop(adjCrop, mRotInfo.src.format,
+ mRotInfo.flags & utils::OV_MDP_DEINTERLACE);
+ adjCrop = getDownscaleAdjustedCrop(adjCrop, mDownscale);
+
+ mRotInfo.src_rect.x = adjCrop.x;
+ mRotInfo.src_rect.y = adjCrop.y;
+ mRotInfo.src_rect.w = adjCrop.w;
+ mRotInfo.src_rect.h = adjCrop.h;
+
+ mRotInfo.dst_rect.x = 0;
+ mRotInfo.dst_rect.y = 0;
+ mRotInfo.dst_rect.w = mDownscale ?
+ mRotInfo.src_rect.w / mDownscale : mRotInfo.src_rect.w;
+ mRotInfo.dst_rect.h = mDownscale ?
+ mRotInfo.src_rect.h / mDownscale : mRotInfo.src_rect.h;
+ //Clear for next round
+ mDownscale = 0;
+
+ doTransform();
+
+ mRotInfo.flags |= MDSS_MDP_ROT_ONLY;
+ mEnabled = true;
+ if(!overlay::mdp_wrapper::setOverlay(mFd.getFD(), mRotInfo)) {
+ ALOGE("MdssRot commit failed!");
+ dump();
+ return (mEnabled = false);
+ }
+ mRotData.id = mRotInfo.id;
+ return true;
+}
+
+bool MdssRot::queueBuffer(int fd, uint32_t offset) {
+ if(enabled() and (not isRotCached(fd,offset))) {
+ int prev_fd = getSrcMemId();
+ uint32_t prev_offset = getSrcOffset();
+
+ mRotData.data.memory_id = fd;
+ mRotData.data.offset = offset;
+
+ if(false == remap(RotMem::ROT_NUM_BUFS)) {
+ ALOGE("%s Remap failed, not queuing", __FUNCTION__);
+ return false;
+ }
+
+ mRotData.dst_data.offset =
+ mMem.mRotOffset[mMem.mCurrIndex];
+
+ if(!overlay::mdp_wrapper::play(mFd.getFD(), mRotData)) {
+ ALOGE("MdssRot play failed!");
+ dump();
+ mRotData.data.memory_id = prev_fd;
+ mRotData.data.offset = prev_offset;
+ return false;
+ }
+ save();
+ mMem.mCurrIndex =
+ (mMem.mCurrIndex + 1) % mMem.mem.numBufs();
+ }
+ return true;
+}
+
+bool MdssRot::open_i(uint32_t numbufs, uint32_t bufsz)
+{
+ OvMem mem;
+ OVASSERT(MAP_FAILED == mem.addr(), "MAP failed in open_i");
+ bool isSecure = mRotInfo.flags & utils::OV_MDP_SECURE_OVERLAY_SESSION;
+
+ if(!mem.open(numbufs, bufsz, isSecure)){
+ ALOGE("%s: Failed to open", __func__);
+ mem.close();
+ return false;
+ }
+
+ OVASSERT(MAP_FAILED != mem.addr(), "MAP failed");
+ OVASSERT(mem.getFD() != -1, "getFd is -1");
+
+ mRotData.dst_data.memory_id = mem.getFD();
+ mRotData.dst_data.offset = 0;
+ mMem.mem = mem;
+ return true;
+}
+
+bool MdssRot::remap(uint32_t numbufs) {
+ // Calculate the size based on rotator's dst format, w and h.
+ uint32_t opBufSize = calcOutputBufSize();
+ // If current size changed, remap
+ if(opBufSize == mMem.size()) {
+ ALOGE_IF(DEBUG_OVERLAY, "%s: same size %d", __FUNCTION__, opBufSize);
+ return true;
+ }
+
+ ALOGE_IF(DEBUG_OVERLAY, "%s: size changed - remapping", __FUNCTION__);
+
+ if(!mMem.close()) {
+ ALOGE("%s error in closing prev rot mem", __FUNCTION__);
+ return false;
+ }
+
+ if(!open_i(numbufs, opBufSize)) {
+ ALOGE("%s Error could not open", __FUNCTION__);
+ return false;
+ }
+
+ for (uint32_t i = 0; i < numbufs; ++i) {
+ mMem.mRotOffset[i] = i * opBufSize;
+ }
+
+ return true;
+}
+
+bool MdssRot::close() {
+ bool success = true;
+ if(mFd.valid() && (getSessId() != (uint32_t) MSMFB_NEW_REQUEST)) {
+ if(!mdp_wrapper::unsetOverlay(mFd.getFD(), getSessId())) {
+ ALOGE("MdssRot::close unsetOverlay failed, fd=%d sessId=%d",
+ mFd.getFD(), getSessId());
+ success = false;
+ }
+ }
+
+ if (!mFd.close()) {
+ ALOGE("Mdss Rot error closing fd");
+ success = false;
+ }
+ if (!mMem.close()) {
+ ALOGE("Mdss Rot error closing mem");
+ success = false;
+ }
+ reset();
+ return success;
+}
+
+void MdssRot::reset() {
+ ovutils::memset0(mRotInfo);
+ ovutils::memset0(mLSRotInfo);
+ ovutils::memset0(mRotData);
+ mRotData.data.memory_id = -1;
+ mRotInfo.id = MSMFB_NEW_REQUEST;
+ ovutils::memset0(mMem.mRotOffset);
+ mMem.mCurrIndex = 0;
+ mOrientation = utils::OVERLAY_TRANSFORM_0;
+ mDownscale = 0;
+}
+
+void MdssRot::dump() const {
+ ALOGE("== Dump MdssRot start ==");
+ mFd.dump();
+ mMem.mem.dump();
+ mdp_wrapper::dump("mRotInfo", mRotInfo);
+ mdp_wrapper::dump("mRotData", mRotData);
+ ALOGE("== Dump MdssRot end ==");
+}
+
+uint32_t MdssRot::calcOutputBufSize() {
+ uint32_t opBufSize = 0;
+ ovutils::Whf destWhf(mRotInfo.dst_rect.w, mRotInfo.dst_rect.h,
+ mRotInfo.src.format); //mdss src and dst formats are same.
+
+ if (mRotInfo.flags & ovutils::OV_MDSS_MDP_BWC_EN) {
+ opBufSize = calcCompressedBufSize(destWhf);
+ } else {
+ opBufSize = Rotator::calcOutputBufSize(destWhf);
+ }
+
+ return opBufSize;
+}
+
+void MdssRot::getDump(char *buf, size_t len) const {
+ ovutils::getDump(buf, len, "MdssRotCtrl", mRotInfo);
+ ovutils::getDump(buf, len, "MdssRotData", mRotData);
+}
+
+// Calculate the compressed o/p buffer size for BWC
+uint32_t MdssRot::calcCompressedBufSize(const ovutils::Whf& destWhf) {
+ uint32_t bufSize = 0;
+ //Worst case alignments
+ int aWidth = ovutils::align(destWhf.w, 64);
+ int aHeight = ovutils::align(destWhf.h, 4);
+ /*
+ Format | RAU size (width x height)
+ ----------------------------------------------
+ ARGB | 32 pixel x 4 line
+ RGB888 | 32 pixel x 4 line
+ Y (Luma) | 64 pixel x 4 line
+ CRCB 420 | 32 pixel x 2 line
+ CRCB 422 H2V1 | 32 pixel x 4 line
+ CRCB 422 H1V2 | 64 pixel x 2 line
+
+ Metadata requirements:-
+ 1 byte meta data for every 8 RAUs
+ 2 byte meta data per RAU
+ */
+
+ //These blocks attempt to allocate for the worst case in each of the
+ //respective format classes, yuv/rgb. The table above is for reference
+ if(utils::isYuv(destWhf.format)) {
+ int yRauCount = aWidth / 64; //Y
+ int cRauCount = aWidth / 32; //C
+ int yStride = (64 * 4 * yRauCount) + alignup(yRauCount, 8) / 8;
+ int cStride = ((32 * 2 * cRauCount) + alignup(cRauCount, 8) / 8) * 2;
+ int yStrideOffset = (aHeight / 4);
+ int cStrideOffset = (aHeight / 2);
+ bufSize = (yStride * yStrideOffset + cStride * cStrideOffset) +
+ (yRauCount * yStrideOffset * 2) +
+ (cRauCount * cStrideOffset * 2) * 2;
+ ALOGD_IF(DEBUG_MDSS_ROT, "%s:YUV Y RAU Count = %d C RAU Count = %d",
+ __FUNCTION__, yRauCount, cRauCount);
+ } else {
+ int rauCount = aWidth / 32;
+ //Single plane
+ int stride = (32 * 4 * rauCount) + alignup(rauCount, 8) / 8;
+ int strideOffset = (aHeight / 4);
+ bufSize = (stride * strideOffset * 4 /*bpp*/) +
+ (rauCount * strideOffset * 2);
+ ALOGD_IF(DEBUG_MDSS_ROT, "%s:RGB RAU count = %d", __FUNCTION__,
+ rauCount);
+ }
+
+ ALOGD_IF(DEBUG_MDSS_ROT, "%s: aligned width = %d, aligned height = %d "
+ "Buf Size = %d", __FUNCTION__, aWidth, aHeight, bufSize);
+
+ return bufSize;
+}
+
+int MdssRot::getDownscaleFactor(const int& srcW, const int& srcH,
+ const int& dstW, const int& dstH, const uint32_t& mdpFormat,
+ const bool& isInterlaced) {
+ if(not srcW or not srcH or not dstW or not dstH or isInterlaced) return 0;
+
+ Dim crop(0, 0, srcW, srcH);
+ Dim adjCrop = getFormatAdjustedCrop(crop, mdpFormat,
+ false /*isInterlaced */);
+
+ uint32_t downscale = min((adjCrop.w / dstW), (adjCrop.h / dstH));
+ //Reduced to a power of 2
+ downscale = (uint32_t) powf(2.0f, floorf(log2f((float)downscale)));
+
+ if(downscale < 2 or downscale > 32) return 0;
+
+ //Allow only 1 line or pixel to be chopped off since the source needs to
+ //be aligned to downscale. Progressively try with smaller downscale to see
+ //if we can satisfy the threshold
+ //For YUV the loop shouldnt be needed, unless in exceptional cases
+ Dim dsAdjCrop = getDownscaleAdjustedCrop(adjCrop, downscale);
+ while(downscale > 2 and (adjCrop.w > dsAdjCrop.w or
+ adjCrop.h > dsAdjCrop.h)) {
+ downscale /= 2;
+ dsAdjCrop = getDownscaleAdjustedCrop(adjCrop, downscale);
+ }
+
+ if(not dsAdjCrop.w or not dsAdjCrop.h) return 0;
+ return downscale;
+}
+
+Dim MdssRot::getFormatAdjustedCrop(const Dim& crop,
+ const uint32_t& mdpFormat, const bool& isInterlaced) {
+ Dim adjCrop = crop;
+ if (isYuv(mdpFormat)) {
+ normalizeCrop(adjCrop.x, adjCrop.w);
+ normalizeCrop(adjCrop.y, adjCrop.h);
+ // For interlaced, crop.h should be 4-aligned
+ if (isInterlaced and (adjCrop.h % 4))
+ adjCrop.h = aligndown(adjCrop.h, 4);
+ }
+ return adjCrop;
+}
+
+Dim MdssRot::getDownscaleAdjustedCrop(const Dim& crop,
+ const uint32_t& downscale) {
+ uint32_t alignedSrcW = aligndown(crop.w, downscale * 2);
+ uint32_t alignedSrcH = aligndown(crop.h, downscale * 2);
+ return Dim(crop.x, crop.y, alignedSrcW, alignedSrcH);
+}
+
+} // namespace overlay
diff --git a/msm8909/liboverlay/overlayMem.h b/msm8909/liboverlay/overlayMem.h
new file mode 100644
index 0000000..f0a1922
--- /dev/null
+++ b/msm8909/liboverlay/overlayMem.h
@@ -0,0 +1,222 @@
+/*
+* Copyright (c) 2011, The Linux Foundation. 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 The Linux Foundation 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 <sys/mman.h>
+#include <fcntl.h>
+#include <alloc_controller.h>
+#include <memalloc.h>
+
+#include "gralloc_priv.h"
+#include "overlayUtils.h"
+#define SIZE_1M 0x00100000
+
+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, bool isSecure);
+
+ /* 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 sent down by the client */
+ uint32_t mBufSz;
+
+ /* num of bufs */
+ uint32_t mNumBuffers;
+
+ /* gralloc alloc controller */
+ gralloc::IAllocController* mAlloc;
+
+ /*Holds the aligned buffer size used for actual allocation*/
+ uint32_t mBufSzAligned;
+};
+
+//-------------------Inlines-----------------------------------
+
+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();
+}
+
+inline OvMem::~OvMem() { }
+
+inline bool OvMem::open(uint32_t numbufs,
+ uint32_t bufSz, bool isSecure)
+{
+ alloc_data data;
+ int allocFlags = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP;
+ int err = 0;
+ OVASSERT(numbufs && bufSz, "numbufs=%d bufSz=%d", numbufs, bufSz);
+ mBufSz = bufSz;
+
+ if(isSecure) {
+ allocFlags = GRALLOC_USAGE_PRIVATE_MM_HEAP;
+ allocFlags |= GRALLOC_USAGE_PROTECTED;
+ mBufSzAligned = utils::align(bufSz, SIZE_1M);
+ data.align = SIZE_1M;
+ } else {
+ mBufSzAligned = bufSz;
+ data.align = getpagesize();
+ }
+
+ // Allocate uncached rotator buffers
+ allocFlags |= GRALLOC_USAGE_PRIVATE_UNCACHED;
+
+ mNumBuffers = numbufs;
+
+ data.base = 0;
+ data.fd = -1;
+ data.offset = 0;
+ data.size = mBufSzAligned * mNumBuffers;
+ data.uncached = true;
+
+ err = mAlloc->allocate(data, allocFlags);
+ if (err != 0) {
+ ALOGE("OvMem: Error allocating memory");
+ return false;
+ }
+
+ mFd = data.fd;
+ mBaseAddr = data.base;
+ mAllocType = data.allocType;
+
+ return true;
+}
+
+inline bool OvMem::close()
+{
+ int ret = 0;
+
+ if(!valid()) {
+ return true;
+ }
+
+ IMemAlloc* memalloc = mAlloc->getAllocator(mAllocType);
+ ret = memalloc->free_buffer(mBaseAddr, mBufSzAligned * mNumBuffers, 0, mFd);
+ if (ret != 0) {
+ ALOGE("OvMem: error freeing buffer");
+ return false;
+ }
+
+ mFd = -1;
+ mBaseAddr = MAP_FAILED;
+ mAllocType = 0;
+ mBufSz = 0;
+ mBufSzAligned = 0;
+ mNumBuffers = 0;
+ return true;
+}
+
+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("== Dump OvMem start ==");
+ ALOGE("fd=%d addr=%p type=%d bufsz=%u AlignedBufSz=%u",
+ mFd, mBaseAddr, mAllocType, mBufSz, mBufSzAligned);
+ ALOGE("== Dump OvMem end ==");
+}
+
+} // overlay
+
+#endif // OVERLAY_MEM_H
diff --git a/msm8909/liboverlay/overlayRotator.cpp b/msm8909/liboverlay/overlayRotator.cpp
new file mode 100644
index 0000000..b55f06a
--- /dev/null
+++ b/msm8909/liboverlay/overlayRotator.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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 "mdp_version.h"
+#include "sync/sync.h"
+#include "gr.h"
+
+namespace ovutils = overlay::utils;
+
+namespace overlay {
+
+//============Rotator=========================
+
+Rotator::Rotator() {
+ char property[PROPERTY_VALUE_MAX];
+ mRotCacheDisabled = false;
+ if((property_get("debug.rotcache.disable", property, NULL) > 0) &&
+ (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+ (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+ /* Used in debugging to turnoff rotator caching */
+ mRotCacheDisabled = true;
+ }
+}
+
+Rotator::~Rotator() {}
+
+Rotator* Rotator::getRotator() {
+ int type = getRotatorHwType();
+ if(type == TYPE_MDP) {
+ return new MdpRot(); //will do reset
+ } else if(type == TYPE_MDSS) {
+ return new MdssRot();
+ } else {
+ ALOGE("%s Unknown h/w type %d", __FUNCTION__, type);
+ return NULL;
+ }
+}
+
+int Rotator::getDownscaleFactor(const int& srcW, const int& srcH,
+ const int& dstW, const int& dstH, const uint32_t& mdpFormat,
+ const bool& isInterlaced) {
+ if(getRotatorHwType() == TYPE_MDSS) {
+ return MdssRot::getDownscaleFactor(srcW, srcH, dstW, dstH,
+ mdpFormat, isInterlaced);
+ }
+ return MdpRot::getDownscaleFactor(srcW, srcH, dstW, dstH,
+ mdpFormat, isInterlaced);
+}
+
+uint32_t Rotator::calcOutputBufSize(const utils::Whf& destWhf) {
+ //dummy aligned w & h.
+ int alW = 0, alH = 0;
+ int halFormat = ovutils::getHALFormat(destWhf.format);
+ //A call into gralloc/memalloc
+ return getBufferSizeAndDimensions(
+ destWhf.w, destWhf.h, halFormat, alW, alH);
+}
+
+int Rotator::getRotatorHwType() {
+ int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion();
+ if (mdpVersion == qdutils::MDSS_V5)
+ return TYPE_MDSS;
+ return TYPE_MDP;
+}
+
+bool Rotator::isRotCached(int fd, uint32_t offset) const {
+ if(mRotCacheDisabled or rotConfChanged() or rotDataChanged(fd,offset))
+ return false;
+ return true;
+}
+
+bool Rotator::rotDataChanged(int fd, uint32_t offset) const {
+ /* fd and offset are the attributes of the current rotator input buffer.
+ * At this instance, getSrcMemId() and getSrcOffset() return the
+ * attributes of the previous rotator input buffer */
+ if( (fd == getSrcMemId()) and (offset == getSrcOffset()) )
+ return false;
+ return true;
+}
+
+//============RotMem=========================
+
+bool RotMem::close() {
+ bool ret = true;
+ if(valid()) {
+ if(mem.close() == false) {
+ ALOGE("%s error in closing rot mem", __FUNCTION__);
+ ret = false;
+ }
+ }
+ return ret;
+}
+
+RotMem::RotMem() : mCurrIndex(0) {
+ utils::memset0(mRotOffset);
+ for(int i = 0; i < ROT_NUM_BUFS; i++) {
+ mRelFence[i] = -1;
+ }
+}
+
+RotMem::~RotMem() {
+ for(int i = 0; i < ROT_NUM_BUFS; i++) {
+ ::close(mRelFence[i]);
+ mRelFence[i] = -1;
+ }
+}
+
+void RotMem::setCurrBufReleaseFd(const int& fence) {
+ int ret = 0;
+
+ if(mRelFence[mCurrIndex] >= 0) {
+ //Wait for previous usage of this buffer to be over.
+ //Can happen if rotation takes > vsync and a fast producer. i.e queue
+ //happens in subsequent vsyncs either because content is 60fps or
+ //because the producer is hasty sometimes.
+ ret = sync_wait(mRelFence[mCurrIndex], 1000);
+ if(ret < 0) {
+ ALOGE("%s: sync_wait error!! error no = %d err str = %s",
+ __FUNCTION__, errno, strerror(errno));
+ }
+ ::close(mRelFence[mCurrIndex]);
+ }
+ mRelFence[mCurrIndex] = fence;
+}
+
+void RotMem::setPrevBufReleaseFd(const int& fence) {
+ uint32_t numRotBufs = mem.numBufs();
+ uint32_t prevIndex = (mCurrIndex + numRotBufs - 1) % (numRotBufs);
+
+ if(mRelFence[prevIndex] >= 0) {
+ /* No need of any wait as nothing will be written into this
+ * buffer by the rotator (this func is called when rotator is
+ * in cache mode) */
+ ::close(mRelFence[prevIndex]);
+ }
+
+ mRelFence[prevIndex] = fence;
+}
+
+//============RotMgr=========================
+RotMgr * RotMgr::sRotMgr = NULL;
+
+RotMgr* RotMgr::getInstance() {
+ if(sRotMgr == NULL) {
+ sRotMgr = new RotMgr();
+ }
+ return sRotMgr;
+}
+
+RotMgr::RotMgr() {
+ for(int i = 0; i < MAX_ROT_SESS; i++) {
+ mRot[i] = 0;
+ }
+ mUseCount = 0;
+ mRotDevFd = -1;
+}
+
+RotMgr::~RotMgr() {
+ clear();
+}
+
+void RotMgr::configBegin() {
+ //Reset the number of objects used
+ mUseCount = 0;
+}
+
+void RotMgr::configDone() {
+ //Remove the top most unused objects. Videos come and go.
+ for(int i = mUseCount; i < MAX_ROT_SESS; i++) {
+ if(mRot[i]) {
+ delete mRot[i];
+ mRot[i] = 0;
+ }
+ }
+}
+
+Rotator* RotMgr::getNext() {
+ //Return a rot object, creating one if necessary
+ overlay::Rotator *rot = NULL;
+ if(mUseCount >= MAX_ROT_SESS) {
+ ALOGW("%s, MAX rotator sessions reached, request rejected", __func__);
+ } else {
+ if(mRot[mUseCount] == NULL)
+ mRot[mUseCount] = overlay::Rotator::getRotator();
+ rot = mRot[mUseCount++];
+ }
+ return rot;
+}
+
+void RotMgr::clear() {
+ //Brute force obj destruction, helpful in suspend.
+ for(int i = 0; i < MAX_ROT_SESS; i++) {
+ if(mRot[i]) {
+ delete mRot[i];
+ mRot[i] = 0;
+ }
+ }
+ mUseCount = 0;
+ ::close(mRotDevFd);
+ mRotDevFd = -1;
+}
+
+void RotMgr::getDump(char *buf, size_t len) {
+ for(int i = 0; i < MAX_ROT_SESS; i++) {
+ if(mRot[i]) {
+ mRot[i]->getDump(buf, len);
+ }
+ }
+ char str[4] = {'\0'};
+ snprintf(str, 4, "\n");
+ strlcat(buf, str, len);
+}
+
+int RotMgr::getRotDevFd() {
+ if(mRotDevFd < 0 && Rotator::getRotatorHwType() == Rotator::TYPE_MDSS) {
+ mRotDevFd = ::open("/dev/graphics/fb0", O_RDWR, 0);
+ if(mRotDevFd < 0) {
+ ALOGE("%s failed to open fb0", __FUNCTION__);
+ }
+ }
+ return mRotDevFd;
+}
+
+}
diff --git a/msm8909/liboverlay/overlayRotator.h b/msm8909/liboverlay/overlayRotator.h
new file mode 100644
index 0000000..e045b44
--- /dev/null
+++ b/msm8909/liboverlay/overlayRotator.h
@@ -0,0 +1,322 @@
+/*
+* Copyright (c) 2011,2013 The Linux Foundation. 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 The Linux Foundation. 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 <stdlib.h>
+
+#include "mdpWrapper.h"
+#include "overlayUtils.h"
+#include "overlayMem.h"
+
+namespace overlay {
+
+/*
+ Manages the case where new rotator memory needs to be
+ allocated, before previous is freed, due to resolution change etc. If we make
+ rotator memory to be always max size, irrespctive of source resolution then
+ we don't need this RotMem wrapper. The inner class is sufficient.
+*/
+struct RotMem {
+ // Max rotator buffers
+ enum { ROT_NUM_BUFS = 2 };
+ RotMem();
+ ~RotMem();
+ bool close();
+ bool valid() { return mem.valid(); }
+ uint32_t size() const { return mem.bufSz(); }
+ void setCurrBufReleaseFd(const int& fence);
+ void setPrevBufReleaseFd(const int& fence);
+
+ // rotator data info dst offset
+ uint32_t mRotOffset[ROT_NUM_BUFS];
+ int mRelFence[ROT_NUM_BUFS];
+ // current slot being used
+ uint32_t mCurrIndex;
+ OvMem mem;
+};
+
+class Rotator
+{
+public:
+ enum { TYPE_MDP, TYPE_MDSS };
+ virtual ~Rotator();
+ virtual void setSource(const utils::Whf& wfh) = 0;
+ virtual void setCrop(const utils::Dim& crop) = 0;
+ virtual void setFlags(const utils::eMdpFlags& flags) = 0;
+ virtual void setTransform(const utils::eTransform& rot) = 0;
+ virtual bool commit() = 0;
+ /* return true if the current rotator state is cached */
+ virtual bool isRotCached(int fd, uint32_t offset) const;
+ /* return true if current rotator config is same as the last round*/
+ virtual bool rotConfChanged() const = 0;
+ /* return true if the current rotator input buffer fd and offset
+ * are same as the last round */
+ virtual bool rotDataChanged(int fd, uint32_t offset) const;
+ virtual void setDownscale(int ds) = 0;
+ /* returns the src buffer of the rotator for the previous/current round,
+ * depending on when it is called(before/after the queuebuffer)*/
+ virtual int getSrcMemId() const = 0;
+ //Mem id and offset should be retrieved only after rotator kickoff
+ virtual int getDstMemId() const = 0;
+ virtual uint32_t getSrcOffset() const = 0;
+ virtual uint32_t getDstOffset() const = 0;
+ //Destination width, height, format, position should be retrieved only after
+ //rotator configuration is committed via commit API
+ virtual uint32_t getDstFormat() const = 0;
+ virtual utils::Whf getDstWhf() const = 0;
+ virtual utils::Dim getDstDimensions() const = 0;
+ virtual uint32_t getSessId() const = 0;
+ virtual bool queueBuffer(int fd, uint32_t offset) = 0;
+ virtual void dump() const = 0;
+ virtual void getDump(char *buf, size_t len) const = 0;
+ inline void setCurrBufReleaseFd(const int& fence) {
+ mMem.setCurrBufReleaseFd(fence);
+ }
+ inline void setPrevBufReleaseFd(const int& fence) {
+ mMem.setPrevBufReleaseFd(fence);
+ }
+ static Rotator *getRotator();
+ /* Returns downscale by successfully applying constraints
+ * Returns 0 if target doesnt support rotator downscaling
+ * or if any of the constraints are not met
+ */
+ static int getDownscaleFactor(const int& srcW, const int& srcH,
+ const int& dstW, const int& dstH, const uint32_t& mdpFormat,
+ const bool& isInterlaced);
+
+protected:
+ /* Rotator memory manager */
+ RotMem mMem;
+ Rotator();
+ static uint32_t calcOutputBufSize(const utils::Whf& destWhf);
+
+private:
+ bool mRotCacheDisabled;
+ /*Returns rotator h/w type */
+ static int getRotatorHwType();
+ friend class RotMgr;
+};
+
+/*
+* MDP rot holds MDP's rotation related structures.
+*
+* */
+class MdpRot : public Rotator {
+public:
+ virtual ~MdpRot();
+ virtual void setSource(const utils::Whf& wfh);
+ virtual void setCrop(const utils::Dim& crop);
+ virtual void setFlags(const utils::eMdpFlags& flags);
+ virtual void setTransform(const utils::eTransform& rot);
+ virtual bool commit();
+ virtual bool rotConfChanged() const;
+ virtual void setDownscale(int ds);
+ virtual int getSrcMemId() const;
+ virtual int getDstMemId() const;
+ virtual uint32_t getSrcOffset() const;
+ virtual uint32_t getDstOffset() const;
+ virtual uint32_t getDstFormat() const;
+ virtual utils::Whf getDstWhf() const;
+ virtual utils::Dim getDstDimensions() const;
+ virtual uint32_t getSessId() const;
+ virtual bool queueBuffer(int fd, uint32_t offset);
+ virtual void dump() const;
+ virtual void getDump(char *buf, size_t len) const;
+
+private:
+ explicit MdpRot();
+ bool init();
+ bool close();
+ void setRotations(uint32_t r);
+ bool enabled () const;
+ /* remap rot buffers */
+ bool remap(uint32_t numbufs);
+ bool open_i(uint32_t numbufs, uint32_t bufsz);
+ /* Deferred transform calculations */
+ void doTransform();
+ /* reset underlying data, basically memset 0 */
+ void reset();
+ /* save mRotImgInfo to be last known good config*/
+ void save();
+ /* Calculates the rotator's o/p buffer size post the transform calcs and
+ * knowing the o/p format depending on whether fastYuv is enabled or not */
+ uint32_t calcOutputBufSize();
+
+ /* Applies downscale by taking areas
+ * Returns a log(downscale)
+ * Constraints applied:
+ * - downscale should be a power of 2
+ * - Max downscale is 1/8
+ */
+ static int getDownscaleFactor(const int& srcW, const int& srcH,
+ const int& dstW, const int& dstH, const uint32_t& mdpFormat,
+ const bool& isInterlaced);
+
+ /* rot info*/
+ msm_rotator_img_info mRotImgInfo;
+ /* Last saved rot info*/
+ msm_rotator_img_info mLSRotImgInfo;
+ /* rot data */
+ msm_rotator_data_info mRotDataInfo;
+ /* Orientation */
+ utils::eTransform mOrientation;
+ /* rotator fd */
+ OvFD mFd;
+
+ friend Rotator* Rotator::getRotator();
+ friend int Rotator::getDownscaleFactor(const int& srcW, const int& srcH,
+ const int& dstW, const int& dstH, const uint32_t& mdpFormat,
+ const bool& isInterlaced);
+};
+
+/*
++* MDSS Rot holds MDSS's rotation related structures.
++*
++* */
+class MdssRot : public Rotator {
+public:
+ virtual ~MdssRot();
+ virtual void setSource(const utils::Whf& wfh);
+ virtual void setCrop(const utils::Dim& crop);
+ virtual void setFlags(const utils::eMdpFlags& flags);
+ virtual void setTransform(const utils::eTransform& rot);
+ virtual bool commit();
+ virtual bool rotConfChanged() const;
+ virtual void setDownscale(int ds);
+ virtual int getSrcMemId() const;
+ virtual int getDstMemId() const;
+ virtual uint32_t getSrcOffset() const;
+ virtual uint32_t getDstOffset() const;
+ virtual uint32_t getDstFormat() const;
+ virtual utils::Whf getDstWhf() const;
+ virtual utils::Dim getDstDimensions() const;
+ virtual uint32_t getSessId() const;
+ virtual bool queueBuffer(int fd, uint32_t offset);
+ virtual void dump() const;
+ virtual void getDump(char *buf, size_t len) const;
+
+private:
+ explicit MdssRot();
+ bool init();
+ bool close();
+ void setRotations(uint32_t r);
+ bool enabled () const;
+ /* remap rot buffers */
+ bool remap(uint32_t numbufs);
+ bool open_i(uint32_t numbufs, uint32_t bufsz);
+ /* Deferred transform calculations */
+ void doTransform();
+ /* reset underlying data, basically memset 0 */
+ void reset();
+ /* save mRotInfo to be last known good config*/
+ void save();
+ /* Calculates the rotator's o/p buffer size post the transform calcs and
+ * knowing the o/p format depending on whether fastYuv is enabled or not */
+ uint32_t calcOutputBufSize();
+ // Calculate the compressed o/p buffer size for BWC
+ uint32_t calcCompressedBufSize(const utils::Whf& destWhf);
+
+ /* Caller's responsibility to swap srcW, srcH if there is a 90 transform
+ * Returns actual downscale (not a log value)
+ * Constraints applied:
+ * - downscale should be a power of 2
+ * - Max downscale is 1/32
+ * - Equal downscale is applied in both directions
+ * - {srcW, srcH} mod downscale = 0
+ * - Interlaced content is not supported
+ */
+ static int getDownscaleFactor(const int& srcW, const int& srcH,
+ const int& dstW, const int& dstH, const uint32_t& mdpFormat,
+ const bool& isInterlaced);
+
+ static utils::Dim getFormatAdjustedCrop(const utils::Dim& crop,
+ const uint32_t& mdpFormat, const bool& isInterlaced);
+
+ static utils::Dim getDownscaleAdjustedCrop(const utils::Dim& crop,
+ const uint32_t& downscale);
+
+ /* MdssRot info structure */
+ mdp_overlay mRotInfo;
+ /* Last saved MdssRot info structure*/
+ mdp_overlay mLSRotInfo;
+ /* MdssRot data structure */
+ msmfb_overlay_data mRotData;
+ /* Orientation */
+ utils::eTransform mOrientation;
+ /* rotator fd */
+ OvFD mFd;
+ /* Enable/Disable Mdss Rot*/
+ bool mEnabled;
+ int mDownscale;
+
+ friend Rotator* Rotator::getRotator();
+ friend int Rotator::getDownscaleFactor(const int& srcW, const int& srcH,
+ const int& dstW, const int& dstH, const uint32_t& mdpFormat,
+ const bool& isInterlaced);
+};
+
+// Holder of rotator objects. Manages lifetimes
+class RotMgr {
+public:
+ //Virtually we can support as many rotator sessions as possible, However
+ // more number of rotator sessions leads to performance issues, so
+ // restricting the max rotator session to 4
+ enum { MAX_ROT_SESS = 4 };
+
+ ~RotMgr();
+ void configBegin();
+ void configDone();
+ overlay::Rotator *getNext();
+ void clear(); //Removes all instances
+ //Resets the usage of top count objects, making them available for reuse
+ void markUnusedTop(const uint32_t& count) { mUseCount -= count; }
+ /* Returns rot dump.
+ * Expects a NULL terminated buffer of big enough size.
+ */
+ void getDump(char *buf, size_t len);
+ int getRotDevFd();
+ int getNumActiveSessions() { return mUseCount; }
+
+ static RotMgr *getInstance();
+
+private:
+ RotMgr();
+ static RotMgr *sRotMgr;
+
+ overlay::Rotator *mRot[MAX_ROT_SESS];
+ uint32_t mUseCount;
+ int mRotDevFd;
+};
+
+
+} // overlay
+
+#endif // OVERlAY_ROTATOR_H
diff --git a/msm8909/liboverlay/overlayUtils.cpp b/msm8909/liboverlay/overlayUtils.cpp
new file mode 100644
index 0000000..cbd52ae
--- /dev/null
+++ b/msm8909/liboverlay/overlayUtils.cpp
@@ -0,0 +1,399 @@
+/*
+* Copyright (c) 2011-2014, The Linux Foundation. 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 The Linux Foundation 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 <stdlib.h>
+#include <math.h>
+#include <utils/Log.h>
+#include <linux/msm_mdp.h>
+#include <cutils/properties.h>
+#include "gralloc_priv.h"
+#include "overlayUtils.h"
+#include "mdpWrapper.h"
+#include "mdp_version.h"
+#include <hardware/hwcomposer_defs.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 <class T>
+ 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::fbPath = "/dev/graphics/fb%u";
+const char* const Res::rotPath = "/dev/msm_rotator";
+//--------------------------------------------------------
+
+
+
+namespace utils {
+
+//--------------------------------------------------------
+//Refer to graphics.h, gralloc_priv.h, msm_mdp.h
+int getMdpFormat(int format) {
+ switch (format) {
+ //From graphics.h
+ case HAL_PIXEL_FORMAT_RGBA_8888 :
+ return MDP_RGBA_8888;
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ return MDP_RGBX_8888;
+ case HAL_PIXEL_FORMAT_RGB_888:
+ return MDP_RGB_888;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ return MDP_RGB_565;
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ return MDP_BGRA_8888;
+ case HAL_PIXEL_FORMAT_BGRX_8888:
+ return MDP_BGRX_8888;
+ case HAL_PIXEL_FORMAT_YV12:
+ return MDP_Y_CR_CB_GH2V2;
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ return MDP_Y_CBCR_H2V1;
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ return MDP_Y_CRCB_H2V2;
+
+ //From gralloc_priv.h
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
+ return MDP_Y_CBCR_H2V2_TILE;
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP:
+ return MDP_Y_CBCR_H2V2;
+ case HAL_PIXEL_FORMAT_YCrCb_422_SP:
+ return MDP_Y_CRCB_H2V1;
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ return MDP_YCBYCR_H2V1;
+ case HAL_PIXEL_FORMAT_YCrCb_422_I:
+ return MDP_YCRYCB_H2V1;
+ case HAL_PIXEL_FORMAT_YCbCr_444_SP:
+ return MDP_Y_CBCR_H1V1;
+ case HAL_PIXEL_FORMAT_YCrCb_444_SP:
+ return MDP_Y_CRCB_H1V1;
+ case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+ case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
+ //NV12 encodeable format maps to the venus format on
+ //B-Family targets
+ return MDP_Y_CBCR_H2V2_VENUS;
+ default:
+ //Unsupported by MDP
+ //---graphics.h--------
+ //HAL_PIXEL_FORMAT_RGBA_5551
+ //HAL_PIXEL_FORMAT_RGBA_4444
+ //---gralloc_priv.h-----
+ //HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO = 0x7FA30C01
+ //HAL_PIXEL_FORMAT_R_8 = 0x10D
+ //HAL_PIXEL_FORMAT_RG_88 = 0x10E
+ ALOGE("%s: Unsupported HAL format = 0x%x", __func__, format);
+ return -1;
+ }
+ // not reached
+ return -1;
+}
+
+// This function returns corresponding tile format
+// MDSS support following RGB tile formats
+// 32 bit formats
+// 16 bit formats
+int getMdpFormat(int format, bool tileEnabled)
+{
+ if(!tileEnabled) {
+ return getMdpFormat(format);
+ }
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888 :
+ return MDP_RGBA_8888_TILE;
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ return MDP_RGBX_8888_TILE;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ return MDP_RGB_565_TILE;
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ return MDP_BGRA_8888_TILE;
+ case HAL_PIXEL_FORMAT_BGRX_8888:
+ return MDP_BGRX_8888_TILE;
+ default:
+ return getMdpFormat(format);
+ }
+}
+
+
+
+//Takes mdp format as input and translates to equivalent HAL format
+//Refer to graphics.h, gralloc_priv.h, msm_mdp.h for formats.
+int getHALFormat(int mdpFormat) {
+ switch (mdpFormat) {
+ //From graphics.h
+ case MDP_RGBA_8888:
+ return HAL_PIXEL_FORMAT_RGBA_8888;
+ case MDP_RGBX_8888:
+ return HAL_PIXEL_FORMAT_RGBX_8888;
+ case MDP_RGB_888:
+ return HAL_PIXEL_FORMAT_RGB_888;
+ case MDP_RGB_565:
+ return HAL_PIXEL_FORMAT_RGB_565;
+ case MDP_BGRA_8888:
+ return HAL_PIXEL_FORMAT_BGRA_8888;
+ case MDP_Y_CR_CB_GH2V2:
+ return HAL_PIXEL_FORMAT_YV12;
+ case MDP_Y_CBCR_H2V1:
+ return HAL_PIXEL_FORMAT_YCbCr_422_SP;
+ case MDP_Y_CRCB_H2V2:
+ return HAL_PIXEL_FORMAT_YCrCb_420_SP;
+
+ //From gralloc_priv.h
+ case MDP_Y_CBCR_H2V2_TILE:
+ return HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED;
+ case MDP_Y_CBCR_H2V2:
+ return HAL_PIXEL_FORMAT_YCbCr_420_SP;
+ case MDP_Y_CRCB_H2V1:
+ return HAL_PIXEL_FORMAT_YCrCb_422_SP;
+ case MDP_YCBYCR_H2V1:
+ return HAL_PIXEL_FORMAT_YCbCr_422_I;
+ case MDP_YCRYCB_H2V1:
+ return HAL_PIXEL_FORMAT_YCrCb_422_I;
+ case MDP_Y_CBCR_H1V1:
+ return HAL_PIXEL_FORMAT_YCbCr_444_SP;
+ case MDP_Y_CRCB_H1V1:
+ return HAL_PIXEL_FORMAT_YCrCb_444_SP;
+ case MDP_Y_CBCR_H2V2_VENUS:
+ return HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS;
+ default:
+ ALOGE("%s: Unsupported MDP format = 0x%x", __func__, mdpFormat);
+ return -1;
+ }
+ // not reached
+ return -1;
+}
+
+int getMdpOrient(eTransform rotation) {
+ int retTrans = 0;
+ bool trans90 = false;
+ int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion();
+ bool aFamily = (mdpVersion < qdutils::MDSS_V5);
+
+ ALOGD_IF(DEBUG_OVERLAY, "%s: In rotation = %d", __FUNCTION__, rotation);
+ if(rotation & OVERLAY_TRANSFORM_ROT_90) {
+ retTrans |= MDP_ROT_90;
+ trans90 = true;
+ }
+
+ if(rotation & OVERLAY_TRANSFORM_FLIP_H) {
+ if(trans90 && aFamily) {
+ //Swap for a-family, since its driver does 90 first
+ retTrans |= MDP_FLIP_UD;
+ } else {
+ retTrans |= MDP_FLIP_LR;
+ }
+ }
+
+ if(rotation & OVERLAY_TRANSFORM_FLIP_V) {
+ if(trans90 && aFamily) {
+ //Swap for a-family, since its driver does 90 first
+ retTrans |= MDP_FLIP_LR;
+ } else {
+ retTrans |= MDP_FLIP_UD;
+ }
+ }
+
+ ALOGD_IF(DEBUG_OVERLAY, "%s: Out rotation = %d", __FUNCTION__, retTrans);
+ return retTrans;
+}
+
+void getDecimationFactor(const int& src_w, const int& src_h,
+ const int& dst_w, const int& dst_h, uint8_t& horzDeci,
+ uint8_t& vertDeci) {
+ horzDeci = 0;
+ vertDeci = 0;
+ float horDscale = ceilf((float)src_w / (float)dst_w);
+ float verDscale = ceilf((float)src_h / (float)dst_h);
+ qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance();
+
+ //Next power of 2, if not already
+ horDscale = powf(2.0f, ceilf(log2f(horDscale)));
+ verDscale = powf(2.0f, ceilf(log2f(verDscale)));
+
+ //Since MDP can do downscale and has better quality, split the task
+ //between decimator and MDP downscale
+ horDscale /= (float)mdpHw.getMaxMDPDownscale();
+ verDscale /= (float)mdpHw.getMaxMDPDownscale();
+
+ if((int)horDscale)
+ horzDeci = (uint8_t)log2f(horDscale);
+
+ if((int)verDscale)
+ vertDeci = (uint8_t)log2f(verDscale);
+
+ if(src_w > (int) mdpHw.getMaxMixerWidth()) {
+ //If the client sends us something > what a layer mixer supports
+ //then it means it doesn't want to use split-pipe but wants us to
+ //decimate. A minimum decimation of 2 will ensure that the width is
+ //always within layer mixer limits.
+ if(horzDeci < 2)
+ horzDeci = 2;
+ }
+}
+
+static inline int compute(const uint32_t& x, const uint32_t& y,
+ const uint32_t& z) {
+ return x - ( y + z );
+}
+
+void preRotateSource(const eTransform& tr, Whf& whf, Dim& srcCrop) {
+ if(tr & OVERLAY_TRANSFORM_FLIP_H) {
+ srcCrop.x = compute(whf.w, srcCrop.x, srcCrop.w);
+ }
+ if(tr & OVERLAY_TRANSFORM_FLIP_V) {
+ srcCrop.y = compute(whf.h, srcCrop.y, srcCrop.h);
+ }
+ if(tr & OVERLAY_TRANSFORM_ROT_90) {
+ int tmp = srcCrop.x;
+ srcCrop.x = compute(whf.h,
+ srcCrop.y,
+ srcCrop.h);
+ srcCrop.y = tmp;
+ swap(whf.w, whf.h);
+ swap(srcCrop.w, srcCrop.h);
+ }
+}
+
+void getDump(char *buf, size_t len, const char *prefix,
+ const mdp_overlay& ov) {
+ char str[256] = {'\0'};
+ snprintf(str, 256,
+ "%s id=%d z=%d alpha=%d mask=%d flags=0x%x H.Deci=%d,"
+ "V.Deci=%d\n",
+ prefix, ov.id, ov.z_order, ov.alpha,
+ ov.transp_mask, ov.flags, ov.horz_deci, ov.vert_deci);
+ strlcat(buf, str, len);
+ getDump(buf, len, "\tsrc", ov.src);
+ getDump(buf, len, "\tsrc_rect", ov.src_rect);
+ getDump(buf, len, "\tdst_rect", ov.dst_rect);
+}
+
+void getDump(char *buf, size_t len, const char *prefix,
+ const msmfb_img& ov) {
+ char str_src[256] = {'\0'};
+ snprintf(str_src, 256,
+ "%s w=%d h=%d format=%d %s\n",
+ prefix, ov.width, ov.height, ov.format,
+ overlay::utils::getFormatString(ov.format));
+ strlcat(buf, str_src, len);
+}
+
+void getDump(char *buf, size_t len, const char *prefix,
+ const mdp_rect& ov) {
+ char str_rect[256] = {'\0'};
+ snprintf(str_rect, 256,
+ "%s x=%d y=%d w=%d h=%d\n",
+ prefix, ov.x, ov.y, ov.w, ov.h);
+ strlcat(buf, str_rect, len);
+}
+
+void getDump(char *buf, size_t len, const char *prefix,
+ const msmfb_overlay_data& ov) {
+ char str[256] = {'\0'};
+ snprintf(str, 256,
+ "%s id=%d\n",
+ prefix, ov.id);
+ strlcat(buf, str, len);
+ getDump(buf, len, "\tdata", ov.data);
+}
+
+void getDump(char *buf, size_t len, const char *prefix,
+ const msmfb_data& ov) {
+ char str_data[256] = {'\0'};
+ snprintf(str_data, 256,
+ "%s offset=%d memid=%d id=%d flags=0x%x\n",
+ prefix, ov.offset, ov.memory_id, ov.id, ov.flags);
+ strlcat(buf, str_data, len);
+}
+
+void getDump(char *buf, size_t len, const char *prefix,
+ const msm_rotator_img_info& rot) {
+ char str[256] = {'\0'};
+ snprintf(str, 256, "%s sessid=%u rot=%d, enable=%d downscale=%d\n",
+ prefix, rot.session_id, rot.rotations, rot.enable,
+ rot.downscale_ratio);
+ strlcat(buf, str, len);
+ getDump(buf, len, "\tsrc", rot.src);
+ getDump(buf, len, "\tdst", rot.dst);
+ getDump(buf, len, "\tsrc_rect", rot.src_rect);
+}
+
+void getDump(char *buf, size_t len, const char *prefix,
+ const msm_rotator_data_info& rot) {
+ char str[256] = {'\0'};
+ snprintf(str, 256,
+ "%s sessid=%u\n",
+ prefix, rot.session_id);
+ strlcat(buf, str, len);
+ getDump(buf, len, "\tsrc", rot.src);
+ getDump(buf, len, "\tdst", rot.dst);
+}
+
+//Helper to even out x,w and y,h pairs
+//x,y are always evened to ceil and w,h are evened to floor
+void normalizeCrop(uint32_t& xy, uint32_t& wh) {
+ if(xy & 1) {
+ even_ceil(xy);
+ if(wh & 1)
+ even_floor(wh);
+ else
+ wh -= 2;
+ } else {
+ even_floor(wh);
+ }
+}
+
+} // utils
+
+} // overlay
diff --git a/msm8909/liboverlay/overlayUtils.h b/msm8909/liboverlay/overlayUtils.h
new file mode 100644
index 0000000..2b8e303
--- /dev/null
+++ b/msm8909/liboverlay/overlayUtils.h
@@ -0,0 +1,683 @@
+/*
+* Copyright (c) 2011-2014, The Linux Foundation. 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 The Linux Foundation 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 <cutils/log.h> // ALOGE, etc
+#include <errno.h>
+#include <fcntl.h> // open, O_RDWR, etc
+#include <hardware/hardware.h>
+#include <hardware/gralloc.h> // buffer_handle_t
+#include <linux/msm_mdp.h> // flags
+#include <linux/msm_rotator.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+#include "gralloc_priv.h" //for interlace
+
+// Older platforms do not support Venus
+#ifndef VENUS_COLOR_FORMAT
+#define MDP_Y_CBCR_H2V2_VENUS MDP_IMGTYPE_LIMIT
+#endif
+
+/*
+*
+* 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
+
+#ifndef MDSS_MDP_RIGHT_MIXER
+#define MDSS_MDP_RIGHT_MIXER 0x100
+#endif
+
+#ifndef MDP_OV_PIPE_FORCE_DMA
+#define MDP_OV_PIPE_FORCE_DMA 0x4000
+#endif
+
+#ifndef MDSS_MDP_DUAL_PIPE
+#define MDSS_MDP_DUAL_PIPE 0x200
+#endif
+
+#define FB_DEVICE_TEMPLATE "/dev/graphics/fb%u"
+
+namespace overlay {
+
+// fwd
+class Overlay;
+class OvFD;
+
+/* helper function to open by using fbnum */
+bool open(OvFD& fd, uint32_t fbnum, const char* const dev,
+ int flags = O_RDWR);
+
+namespace utils {
+struct Whf;
+struct Dim;
+
+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&);
+};
+
+bool isMdssRotator();
+void normalizeCrop(uint32_t& xy, uint32_t& wh);
+
+template <class Type>
+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 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;
+ uint32_t format;
+ uint32_t size;
+};
+
+enum { MAX_PATH_LEN = 256 };
+
+enum { DEFAULT_PLANE_ALPHA = 0xFF };
+
+/**
+ * Rotator flags: not to be confused with orientation flags.
+ * Usually, you want to open the rotator to make sure it is
+ * ready for business.
+ * */
+ enum eRotFlags {
+ ROT_FLAGS_NONE = 0,
+ //Use rotator for 0 rotation. It is used anyway for others.
+ ROT_0_ENABLED = 1 << 0,
+ //Enable rotator downscale optimization for hardware bugs not handled in
+ //driver. If downscale optimizatation is required,
+ //then rotator will be used even if its 0 rotation case.
+ ROT_DOWNSCALE_ENABLED = 1 << 1,
+ ROT_PREROTATED = 1 << 2,
+};
+
+enum eRotDownscale {
+ ROT_DS_NONE = 0,
+ ROT_DS_HALF = 1,
+ ROT_DS_FOURTH = 2,
+ ROT_DS_EIGHTH = 3,
+};
+
+/*
+ * 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_PIPE_FORCE_DMA = MDP_OV_PIPE_FORCE_DMA,
+ OV_MDP_DEINTERLACE = MDP_DEINTERLACE,
+ OV_MDP_SECURE_OVERLAY_SESSION = MDP_SECURE_OVERLAY_SESSION,
+ OV_MDP_SECURE_DISPLAY_OVERLAY_SESSION = MDP_SECURE_DISPLAY_OVERLAY_SESSION,
+ OV_MDP_SOURCE_ROTATED_90 = MDP_SOURCE_ROTATED_90,
+ OV_MDP_BACKEND_COMPOSITION = MDP_BACKEND_COMPOSITION,
+ OV_MDP_BLEND_FG_PREMULT = MDP_BLEND_FG_PREMULT,
+ OV_MDP_FLIP_H = MDP_FLIP_LR,
+ OV_MDP_FLIP_V = MDP_FLIP_UD,
+ OV_MDSS_MDP_RIGHT_MIXER = MDSS_MDP_RIGHT_MIXER,
+ OV_MDP_PP_EN = MDP_OVERLAY_PP_CFG_EN,
+ OV_MDSS_MDP_BWC_EN = MDP_BWC_EN,
+ OV_MDSS_MDP_DUAL_PIPE = MDSS_MDP_DUAL_PIPE,
+ OV_MDP_SOLID_FILL = MDP_SOLID_FILL,
+};
+
+enum eZorder {
+ ZORDER_0 = 0,
+ ZORDER_1,
+ ZORDER_2,
+ ZORDER_3,
+ Z_SYSTEM_ALLOC = 0xFFFF
+};
+
+enum eMdpPipeType {
+ OV_MDP_PIPE_RGB = 0,
+ OV_MDP_PIPE_VG,
+ OV_MDP_PIPE_DMA,
+ OV_MDP_PIPE_ANY, //Any
+};
+
+// Identify destination pipes
+// TODO Names useless, replace with int and change all interfaces
+enum eDest {
+ OV_P0 = 0,
+ OV_P1,
+ OV_P2,
+ OV_P3,
+ OV_P4,
+ OV_P5,
+ OV_P6,
+ OV_P7,
+ OV_P8,
+ OV_P9,
+ OV_INVALID,
+ OV_MAX = OV_INVALID,
+};
+
+/* Used when a buffer is split over 2 pipes and sent to display */
+enum {
+ OV_LEFT_SPLIT = 0,
+ OV_RIGHT_SPLIT,
+};
+
+/* values for copybit_set_parameter(OVERLAY_TRANSFORM) */
+enum eTransform {
+ /* No rot */
+ OVERLAY_TRANSFORM_0 = 0x0,
+ /* flip source image horizontally 0x1 */
+ OVERLAY_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H,
+ /* flip source image vertically 0x2 */
+ OVERLAY_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
+ /* 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 90 degrees 0x4 */
+ OVERLAY_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
+ /* rotate source image 90 degrees and flip horizontally 0x5 */
+ OVERLAY_TRANSFORM_ROT_90_FLIP_H = HAL_TRANSFORM_ROT_90 |
+ HAL_TRANSFORM_FLIP_H,
+ /* rotate source image 90 degrees and flip vertically 0x6 */
+ OVERLAY_TRANSFORM_ROT_90_FLIP_V = HAL_TRANSFORM_ROT_90 |
+ HAL_TRANSFORM_FLIP_V,
+ /* 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
+};
+
+enum eBlending {
+ OVERLAY_BLENDING_UNDEFINED = 0x0,
+ /* No blending */
+ OVERLAY_BLENDING_OPAQUE,
+ /* src.rgb + dst.rgb*(1-src_alpha) */
+ OVERLAY_BLENDING_PREMULT,
+ /* src.rgb * src_alpha + dst.rgb (1 - src_alpha) */
+ OVERLAY_BLENDING_COVERAGE,
+};
+
+// Used to consolidate pipe params
+struct PipeArgs {
+ PipeArgs() : mdpFlags(OV_MDP_FLAGS_NONE),
+ zorder(Z_SYSTEM_ALLOC),
+ rotFlags(ROT_FLAGS_NONE),
+ planeAlpha(DEFAULT_PLANE_ALPHA),
+ blending(OVERLAY_BLENDING_COVERAGE){
+ }
+
+ PipeArgs(eMdpFlags f, Whf _whf,
+ eZorder z, eRotFlags r,
+ int pA = DEFAULT_PLANE_ALPHA, eBlending b = OVERLAY_BLENDING_COVERAGE) :
+ mdpFlags(f),
+ whf(_whf),
+ zorder(z),
+ rotFlags(r),
+ planeAlpha(pA),
+ blending(b){
+ }
+
+ eMdpFlags mdpFlags; // for mdp_overlay flags
+ Whf whf;
+ eZorder zorder; // stage number
+ eRotFlags rotFlags;
+ int planeAlpha;
+ eBlending blending;
+};
+
+// 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 void setMdpFlags(eMdpFlags& f, eMdpFlags v) {
+ f = static_cast<eMdpFlags>(setBit(f, v));
+}
+
+inline void clearMdpFlags(eMdpFlags& f, eMdpFlags v) {
+ f = static_cast<eMdpFlags>(clrBit(f, v));
+}
+
+enum { FB0, FB1, FB2 };
+
+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 getMdpFormat(int format, bool tileEnabled);
+int getHALFormat(int mdpFormat);
+void getDecimationFactor(const int& src_w, const int& src_h,
+ const int& dst_w, const int& dst_h, uint8_t& horzDeci,
+ uint8_t& vertDeci);
+
+/* 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);
+const char* getFormatString(int format);
+
+template <class T>
+inline void memset0(T& t) { ::memset(&t, 0, sizeof(t)); }
+
+template <class T> inline void swap ( T& a, T& b )
+{
+ T c(a); a=b; b=c;
+}
+
+template<typename T> inline T max(T a, T b) { return (a > b) ? a : b; }
+
+template<typename T> inline T min(T a, T b) { return (a < b) ? a : b; }
+
+inline int alignup(int value, int a) {
+ //if align = 0, return the value. Else, do alignment.
+ return a ? ((((value - 1) / a) + 1) * a) : value;
+}
+
+inline int aligndown(int value, int a) {
+ //if align = 0, return the value. Else, do alignment.
+ return a ? ((value) & ~(a-1)) : 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;
+}
+
+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_H1V1:
+ case MDP_Y_CRCB_H2V1:
+ case MDP_Y_CRCB_H2V2_TILE:
+ case MDP_Y_CBCR_H2V2_TILE:
+ case MDP_Y_CR_CB_H2V2:
+ case MDP_Y_CR_CB_GH2V2:
+ case MDP_Y_CBCR_H2V2_VENUS:
+ case MDP_YCBYCR_H2V1:
+ case MDP_YCRYCB_H2V1:
+ 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 const char* getFormatString(int format){
+ #define STR(f) #f;
+ static const char* formats[MDP_IMGTYPE_LIMIT + 1] = {0};
+ formats[MDP_RGB_565] = STR(MDP_RGB_565);
+ formats[MDP_XRGB_8888] = STR(MDP_XRGB_8888);
+ formats[MDP_Y_CBCR_H2V2] = STR(MDP_Y_CBCR_H2V2);
+ formats[MDP_Y_CBCR_H2V2_ADRENO] = STR(MDP_Y_CBCR_H2V2_ADRENO);
+ formats[MDP_ARGB_8888] = STR(MDP_ARGB_8888);
+ formats[MDP_RGB_888] = STR(MDP_RGB_888);
+ formats[MDP_Y_CRCB_H2V2] = STR(MDP_Y_CRCB_H2V2);
+ formats[MDP_YCBYCR_H2V1] = STR(MDP_YCBYCR_H2V1);
+ formats[MDP_YCRYCB_H2V1] = STR(MDP_YCRYCB_H2V1);
+ formats[MDP_CBYCRY_H2V1] = STR(MDP_CBYCRY_H2V1);
+ formats[MDP_Y_CRCB_H2V1] = STR(MDP_Y_CRCB_H2V1);
+ formats[MDP_Y_CBCR_H2V1] = STR(MDP_Y_CBCR_H2V1);
+ formats[MDP_Y_CRCB_H1V2] = STR(MDP_Y_CRCB_H1V2);
+ formats[MDP_Y_CBCR_H1V2] = STR(MDP_Y_CBCR_H1V2);
+ formats[MDP_RGBA_8888] = STR(MDP_RGBA_8888);
+ formats[MDP_BGRA_8888] = STR(MDP_BGRA_8888);
+ formats[MDP_RGBX_8888] = STR(MDP_RGBX_8888);
+ formats[MDP_Y_CRCB_H2V2_TILE] = STR(MDP_Y_CRCB_H2V2_TILE);
+ formats[MDP_Y_CBCR_H2V2_TILE] = STR(MDP_Y_CBCR_H2V2_TILE);
+ formats[MDP_Y_CR_CB_H2V2] = STR(MDP_Y_CR_CB_H2V2);
+ formats[MDP_Y_CR_CB_GH2V2] = STR(MDP_Y_CR_CB_GH2V2);
+ formats[MDP_Y_CB_CR_H2V2] = STR(MDP_Y_CB_CR_H2V2);
+ formats[MDP_Y_CRCB_H1V1] = STR(MDP_Y_CRCB_H1V1);
+ formats[MDP_Y_CBCR_H1V1] = STR(MDP_Y_CBCR_H1V1);
+ formats[MDP_YCRCB_H1V1] = STR(MDP_YCRCB_H1V1);
+ formats[MDP_YCBCR_H1V1] = STR(MDP_YCBCR_H1V1);
+ formats[MDP_BGR_565] = STR(MDP_BGR_565);
+ formats[MDP_BGR_888] = STR(MDP_BGR_888);
+ formats[MDP_Y_CBCR_H2V2_VENUS] = STR(MDP_Y_CBCR_H2V2_VENUS);
+ formats[MDP_BGRX_8888] = STR(MDP_BGRX_8888);
+ formats[MDP_RGBA_8888_TILE] = STR(MDP_RGBA_8888_TILE);
+ formats[MDP_ARGB_8888_TILE] = STR(MDP_ARGB_8888_TILE);
+ formats[MDP_ABGR_8888_TILE] = STR(MDP_ABGR_8888_TILE);
+ formats[MDP_BGRA_8888_TILE] = STR(MDP_BGRA_8888_TILE);
+ formats[MDP_RGBX_8888_TILE] = STR(MDP_RGBX_8888_TILE);
+ formats[MDP_XRGB_8888_TILE] = STR(MDP_XRGB_8888_TILE);
+ formats[MDP_XBGR_8888_TILE] = STR(MDP_XBGR_8888_TILE);
+ formats[MDP_BGRX_8888_TILE] = STR(MDP_BGRX_8888_TILE);
+ formats[MDP_RGB_565_TILE] = STR(MDP_RGB_565_TILE);
+ formats[MDP_IMGTYPE_LIMIT] = STR(MDP_IMGTYPE_LIMIT);
+
+ if(format < 0 || format >= MDP_IMGTYPE_LIMIT) {
+ ALOGE("%s wrong fmt %d", __FUNCTION__, format);
+ return "Unsupported format";
+ }
+ if(formats[format] == 0) {
+ ALOGE("%s: table missing format %d from header", __FUNCTION__, format);
+ return "";
+ }
+ return formats[format];
+}
+
+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);
+}
+
+template <class Type>
+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 bool openDev(OvFD& fd, int fbnum,
+ const char* const devpath, int flags) {
+ return overlay::open(fd, fbnum, devpath, flags);
+}
+
+template <class T>
+inline void even_ceil(T& value) {
+ if(value & 1)
+ value++;
+}
+
+template <class T>
+inline void even_floor(T& value) {
+ if(value & 1)
+ value--;
+}
+
+/* Prerotation adjusts crop co-ordinates to the new transformed values within
+ * destination buffer. This is necessary only when the entire buffer is rotated
+ * irrespective of crop (A-family). If only the crop portion of the buffer is
+ * rotated into a destination buffer matching the size of crop, we don't need to
+ * use this helper (B-family).
+ * @Deprecated as of now, retained for the case where a full buffer needs
+ * transform and also as a reference.
+ */
+void preRotateSource(const eTransform& tr, Whf& whf, Dim& srcCrop);
+void getDump(char *buf, size_t len, const char *prefix, const mdp_overlay& ov);
+void getDump(char *buf, size_t len, const char *prefix, const msmfb_img& ov);
+void getDump(char *buf, size_t len, const char *prefix, const mdp_rect& ov);
+void getDump(char *buf, size_t len, const char *prefix,
+ const msmfb_overlay_data& ov);
+void getDump(char *buf, size_t len, const char *prefix, const msmfb_data& ov);
+void getDump(char *buf, size_t len, const char *prefix,
+ const msm_rotator_img_info& ov);
+void getDump(char *buf, size_t len, const char *prefix,
+ const msm_rotator_data_info& ov);
+
+} // namespace utils ends
+
+//--------------------Class Res stuff (namespace overlay only) -----------
+
+class Res {
+public:
+ // /dev/graphics/fb%u
+ static const char* const fbPath;
+ // /dev/msm_rotator
+ static const char* const rotPath;
+};
+
+
+//--------------------Class OvFD stuff (namespace overlay only) -----------
+
+/*
+* 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 since copy() can be used to share fd, in 3d cases.
+}
+
+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)
+{
+ ::strlcpy(mPath, dev, sizeof(mPath));
+}
+
+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/msm8909/liboverlay/overlayWriteback.cpp b/msm8909/liboverlay/overlayWriteback.cpp
new file mode 100644
index 0000000..ed42a9f
--- /dev/null
+++ b/msm8909/liboverlay/overlayWriteback.cpp
@@ -0,0 +1,280 @@
+/*
+* Copyright (c) 2013 The Linux Foundation. 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 The Linux Foundation. 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 "overlay.h"
+#include "overlayWriteback.h"
+#include "mdpWrapper.h"
+
+#define SIZE_1M 0x00100000
+
+namespace overlay {
+
+//=========== class WritebackMem ==============================================
+bool WritebackMem::manageMem(uint32_t size, bool isSecure) {
+ if(mBuf.bufSz() == size) {
+ return true;
+ }
+ if(mBuf.valid()) {
+ if(!mBuf.close()) {
+ ALOGE("%s error closing mem", __func__);
+ return false;
+ }
+ }
+ return alloc(size, isSecure);
+}
+
+bool WritebackMem::alloc(uint32_t size, bool isSecure) {
+ if(!mBuf.open(NUM_BUFS, size, isSecure)){
+ ALOGE("%s: Failed to open", __func__);
+ mBuf.close();
+ return false;
+ }
+
+ OVASSERT(MAP_FAILED != mBuf.addr(), "MAP failed");
+ OVASSERT(mBuf.getFD() != -1, "getFd is -1");
+
+ mCurrOffsetIndex = 0;
+ for (uint32_t i = 0; i < NUM_BUFS; i++) {
+ mOffsets[i] = i * size;
+ }
+ return true;
+}
+
+bool WritebackMem::dealloc() {
+ bool ret = true;
+ if(mBuf.valid()) {
+ ret = mBuf.close();
+ }
+ return ret;
+}
+
+//=========== class Writeback =================================================
+Writeback::Writeback() : mXres(0), mYres(0), mOpFmt(-1), mSecure(false) {
+ int fbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
+ if(!utils::openDev(mFd, fbNum, Res::fbPath, O_RDWR)) {
+ ALOGE("%s failed to init %s", __func__, Res::fbPath);
+ return;
+ }
+ startSession();
+}
+
+Writeback::~Writeback() {
+ stopSession();
+ if (!mFd.close()) {
+ ALOGE("%s error closing fd", __func__);
+ }
+}
+
+bool Writeback::startSession() {
+ if(!mdp_wrapper::wbInitStart(mFd.getFD())) {
+ ALOGE("%s failed", __func__);
+ return false;
+ }
+ return true;
+}
+
+bool Writeback::stopSession() {
+ if(mFd.valid()) {
+ if(!Overlay::displayCommit(mFd.getFD())) {
+ ALOGE("%s: displayCommit failed", __func__);
+ return false;
+ }
+ if(!mdp_wrapper::wbStopTerminate(mFd.getFD())) {
+ ALOGE("%s: wbStopTerminate failed", __func__);
+ return false;
+ }
+ } else {
+ ALOGE("%s Invalid fd", __func__);
+ return false;
+ }
+ return true;
+}
+
+bool Writeback::configureDpyInfo(int xres, int yres) {
+ if(mXres != xres || mYres != yres) {
+ fb_var_screeninfo vinfo;
+ memset(&vinfo, 0, sizeof(fb_var_screeninfo));
+ if(!mdp_wrapper::getVScreenInfo(mFd.getFD(), vinfo)) {
+ ALOGE("%s failed", __func__);
+ return false;
+ }
+ vinfo.xres = xres;
+ vinfo.yres = yres;
+ vinfo.xres_virtual = xres;
+ vinfo.yres_virtual = yres;
+ vinfo.xoffset = 0;
+ vinfo.yoffset = 0;
+ if(!mdp_wrapper::setVScreenInfo(mFd.getFD(), vinfo)) {
+ ALOGE("%s failed", __func__);
+ return false;
+ }
+ mXres = xres;
+ mYres = yres;
+ }
+ return true;
+}
+
+bool Writeback::configureMemory(uint32_t size) {
+ if(!mWbMem.manageMem(size, mSecure)) {
+ ALOGE("%s failed, memory failure", __func__);
+ return false;
+ }
+ return true;
+}
+
+bool Writeback::queueBuffer(int opFd, uint32_t opOffset) {
+ memset(&mFbData, 0, sizeof(struct msmfb_data));
+ //Queue
+ mFbData.offset = opOffset;
+ mFbData.memory_id = opFd;
+ mFbData.id = 0;
+ mFbData.flags = 0;
+ if(!mdp_wrapper::wbQueueBuffer(mFd.getFD(), mFbData)) {
+ ALOGE("%s: queuebuffer failed", __func__);
+ return false;
+ }
+ return true;
+}
+
+bool Writeback::dequeueBuffer() {
+ //Dequeue
+ mFbData.flags = MSMFB_WRITEBACK_DEQUEUE_BLOCKING;
+ if(!mdp_wrapper::wbDequeueBuffer(mFd.getFD(), mFbData)) {
+ ALOGE("%s: dequeuebuffer failed", __func__);
+ return false;
+ }
+ return true;
+}
+
+bool Writeback::writeSync(int opFd, uint32_t opOffset) {
+ if(!queueBuffer(opFd, opOffset)) {
+ return false;
+ }
+ if(!Overlay::displayCommit(mFd.getFD())) {
+ return false;
+ }
+ if(!dequeueBuffer()) {
+ return false;
+ }
+ return true;
+}
+
+bool Writeback::writeSync() {
+ mWbMem.useNextBuffer();
+ return writeSync(mWbMem.getDstFd(), mWbMem.getOffset());
+}
+
+bool Writeback::setOutputFormat(int mdpFormat) {
+ if(mdpFormat != mOpFmt) {
+ struct msmfb_metadata metadata;
+ memset(&metadata, 0 , sizeof(metadata));
+ metadata.op = metadata_op_wb_format;
+ metadata.data.mixer_cfg.writeback_format = mdpFormat;
+ if (ioctl(mFd.getFD(), MSMFB_METADATA_SET, &metadata) < 0) {
+ ALOGE("Error setting MDP Writeback format");
+ return false;
+ }
+ mOpFmt = mdpFormat;
+ }
+ return true;
+}
+
+int Writeback::getOutputFormat() {
+ if(mOpFmt < 0) {
+ struct msmfb_metadata metadata;
+ memset(&metadata, 0 , sizeof(metadata));
+ metadata.op = metadata_op_wb_format;
+ if (ioctl(mFd.getFD(), MSMFB_METADATA_GET, &metadata) < 0) {
+ ALOGE("Error retrieving MDP Writeback format");
+ return -1;
+ }
+ mOpFmt = metadata.data.mixer_cfg.writeback_format;
+ }
+ return mOpFmt;
+}
+
+bool Writeback::setSecure(bool isSecure) {
+ if(isSecure != mSecure) {
+ // Call IOCTL to set WB interface as secure
+ struct msmfb_metadata metadata;
+ memset(&metadata, 0 , sizeof(metadata));
+ metadata.op = metadata_op_wb_secure;
+ metadata.data.secure_en = isSecure;
+ if (ioctl(mFd.getFD(), MSMFB_METADATA_SET, &metadata) < 0) {
+ ALOGE("Error setting MDP WB secure");
+ return false;
+ }
+ mSecure = isSecure;
+ }
+ return true;
+}
+
+//static
+
+Writeback *Writeback::getInstance() {
+ if(sWb == NULL) {
+ sWb = new Writeback();
+ }
+ sUsed = true;
+ return sWb;
+}
+
+void Writeback::configDone() {
+ if(sUsed == false && sWb) {
+ delete sWb;
+ sWb = NULL;
+ }
+}
+
+void Writeback::clear() {
+ sUsed = false;
+ if(sWb) {
+ delete sWb;
+ sWb = NULL;
+ }
+}
+
+bool Writeback::getDump(char *buf, size_t len) {
+ if(sWb) {
+ utils::getDump(buf, len, "WBData", sWb->mFbData);
+ char outputBufferInfo[256];
+ snprintf(outputBufferInfo, sizeof(outputBufferInfo),
+ "OutputBuffer xres=%d yres=%d format=%s\n\n",
+ sWb->getWidth(), sWb->getHeight(),
+ utils::getFormatString(sWb->getOutputFormat()));
+ strlcat(buf, outputBufferInfo, len);
+ return true;
+ }
+ return false;
+}
+
+Writeback *Writeback::sWb = 0;
+bool Writeback::sUsed = false;
+
+} //namespace overlay
diff --git a/msm8909/liboverlay/overlayWriteback.h b/msm8909/liboverlay/overlayWriteback.h
new file mode 100644
index 0000000..21186e6
--- /dev/null
+++ b/msm8909/liboverlay/overlayWriteback.h
@@ -0,0 +1,122 @@
+/*
+* Copyright (c) 2013 The Linux Foundation. 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 The Linux Foundation. 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_WRITEBACK_H
+#define OVERLAY_WRITEBACK_H
+
+#include "overlayMem.h"
+
+namespace overlay {
+
+class WritebackMgr;
+
+class WritebackMem {
+public:
+ explicit WritebackMem() : mCurrOffsetIndex(0) {
+ memset(&mOffsets, 0, sizeof(mOffsets));
+ }
+ ~WritebackMem() { dealloc(); }
+ bool manageMem(uint32_t size, bool isSecure);
+ void useNextBuffer() {
+ mCurrOffsetIndex = (mCurrOffsetIndex + 1) % NUM_BUFS;
+ }
+ uint32_t getOffset() const { return mOffsets[mCurrOffsetIndex]; }
+ int getDstFd() const { return mBuf.getFD(); }
+private:
+ bool alloc(uint32_t size, bool isSecure);
+ bool dealloc();
+ enum { NUM_BUFS = 2 };
+ OvMem mBuf;
+ uint32_t mOffsets[NUM_BUFS];
+ uint32_t mCurrOffsetIndex;
+};
+
+//Abstracts the WB2 interface of MDP
+//Has modes to either manage memory or work with memory allocated elsewhere
+class Writeback {
+public:
+ ~Writeback();
+ bool configureDpyInfo(int xres, int yres);
+ bool configureMemory(uint32_t size);
+ /* Blocking write. (queue, commit, dequeue)
+ * This class will do writeback memory management.
+ * This class will call display-commit on writeback mixer.
+ */
+ bool writeSync();
+ /* Blocking write. (queue, commit, dequeue)
+ * Client must do writeback memory management.
+ * Client must not call display-commit on writeback mixer.
+ */
+ bool writeSync(int opFd, uint32_t opOffset);
+ /* Async queue. (Does not write)
+ * Client must do writeback memory management.
+ * Client must call display-commit on their own.
+ * Client must use sync mechanism e.g sync pt.
+ */
+ bool queueBuffer(int opFd, uint32_t opOffset);
+ uint32_t getOffset() const { return mWbMem.getOffset(); }
+ int getDstFd() const { return mWbMem.getDstFd(); }
+ int getWidth() const { return mXres; }
+ int getHeight() const { return mYres; }
+ /* Subject to GC if writeback isnt used for a drawing round.
+ * Get always if caching the value.
+ */
+ int getFbFd() const { return mFd.getFD(); }
+ int getOutputFormat();
+ bool setOutputFormat(int mdpFormat);
+ bool setSecure(bool isSecure);
+
+ static Writeback* getInstance();
+ static void configBegin() { sUsed = false; }
+ static void configDone();
+ static void clear();
+ //Will take a dump of data structure only if there is an instance existing
+ //Returns true if dump is added to the input buffer, false otherwise
+ static bool getDump(char *buf, size_t len);
+
+private:
+ explicit Writeback();
+ bool startSession();
+ bool stopSession();
+ //Actually block_until_write_done for the usage here.
+ bool dequeueBuffer();
+ OvFD mFd;
+ WritebackMem mWbMem;
+ struct msmfb_data mFbData;
+ int mXres;
+ int mYres;
+ int mOpFmt;
+ bool mSecure;
+
+ static bool sUsed;
+ static Writeback *sWb;
+};
+
+}
+
+#endif
diff --git a/msm8909/liboverlay/pipes/overlayGenPipe.cpp b/msm8909/liboverlay/pipes/overlayGenPipe.cpp
new file mode 100644
index 0000000..aebaebf
--- /dev/null
+++ b/msm8909/liboverlay/pipes/overlayGenPipe.cpp
@@ -0,0 +1,124 @@
+/*
+* Copyright (c) 2012-2013, The Linux Foundation. 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 The Linux Foundation 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 "overlayGenPipe.h"
+#include "mdp_version.h"
+
+namespace overlay {
+
+GenericPipe::GenericPipe(const int& dpy) : mDpy(dpy),
+ mCtrl(new Ctrl(dpy)), mData(new Data(dpy)) {
+}
+
+GenericPipe::~GenericPipe() {
+ delete mCtrl;
+ delete mData;
+}
+
+void GenericPipe::setSource(const utils::PipeArgs& args) {
+ mCtrl->setSource(args);
+}
+
+void GenericPipe::setCrop(const overlay::utils::Dim& d) {
+ mCtrl->setCrop(d);
+}
+
+void GenericPipe::setColor(const uint32_t color) {
+ mCtrl->setColor(color);
+}
+
+void GenericPipe::setTransform(const utils::eTransform& orient) {
+ mCtrl->setTransform(orient);
+}
+
+void GenericPipe::setPosition(const utils::Dim& d) {
+ mCtrl->setPosition(d);
+}
+
+bool GenericPipe::setVisualParams(const MetaData_t &metadata)
+{
+ return mCtrl->setVisualParams(metadata);
+}
+
+void GenericPipe::setPipeType(const utils::eMdpPipeType& pType) {
+ mCtrl->setPipeType(pType);
+}
+
+bool GenericPipe::commit() {
+ return mCtrl->commit();
+}
+
+bool GenericPipe::queueBuffer(int fd, uint32_t offset) {
+ int pipeId = mCtrl->getPipeId();
+ OVASSERT(-1 != pipeId, "Ctrl ID should not be -1");
+ // set pipe id from ctrl to data
+ mData->setPipeId(pipeId);
+
+ return mData->queueBuffer(fd, offset);
+}
+
+utils::Dim GenericPipe::getCrop() const
+{
+ return mCtrl->getCrop();
+}
+
+uint8_t GenericPipe::getPriority() const {
+ return mCtrl->getPriority();
+}
+
+void GenericPipe::dump() const
+{
+ ALOGE("== Dump Generic pipe start ==");
+ mCtrl->dump();
+ mData->dump();
+ ALOGE("== Dump Generic pipe end ==");
+}
+
+void GenericPipe::getDump(char *buf, size_t len) {
+ mCtrl->getDump(buf, len);
+ mData->getDump(buf, len);
+}
+
+int GenericPipe::getPipeId() {
+ return mCtrl->getPipeId();
+}
+
+bool GenericPipe::validateAndSet(GenericPipe* pipeArray[], const int& count,
+ const int& fbFd) {
+ Ctrl* ctrlArray[count];
+ memset(&ctrlArray, 0, sizeof(ctrlArray));
+
+ for(int i = 0; i < count; i++) {
+ ctrlArray[i] = pipeArray[i]->mCtrl;
+ }
+
+ return Ctrl::validateAndSet(ctrlArray, count, fbFd);
+}
+
+} //namespace overlay
diff --git a/msm8909/liboverlay/pipes/overlayGenPipe.h b/msm8909/liboverlay/pipes/overlayGenPipe.h
new file mode 100644
index 0000000..0a2639a
--- /dev/null
+++ b/msm8909/liboverlay/pipes/overlayGenPipe.h
@@ -0,0 +1,86 @@
+/*
+* Copyright (c) 2011-2013, The Linux Foundation. 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 The Linux Foundation 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 "overlayCtrlData.h"
+
+namespace overlay {
+
+class GenericPipe : utils::NoCopy {
+public:
+ /* ctor */
+ explicit GenericPipe(const int& dpy);
+ /* dtor */
+ ~GenericPipe();
+ /* Control APIs */
+ /* set source using whf, orient and wait flag */
+ void setSource(const utils::PipeArgs& args);
+ /* set crop a.k.a the region of interest */
+ void setCrop(const utils::Dim& d);
+ /* set color for mdp pipe */
+ void setColor(const uint32_t color);
+ /* set orientation*/
+ void setTransform(const utils::eTransform& param);
+ /* set mdp posision using dim */
+ void setPosition(const utils::Dim& dim);
+ /* set visual param */
+ bool setVisualParams(const MetaData_t &metadata);
+ /* set pipe type RGB/DMA/VG */
+ void setPipeType(const utils::eMdpPipeType& pType);
+ /* commit changes to the overlay "set"*/
+ bool commit();
+ /* Data APIs */
+ /* queue buffer to the overlay */
+ bool queueBuffer(int fd, uint32_t offset);
+ /* return cached startup args */
+ const utils::PipeArgs& getArgs() const;
+ /* retrieve cached crop data */
+ utils::Dim getCrop() const;
+ /* return pipe priority */
+ uint8_t getPriority() const;
+ /* dump the state of the object */
+ void dump() const;
+ /* Return the dump in the specified buffer */
+ void getDump(char *buf, size_t len);
+ int getPipeId();
+
+ static bool validateAndSet(GenericPipe* pipeArray[], const int& count,
+ const int& fbFd);
+private:
+ int mDpy;
+ Ctrl *mCtrl;
+ Data *mData;
+};
+
+} //namespace overlay
+
+#endif // OVERLAY_GENERIC_PIPE_H
diff --git a/msm8909/libqdutils/Android.mk b/msm8909/libqdutils/Android.mk
new file mode 100644
index 0000000..212c8d8
--- /dev/null
+++ b/msm8909/libqdutils/Android.mk
@@ -0,0 +1,33 @@
+LOCAL_PATH := $(call my-dir)
+include $(LOCAL_PATH)/../common.mk
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libqdutils
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := $(common_libs) libui libbinder libqservice
+LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
+LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdutils\"
+LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
+LOCAL_COPY_HEADERS_TO := $(common_header_export_path)
+LOCAL_COPY_HEADERS := display_config.h mdp_version.h
+LOCAL_SRC_FILES := profiler.cpp mdp_version.cpp \
+ idle_invalidator.cpp \
+ comptype.cpp qd_utils.cpp \
+ cb_utils.cpp display_config.cpp \
+ cb_swap_rect.cpp
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_COPY_HEADERS_TO := $(common_header_export_path)
+LOCAL_COPY_HEADERS := qdMetaData.h
+LOCAL_SHARED_LIBRARIES := liblog libcutils
+LOCAL_C_INCLUDES := $(common_includes)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
+LOCAL_SRC_FILES := qdMetaData.cpp
+LOCAL_CFLAGS := $(common_flags)
+LOCAL_CFLAGS += -DLOG_TAG=\"DisplayMetaData\"
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := libqdMetaData
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/msm8909/libqdutils/cb_swap_rect.cpp b/msm8909/libqdutils/cb_swap_rect.cpp
new file mode 100644
index 0000000..8c8efec
--- /dev/null
+++ b/msm8909/libqdutils/cb_swap_rect.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014, The Linux Foundation. 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 The Linux Foundation or 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 "cb_swap_rect.h"
+
+ANDROID_SINGLETON_STATIC_INSTANCE(qdutils::cb_swap_rect);
+
+namespace qdutils {
+
+cb_swap_rect:: cb_swap_rect(){
+ swap_rect_feature_on = false ;
+}
+void cb_swap_rect::setSwapRectFeature_on( bool value){
+ swap_rect_feature_on = value ;
+}
+bool cb_swap_rect::checkSwapRectFeature_on(){
+ return swap_rect_feature_on;
+}
+
+};
diff --git a/msm8909/libqdutils/cb_swap_rect.h b/msm8909/libqdutils/cb_swap_rect.h
new file mode 100644
index 0000000..daaeb37
--- /dev/null
+++ b/msm8909/libqdutils/cb_swap_rect.h
@@ -0,0 +1,51 @@
+/* Copyright (c) 2014, The Linux Foundation. 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 copyrigh
+* 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 The Linux Foundation 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 CB_SWAP_RECT
+#define CB_SWAP_RECT
+
+#include <stdint.h>
+#include <utils/Singleton.h>
+#include <cutils/log.h>
+
+using namespace android;
+namespace qdutils {
+enum {
+HWC_SKIP_HWC_COMPOSITION = 0x00040000,
+};
+
+class cb_swap_rect : public Singleton <cb_swap_rect>
+{
+ bool swap_rect_feature_on;
+ public :
+ cb_swap_rect();
+ void setSwapRectFeature_on( bool value);
+ bool checkSwapRectFeature_on();
+};
+} // namespace qdutils
+#endif
diff --git a/msm8909/libqdutils/cb_utils.cpp b/msm8909/libqdutils/cb_utils.cpp
new file mode 100644
index 0000000..9c533a2
--- /dev/null
+++ b/msm8909/libqdutils/cb_utils.cpp
@@ -0,0 +1,133 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 copyrigh
+* 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 The Linux Foundation 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 "cb_utils.h"
+#include "cb_swap_rect.h"
+/* get union of two rects into 3rd rect */
+void getUnion(hwc_rect_t& rect1,hwc_rect_t& rect2, hwc_rect_t& irect) {
+
+ irect.left = min(rect1.left, rect2.left);
+ irect.top = min(rect1.top, rect2.top);
+ irect.right = max(rect1.right, rect2.right);
+ irect.bottom = max(rect1.bottom, rect2.bottom);
+}
+
+int clear (copybit_device_t *copybit, private_handle_t* hnd, hwc_rect_t& rect)
+{
+ int ret = 0;
+ copybit_rect_t clear_rect = {rect.left, rect.top,rect.right,rect.bottom};
+
+ copybit_image_t buf;
+ buf.w = ALIGN(getWidth(hnd),32);
+ buf.h = getHeight(hnd);
+ buf.format = hnd->format;
+ buf.base = (void *)hnd->base;
+ buf.handle = (native_handle_t *)hnd;
+
+ ret = copybit->clear(copybit, &buf, &clear_rect);
+ return ret;
+}
+using namespace android;
+using namespace qhwc;
+namespace qdutils {
+
+int CBUtils::uiClearRegion(hwc_display_contents_1_t* list,
+ int version, LayerProp *layerProp, hwc_rect_t dirtyRect,
+ copybit_device_t *copybit, private_handle_t *renderBuffer) {
+
+ size_t last = list->numHwLayers - 1;
+ hwc_rect_t fbFrame = list->hwLayers[last].displayFrame;
+ Rect fbFrameRect(fbFrame.left,fbFrame.top,fbFrame.right,fbFrame.bottom);
+ Region wormholeRegion(fbFrameRect);
+
+ if ((dirtyRect.right - dirtyRect.left > 0) &&
+ (dirtyRect.bottom - dirtyRect.top > 0)) {
+#ifdef QTI_BSP
+ Rect tmpRect(dirtyRect.left,dirtyRect.top,dirtyRect.right,
+ dirtyRect.bottom);
+ Region tmpRegion(tmpRect);
+ wormholeRegion = wormholeRegion.intersect(tmpRegion);
+#endif
+ }
+ if(cb_swap_rect::getInstance().checkSwapRectFeature_on() == true){
+ wormholeRegion.set(0,0);
+ for(size_t i = 0 ; i < last; i++) {
+ if(((list->hwLayers[i].blending == HWC_BLENDING_NONE) &&
+ (list->hwLayers[i].planeAlpha == 0xFF)) ||
+ !(layerProp[i].mFlags & HWC_COPYBIT) ||
+ (list->hwLayers[i].flags & HWC_SKIP_HWC_COMPOSITION))
+ continue ;
+ hwc_rect_t displayFrame = list->hwLayers[i].displayFrame;
+ Rect tmpRect(displayFrame.left,displayFrame.top,
+ displayFrame.right,displayFrame.bottom);
+ wormholeRegion.set(tmpRect);
+ }
+ }else{
+ for (size_t i = 0 ; i < last; i++) {
+ // need to take care only in per pixel blending.
+ // Restrict calculation only for copybit layers.
+ if((list->hwLayers[i].blending != HWC_BLENDING_NONE) ||
+ (list->hwLayers[i].planeAlpha != 0xFF) ||
+ !(layerProp[i].mFlags & HWC_COPYBIT))
+ continue ;
+ hwc_rect_t displayFrame = list->hwLayers[i].displayFrame;
+ Rect tmpRect(displayFrame.left,displayFrame.top,displayFrame.right,
+ displayFrame.bottom);
+ Region tmpRegion(tmpRect);
+ wormholeRegion.subtractSelf(wormholeRegion.intersect(tmpRegion));
+ }
+ }
+ if(wormholeRegion.isEmpty()){
+ return 1;
+ }
+ //TO DO :- 1. remove union and call clear for each rect.
+ Region::const_iterator it = wormholeRegion.begin();
+ Region::const_iterator const end = wormholeRegion.end();
+ while (it != end) {
+ const Rect& r = *it++;
+ hwc_rect_t tmpWormRect = {r.left,r.top,r.right,r.bottom};
+ if (version == qdutils::MDP_V3_0_4 ||
+ version == qdutils::MDP_V3_0_5) {
+ int clear_w = tmpWormRect.right - tmpWormRect.left;
+ int clear_h = tmpWormRect.bottom - tmpWormRect.top;
+ //mdp can't handle solid fill for one line
+ //making solid fill as full in this case
+ //disable swap rect if presents
+ if ((clear_w == 1) || (clear_h ==1)) {
+ clear(copybit, renderBuffer, fbFrame);
+ return 0;
+ } else {
+ clear(copybit, renderBuffer, tmpWormRect);
+ }
+ } else {
+ clear(copybit, renderBuffer, tmpWormRect);
+ }
+ }
+ return 1;
+}
+
+}//namespace qdutils
diff --git a/msm8909/libqdutils/cb_utils.h b/msm8909/libqdutils/cb_utils.h
new file mode 100644
index 0000000..55225b6
--- /dev/null
+++ b/msm8909/libqdutils/cb_utils.h
@@ -0,0 +1,46 @@
+/* Copyright (c) 2013, The Linux Foundation. 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 copyrigh
+* 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 The Linux Foundation 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 CB_UTIL_H
+#define CB_UTIL_H
+
+#include <ui/Region.h>
+#include "hwc_utils.h"
+#include "copybit.h"
+
+using namespace qhwc;
+namespace qdutils {
+class CBUtils {
+public:
+ static int uiClearRegion(hwc_display_contents_1_t* list,
+ int version, LayerProp *layerProp, hwc_rect_t dirtyIndex,
+ copybit_device_t *copybit, private_handle_t *renderBuffer);
+};
+}//namespace qdutils
+#endif /* end of include guard: CB_UTIL_H*/
+
diff --git a/msm8909/libqdutils/comptype.cpp b/msm8909/libqdutils/comptype.cpp
new file mode 100644
index 0000000..a29158a
--- /dev/null
+++ b/msm8909/libqdutils/comptype.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013, The Linux Foundation. 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 The Linux Foundation or 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<comptype.h>
+
+//Instanticate the QCCompositionType Singleton
+ANDROID_SINGLETON_STATIC_INSTANCE(qdutils::QCCompositionType);
diff --git a/msm8909/libqdutils/comptype.h b/msm8909/libqdutils/comptype.h
new file mode 100644
index 0000000..71f4871
--- /dev/null
+++ b/msm8909/libqdutils/comptype.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2012-2013, The Linux Foundation. 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 The Linux Foundation or 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 <stdint.h>
+#include <utils/Singleton.h>
+#include <cutils/properties.h>
+
+using namespace android;
+namespace qdutils {
+// 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 <QCCompositionType>
+{
+ public:
+ QCCompositionType();
+ ~QCCompositionType() { }
+ int getCompositionType() {return mCompositionType;}
+ private:
+ int mCompositionType;
+
+};
+
+inline QCCompositionType::QCCompositionType()
+{
+ char property[PROPERTY_VALUE_MAX];
+ mCompositionType = COMPOSITION_TYPE_GPU;
+ if (property_get("debug.composition.type", property, "gpu") > 0) {
+ 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
+ }
+ }
+}
+
+}; //namespace qdutils
+#endif //INCLUDE_LIBQCOM_COMPTYPES
diff --git a/msm8909/libqdutils/display_config.cpp b/msm8909/libqdutils/display_config.cpp
new file mode 100644
index 0000000..62422fe
--- /dev/null
+++ b/msm8909/libqdutils/display_config.cpp
@@ -0,0 +1,191 @@
+/*
+* Copyright (c) 2013-2015 The Linux Foundation. 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 The Linux Foundation. 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 <display_config.h>
+#include <QServiceUtils.h>
+
+using namespace android;
+using namespace qService;
+
+namespace qdutils {
+
+int isExternalConnected(void) {
+ int ret;
+ status_t err = (status_t) FAILED_TRANSACTION;
+ sp<IQService> binder = getBinder();
+ Parcel inParcel, outParcel;
+ if(binder != NULL) {
+ err = binder->dispatch(IQService::CHECK_EXTERNAL_STATUS,
+ &inParcel , &outParcel);
+ }
+ if(err) {
+ ALOGE("%s: Failed to get external status err=%d", __FUNCTION__, err);
+ ret = err;
+ } else {
+ ret = outParcel.readInt32();
+ }
+ return ret;
+}
+
+int getDisplayAttributes(int dpy, DisplayAttributes_t& dpyattr) {
+ status_t err = (status_t) FAILED_TRANSACTION;
+ sp<IQService> binder = getBinder();
+ Parcel inParcel, outParcel;
+ inParcel.writeInt32(dpy);
+ if(binder != NULL) {
+ err = binder->dispatch(IQService::GET_DISPLAY_ATTRIBUTES,
+ &inParcel, &outParcel);
+ }
+ if(!err) {
+ dpyattr.vsync_period = outParcel.readInt32();
+ dpyattr.xres = outParcel.readInt32();
+ dpyattr.yres = outParcel.readInt32();
+ dpyattr.xdpi = outParcel.readFloat();
+ dpyattr.ydpi = outParcel.readFloat();
+ dpyattr.panel_type = (char) outParcel.readInt32();
+ } else {
+ ALOGE("%s: Failed to get display attributes err=%d", __FUNCTION__, err);
+ }
+ return err;
+}
+
+int setHSIC(int dpy, const HSICData_t& hsic_data) {
+ status_t err = (status_t) FAILED_TRANSACTION;
+ sp<IQService> binder = getBinder();
+ Parcel inParcel, outParcel;
+ inParcel.writeInt32(dpy);
+ inParcel.writeInt32(hsic_data.hue);
+ inParcel.writeFloat(hsic_data.saturation);
+ inParcel.writeInt32(hsic_data.intensity);
+ inParcel.writeFloat(hsic_data.contrast);
+ if(binder != NULL) {
+ err = binder->dispatch(IQService::SET_HSIC_DATA, &inParcel, &outParcel);
+ }
+ if(err)
+ ALOGE("%s: Failed to get external status err=%d", __FUNCTION__, err);
+ return err;
+}
+
+int getDisplayVisibleRegion(int dpy, hwc_rect_t &rect) {
+ status_t err = (status_t) FAILED_TRANSACTION;
+ sp<IQService> binder = getBinder();
+ Parcel inParcel, outParcel;
+ inParcel.writeInt32(dpy);
+ if(binder != NULL) {
+ err = binder->dispatch(IQService::GET_DISPLAY_VISIBLE_REGION,
+ &inParcel, &outParcel);
+ }
+ if(!err) {
+ rect.left = outParcel.readInt32();
+ rect.top = outParcel.readInt32();
+ rect.right = outParcel.readInt32();
+ rect.bottom = outParcel.readInt32();
+ } else {
+ ALOGE("%s: Failed to getVisibleRegion for dpy =%d: err = %d",
+ __FUNCTION__, dpy, err);
+ }
+ return err;
+}
+
+int setViewFrame(int dpy, int l, int t, int r, int b) {
+ status_t err = (status_t) FAILED_TRANSACTION;
+ sp<IQService> binder = getBinder();
+ Parcel inParcel, outParcel;
+ inParcel.writeInt32(dpy);
+ inParcel.writeInt32(l);
+ inParcel.writeInt32(t);
+ inParcel.writeInt32(r);
+ inParcel.writeInt32(b);
+
+ if(binder != NULL) {
+ err = binder->dispatch(IQService::SET_VIEW_FRAME,
+ &inParcel, &outParcel);
+ }
+ if(err)
+ ALOGE("%s: Failed to set view frame for dpy %d err=%d",
+ __FUNCTION__, dpy, err);
+
+ return err;
+}
+
+int setSecondaryDisplayStatus(int dpy, uint32_t status) {
+ status_t err = (status_t) FAILED_TRANSACTION;
+ sp<IQService> binder = getBinder();
+ Parcel inParcel, outParcel;
+ inParcel.writeInt32(dpy);
+ inParcel.writeInt32(status);
+
+ if(binder != NULL) {
+ err = binder->dispatch(IQService::SET_SECONDARY_DISPLAY_STATUS,
+ &inParcel, &outParcel);
+ }
+ if(err)
+ ALOGE("%s: Failed for dpy %d status = %d err=%d", __FUNCTION__, dpy,
+ status, err);
+
+ return err;
+}
+
+int configureDynRefreshRate(uint32_t op, uint32_t refreshRate) {
+ status_t err = (status_t) FAILED_TRANSACTION;
+ sp<IQService> binder = getBinder();
+ Parcel inParcel, outParcel;
+ inParcel.writeInt32(op);
+ inParcel.writeInt32(refreshRate);
+
+ if(binder != NULL) {
+ err = binder->dispatch(IQService::CONFIGURE_DYN_REFRESH_RATE,
+ &inParcel, &outParcel);
+ }
+
+ if(err)
+ ALOGE("%s: Failed setting op %d err=%d", __FUNCTION__, op, err);
+
+ return err;
+}
+
+}; //namespace
+
+// ----------------------------------------------------------------------------
+// Screen refresh for native daemons linking dynamically to libqdutils
+// ----------------------------------------------------------------------------
+extern "C" int refreshScreen() {
+ int ret = 0;
+ ret = screenRefresh();
+ return ret;
+}
+
+// ----------------------------------------------------------------------------
+// Native daemons needs to send enable partial update ack for PU to enable
+// ----------------------------------------------------------------------------
+extern "C" int setPartialUpdateState() {
+ int ret = 0;
+ ret = setPartialUpdate(IQService::ENABLE_PARTIAL_UPDATE);
+ return ret;
+}
diff --git a/msm8909/libqdutils/display_config.h b/msm8909/libqdutils/display_config.h
new file mode 100644
index 0000000..e9b2fc3
--- /dev/null
+++ b/msm8909/libqdutils/display_config.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2013 The Linux Foundation. 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 The Linux Foundation. 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 <gralloc_priv.h>
+#include <qdMetaData.h>
+#include <mdp_version.h>
+#include <hardware/hwcomposer.h>
+
+// This header is for clients to use to set/get global display configuration
+// The functions in this header run in the client process and wherever necessary
+// do a binder call to HWC to get/set data.
+// Only primary and external displays are supported here.
+// WiFi/virtual displays are not supported.
+
+namespace qdutils {
+
+// Use this enum to specify the dpy parameters where needed
+enum {
+ DISPLAY_PRIMARY = HWC_DISPLAY_PRIMARY,
+ DISPLAY_EXTERNAL = HWC_DISPLAY_EXTERNAL,
+ DISPLAY_VIRTUAL = HWC_DISPLAY_VIRTUAL,
+};
+
+// External Display states - used in setSecondaryDisplayStatus()
+// To be consistent with the same defined in hwc_utils.h
+enum {
+ EXTERNAL_OFFLINE = 0,
+ EXTERNAL_ONLINE,
+ EXTERNAL_PAUSE,
+ EXTERNAL_RESUME,
+};
+
+enum {
+ DISABLE_METADATA_DYN_REFRESH_RATE = 0,
+ ENABLE_METADATA_DYN_REFRESH_RATE,
+ SET_BINDER_DYN_REFRESH_RATE,
+};
+
+// Display Attributes that are available to clients of this library
+// Not to be confused with a similar struct in hwc_utils (in the hwc namespace)
+struct DisplayAttributes_t {
+ uint32_t vsync_period; //nanoseconds
+ uint32_t xres;
+ uint32_t yres;
+ float xdpi;
+ float ydpi;
+ char panel_type;
+};
+
+// Check if external display is connected. Useful to check before making
+// calls for external displays
+// Returns 1 if connected, 0 if disconnected, negative values on errors
+int isExternalConnected(void);
+
+// Get display vsync period which is in nanoseconds
+// i.e vsync_period = 1000000000l / fps
+// Returns 0 on success, negative values on errors
+int getDisplayAttributes(int dpy, DisplayAttributes_t& dpyattr);
+
+// Set HSIC data on a given display ID
+// Returns 0 on success, negative values on errors
+int setHSIC(int dpy, const HSICData_t& hsic_data);
+
+// get the active visible region for the display
+// Returns 0 on success, negative values on errors
+int getDisplayVisibleRegion(int dpy, hwc_rect_t &rect);
+
+// set the view frame information in hwc context from surfaceflinger
+int setViewFrame(int dpy, int l, int t, int r, int b);
+
+// Set the secondary display status(pause/resume/offline etc.,)
+int setSecondaryDisplayStatus(int dpy, uint32_t status);
+
+// Enable/Disable/Set refresh rate dynamically
+int configureDynRefreshRate(uint32_t op, uint32_t refreshRate);
+}; //namespace
diff --git a/msm8909/libqdutils/idle_invalidator.cpp b/msm8909/libqdutils/idle_invalidator.cpp
new file mode 100644
index 0000000..b8db0bf
--- /dev/null
+++ b/msm8909/libqdutils/idle_invalidator.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. 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 The Linux Foundation 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 "idle_invalidator.h"
+#include <unistd.h>
+#include <poll.h>
+#include <string.h>
+#include <fcntl.h>
+#include <cutils/properties.h>
+
+#define II_DEBUG 0
+#define IDLE_NOTIFY_PATH "/sys/devices/virtual/graphics/fb0/idle_notify"
+#define IDLE_TIME_PATH "/sys/devices/virtual/graphics/fb0/idle_time"
+
+
+static const char *threadName = "IdleInvalidator";
+InvalidatorHandler IdleInvalidator::mHandler = NULL;
+android::sp<IdleInvalidator> IdleInvalidator::sInstance(0);
+
+IdleInvalidator::IdleInvalidator(): Thread(false), mHwcContext(0),
+ mTimeoutEventFd(-1) {
+ ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
+}
+
+IdleInvalidator::~IdleInvalidator() {
+ if(mTimeoutEventFd >= 0) {
+ close(mTimeoutEventFd);
+ }
+}
+
+int IdleInvalidator::init(InvalidatorHandler reg_handler, void* user_data) {
+ mHandler = reg_handler;
+ mHwcContext = user_data;
+
+ // Open a sysfs node to receive the timeout notification from driver.
+ mTimeoutEventFd = open(IDLE_NOTIFY_PATH, O_RDONLY);
+ if (mTimeoutEventFd < 0) {
+ ALOGE ("%s:not able to open %s node %s",
+ __FUNCTION__, IDLE_NOTIFY_PATH, strerror(errno));
+ return -1;
+ }
+
+ int defaultIdleTime = 70; //ms
+ char property[PROPERTY_VALUE_MAX] = {0};
+ if((property_get("debug.mdpcomp.idletime", property, NULL) > 0)) {
+ defaultIdleTime = atoi(property);
+ }
+ if(not setIdleTimeout(defaultIdleTime)) {
+ close(mTimeoutEventFd);
+ mTimeoutEventFd = -1;
+ return -1;
+ }
+
+ //Triggers the threadLoop to run, if not already running.
+ run(threadName, android::PRIORITY_LOWEST);
+ return 0;
+}
+
+bool IdleInvalidator::setIdleTimeout(const uint32_t& timeout) {
+ ALOGD_IF(II_DEBUG, "IdleInvalidator::%s timeout %d",
+ __FUNCTION__, timeout);
+
+ // Open a sysfs node to send the timeout value to driver.
+ int fd = open(IDLE_TIME_PATH, O_WRONLY);
+
+ if (fd < 0) {
+ ALOGE ("%s:Unable to open %s node %s",
+ __FUNCTION__, IDLE_TIME_PATH, strerror(errno));
+ return false;
+ }
+
+ char strSleepTime[64];
+ snprintf(strSleepTime, sizeof(strSleepTime), "%d", timeout);
+
+ // Notify driver about the timeout value
+ ssize_t len = pwrite(fd, strSleepTime, strlen(strSleepTime), 0);
+ if(len < -1) {
+ ALOGE ("%s:Unable to write into %s node %s",
+ __FUNCTION__, IDLE_TIME_PATH, strerror(errno));
+ close(fd);
+ return false;
+ }
+
+ close(fd);
+ return true;
+}
+
+bool IdleInvalidator::threadLoop() {
+ ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
+ struct pollfd pFd;
+ pFd.fd = mTimeoutEventFd;
+ if (pFd.fd >= 0)
+ pFd.events = POLLPRI | POLLERR;
+ // Poll for an timeout event from driver
+ int err = poll(&pFd, 1, -1);
+ if(err > 0) {
+ if (pFd.revents & POLLPRI) {
+ char data[64];
+ // Consume the node by reading it
+ ssize_t len = pread(pFd.fd, data, 64, 0);
+ ALOGD_IF(II_DEBUG, "IdleInvalidator::%s Idle Timeout fired len %zd",
+ __FUNCTION__, len);
+ mHandler((void*)mHwcContext);
+ }
+ }
+ return true;
+}
+
+int IdleInvalidator::readyToRun() {
+ ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
+ return 0; /*NO_ERROR*/
+}
+
+void IdleInvalidator::onFirstRef() {
+ ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
+}
+
+IdleInvalidator *IdleInvalidator::getInstance() {
+ ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
+ if(sInstance.get() == NULL)
+ sInstance = new IdleInvalidator();
+ return sInstance.get();
+}
diff --git a/msm8909/libqdutils/idle_invalidator.h b/msm8909/libqdutils/idle_invalidator.h
new file mode 100644
index 0000000..52334a0
--- /dev/null
+++ b/msm8909/libqdutils/idle_invalidator.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. 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 The Linux Foundation 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 <cutils/log.h>
+#include <utils/threads.h>
+#include <gr.h>
+
+typedef void (*InvalidatorHandler)(void*);
+
+class IdleInvalidator : public android::Thread {
+ IdleInvalidator();
+ void *mHwcContext;
+ int mTimeoutEventFd;
+ static InvalidatorHandler mHandler;
+ static android::sp<IdleInvalidator> sInstance;
+
+public:
+ ~IdleInvalidator();
+ /* init timer obj */
+ int init(InvalidatorHandler reg_handler, void* user_data);
+ bool setIdleTimeout(const uint32_t& timeout);
+
+ /*Overrides*/
+ virtual bool threadLoop();
+ virtual int readyToRun();
+ virtual void onFirstRef();
+ static IdleInvalidator *getInstance();
+};
+
+#endif // INCLUDE_IDLEINVALIDATOR
diff --git a/msm8909/libqdutils/mdp_version.cpp b/msm8909/libqdutils/mdp_version.cpp
new file mode 100644
index 0000000..088f82b
--- /dev/null
+++ b/msm8909/libqdutils/mdp_version.cpp
@@ -0,0 +1,489 @@
+/*
+ * Copyright (c) 2012-2014, The Linux Foundation. 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 The Linux Foundation 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 <cutils/log.h>
+#include <linux/msm_mdp.h>
+#include "mdp_version.h"
+#include "qd_utils.h"
+
+#define DEBUG 0
+
+ANDROID_SINGLETON_STATIC_INSTANCE(qdutils::MDPVersion);
+namespace qdutils {
+
+#define TOKEN_PARAMS_DELIM "="
+
+// chip variants have same major number and minor numbers usually vary
+// for e.g., MDSS_MDP_HW_REV_101 is 0x10010000
+// 1001 - major number
+// 0000 - minor number
+// 8x26 v1 minor number is 0000
+// v2 minor number is 0001 etc..
+#ifndef MDSS_MDP_HW_REV_100
+#define MDSS_MDP_HW_REV_100 0x10000000 //8974 v1
+#endif
+#ifndef MDSS_MDP_HW_REV_101
+#define MDSS_MDP_HW_REV_101 0x10010000 //8x26
+#endif
+#ifndef MDSS_MDP_HW_REV_102
+#define MDSS_MDP_HW_REV_102 0x10020000 //8974 v2
+#endif
+#ifndef MDSS_MDP_HW_REV_103
+#define MDSS_MDP_HW_REV_103 0x10030000 //8084
+#endif
+#ifndef MDSS_MDP_HW_REV_104
+#define MDSS_MDP_HW_REV_104 0x10040000 //Next version
+#endif
+#ifndef MDSS_MDP_HW_REV_105
+#define MDSS_MDP_HW_REV_105 0x10050000 //8994
+#endif
+#ifndef MDSS_MDP_HW_REV_106
+#define MDSS_MDP_HW_REV_106 0x10060000 //8x16
+#endif
+#ifndef MDSS_MDP_HW_REV_107
+#define MDSS_MDP_HW_REV_107 0x10070000 //Next version
+#endif
+#ifndef MDSS_MDP_HW_REV_108
+#define MDSS_MDP_HW_REV_108 0x10080000 //8x39 & 8x36
+#endif
+#ifndef MDSS_MDP_HW_REV_109
+#define MDSS_MDP_HW_REV_109 0x10090000 //Next version
+#endif
+#ifndef MDSS_MDP_HW_REV_200
+#define MDSS_MDP_HW_REV_200 0x20000000 //8092
+#endif
+#ifndef MDSS_MDP_HW_REV_206
+#define MDSS_MDP_HW_REV_206 0x20060000 //Future
+#endif
+
+MDPVersion::MDPVersion()
+{
+ mMDPVersion = MDSS_V5;
+ mMdpRev = 0;
+ mRGBPipes = 0;
+ mVGPipes = 0;
+ mDMAPipes = 0;
+ mFeatures = 0;
+ mMDPUpscale = 1;
+ mMDPDownscale = 1;
+ mMacroTileEnabled = false;
+ mLowBw = 0;
+ mHighBw = 0;
+ mSourceSplit = false;
+ mSourceSplitAlways = false;
+ mRGBHasNoScalar = false;
+ mRotDownscale = false;
+
+ // this is the default limit of mixer unless driver reports it.
+ // For resolutions beyond this, we use dual/split overlay pipes.
+ mMaxMixerWidth = 2048;
+
+ updatePanelInfo();
+
+ if(!updateSysFsInfo()) {
+ ALOGE("Unable to read display sysfs node");
+ }
+ if (mMdpRev == MDP_V3_0_4){
+ mMDPVersion = MDP_V3_0_4;
+ }
+ else if (mMdpRev == MDP_V3_0_5){
+ mMDPVersion = MDP_V3_0_5;
+ }
+
+ mHasOverlay = false;
+ if((mMDPVersion >= MDP_V4_0) ||
+ (mMDPVersion == MDP_V_UNKNOWN) ||
+ (mMDPVersion == MDP_V3_0_4) ||
+ (mMDPVersion == MDP_V3_0_5))
+ mHasOverlay = true;
+ if(!updateSplitInfo()) {
+ ALOGE("Unable to read display split node");
+ }
+}
+
+MDPVersion::~MDPVersion() {
+ close(mFd);
+}
+
+int MDPVersion::tokenizeParams(char *inputParams, const char *delim,
+ char* tokenStr[], int *idx) {
+ char *tmp_token = NULL;
+ char *temp_ptr;
+ int index = 0;
+ if (!inputParams) {
+ return -1;
+ }
+ tmp_token = strtok_r(inputParams, delim, &temp_ptr);
+ while (tmp_token != NULL) {
+ tokenStr[index++] = tmp_token;
+ tmp_token = strtok_r(NULL, " ", &temp_ptr);
+ }
+ *idx = index;
+ return 0;
+}
+// This function reads the sysfs node to read the primary panel type
+// and updates information accordingly
+void MDPVersion::updatePanelInfo() {
+ FILE *displayDeviceFP = NULL;
+ FILE *panelInfoNodeFP = NULL;
+ char fbType[MAX_FRAME_BUFFER_NAME_SIZE];
+ const char *strCmdPanel = "mipi dsi cmd panel";
+ const char *strVideoPanel = "mipi dsi video panel";
+ const char *strLVDSPanel = "lvds panel";
+ const char *strEDPPanel = "edp panel";
+
+ displayDeviceFP = fopen("/sys/class/graphics/fb0/msm_fb_type", "r");
+ if(displayDeviceFP){
+ fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE,
+ displayDeviceFP);
+ if(strncmp(fbType, strCmdPanel, strlen(strCmdPanel)) == 0) {
+ mPanelInfo.mType = MIPI_CMD_PANEL;
+ }
+ else if(strncmp(fbType, strVideoPanel, strlen(strVideoPanel)) == 0) {
+ mPanelInfo.mType = MIPI_VIDEO_PANEL;
+ }
+ else if(strncmp(fbType, strLVDSPanel, strlen(strLVDSPanel)) == 0) {
+ mPanelInfo.mType = LVDS_PANEL;
+ }
+ else if(strncmp(fbType, strEDPPanel, strlen(strEDPPanel)) == 0) {
+ mPanelInfo.mType = EDP_PANEL;
+ }
+ fclose(displayDeviceFP);
+ } else {
+ ALOGE("Unable to read Primary Panel Information");
+ }
+
+ panelInfoNodeFP = fopen("/sys/class/graphics/fb0/msm_fb_panel_info", "r");
+ if(panelInfoNodeFP){
+ size_t len = PAGE_SIZE;
+ ssize_t read;
+ char *readLine = (char *) malloc (len);
+ char property[PROPERTY_VALUE_MAX];
+ while((read = getline((char **)&readLine, &len,
+ panelInfoNodeFP)) != -1) {
+ int token_ct=0;
+ char *tokens[10];
+ memset(tokens, 0, sizeof(tokens));
+
+ if(!tokenizeParams(readLine, TOKEN_PARAMS_DELIM, tokens,
+ &token_ct)) {
+ if(!strncmp(tokens[0], "pu_en", strlen("pu_en"))) {
+ mPanelInfo.mPartialUpdateEnable = atoi(tokens[1]);
+ ALOGI("PartialUpdate status: %s",
+ mPanelInfo.mPartialUpdateEnable? "Enabled" :
+ "Disabled");
+ }
+ if(!strncmp(tokens[0], "xstart", strlen("xstart"))) {
+ mPanelInfo.mLeftAlign = atoi(tokens[1]);
+ ALOGI("Left Align: %d", mPanelInfo.mLeftAlign);
+ }
+ if(!strncmp(tokens[0], "walign", strlen("walign"))) {
+ mPanelInfo.mWidthAlign = atoi(tokens[1]);
+ ALOGI("Width Align: %d", mPanelInfo.mWidthAlign);
+ }
+ if(!strncmp(tokens[0], "ystart", strlen("ystart"))) {
+ mPanelInfo.mTopAlign = atoi(tokens[1]);
+ ALOGI("Top Align: %d", mPanelInfo.mTopAlign);
+ }
+ if(!strncmp(tokens[0], "halign", strlen("halign"))) {
+ mPanelInfo.mHeightAlign = atoi(tokens[1]);
+ ALOGI("Height Align: %d", mPanelInfo.mHeightAlign);
+ }
+ if(!strncmp(tokens[0], "min_w", strlen("min_w"))) {
+ mPanelInfo.mMinROIWidth = atoi(tokens[1]);
+ ALOGI("Min ROI Width: %d", mPanelInfo.mMinROIWidth);
+ }
+ if(!strncmp(tokens[0], "min_h", strlen("min_h"))) {
+ mPanelInfo.mMinROIHeight = atoi(tokens[1]);
+ ALOGI("Min ROI Height: %d", mPanelInfo.mMinROIHeight);
+ }
+ if(!strncmp(tokens[0], "roi_merge", strlen("roi_merge"))) {
+ mPanelInfo.mNeedsROIMerge = atoi(tokens[1]);
+ ALOGI("Needs ROI Merge: %d", mPanelInfo.mNeedsROIMerge);
+ }
+ if(!strncmp(tokens[0], "dyn_fps_en", strlen("dyn_fps_en"))) {
+ mPanelInfo.mDynFpsSupported = atoi(tokens[1]);
+ ALOGI("Dynamic Fps: %s", mPanelInfo.mDynFpsSupported ?
+ "Enabled" : "Disabled");
+ }
+ if(!strncmp(tokens[0], "min_fps", strlen("min_fps"))) {
+ mPanelInfo.mMinFps = atoi(tokens[1]);
+ ALOGI("Min Panel fps: %d", mPanelInfo.mMinFps);
+ }
+ if(!strncmp(tokens[0], "max_fps", strlen("max_fps"))) {
+ mPanelInfo.mMaxFps = atoi(tokens[1]);
+ ALOGI("Max Panel fps: %d", mPanelInfo.mMaxFps);
+ }
+ }
+ }
+ if((property_get("persist.hwc.pubypass", property, 0) > 0) &&
+ (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+ (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+ mPanelInfo.mPartialUpdateEnable = 0;
+ ALOGI("PartialUpdate disabled by property");
+ }
+ fclose(panelInfoNodeFP);
+ } else {
+ ALOGE("Failed to open msm_fb_panel_info node");
+ }
+}
+
+// This function reads the sysfs node to read MDP capabilities
+// and parses and updates information accordingly.
+bool MDPVersion::updateSysFsInfo() {
+ FILE *sysfsFd;
+ size_t len = PAGE_SIZE;
+ ssize_t read;
+ char *line = NULL;
+ char sysfsPath[255];
+ memset(sysfsPath, 0, sizeof(sysfsPath));
+ snprintf(sysfsPath , sizeof(sysfsPath),
+ "/sys/class/graphics/fb0/mdp/caps");
+ char property[PROPERTY_VALUE_MAX];
+ bool enableMacroTile = false;
+
+ if((property_get("persist.hwc.macro_tile_enable", property, NULL) > 0) &&
+ (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+ (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+ enableMacroTile = true;
+ }
+
+ sysfsFd = fopen(sysfsPath, "rb");
+
+ if (sysfsFd == NULL) {
+ ALOGE("%s: sysFsFile file '%s' not found",
+ __FUNCTION__, sysfsPath);
+ return false;
+ } else {
+ line = (char *) malloc(len);
+ while((read = getline(&line, &len, sysfsFd)) != -1) {
+ int index=0;
+ char *tokens[10];
+ memset(tokens, 0, sizeof(tokens));
+
+ // parse the line and update information accordingly
+ if(!tokenizeParams(line, TOKEN_PARAMS_DELIM, tokens, &index)) {
+ if(!strncmp(tokens[0], "hw_rev", strlen("hw_rev"))) {
+ mMdpRev = atoi(tokens[1]);
+ }
+ else if(!strncmp(tokens[0], "rgb_pipes", strlen("rgb_pipes"))) {
+ mRGBPipes = (uint8_t)atoi(tokens[1]);
+ }
+ else if(!strncmp(tokens[0], "vig_pipes", strlen("vig_pipes"))) {
+ mVGPipes = (uint8_t)atoi(tokens[1]);
+ }
+ else if(!strncmp(tokens[0], "dma_pipes", strlen("dma_pipes"))) {
+ mDMAPipes = (uint8_t)atoi(tokens[1]);
+ }
+ else if(!strncmp(tokens[0], "max_downscale_ratio",
+ strlen("max_downscale_ratio"))) {
+ mMDPDownscale = atoi(tokens[1]);
+ }
+ else if(!strncmp(tokens[0], "max_upscale_ratio",
+ strlen("max_upscale_ratio"))) {
+ mMDPUpscale = atoi(tokens[1]);
+ } else if(!strncmp(tokens[0], "max_bandwidth_low",
+ strlen("max_bandwidth_low"))) {
+ mLowBw = atol(tokens[1]);
+ } else if(!strncmp(tokens[0], "max_bandwidth_high",
+ strlen("max_bandwidth_high"))) {
+ mHighBw = atol(tokens[1]);
+ } else if(!strncmp(tokens[0], "max_mixer_width",
+ strlen("max_mixer_width"))) {
+ mMaxMixerWidth = atoi(tokens[1]);
+ } else if(!strncmp(tokens[0], "features", strlen("features"))) {
+ for(int i=1; i<index;i++) {
+ if(!strncmp(tokens[i], "bwc", strlen("bwc"))) {
+ mFeatures |= MDP_BWC_EN;
+ } else if(!strncmp(tokens[i], "decimation",
+ strlen("decimation"))) {
+ mFeatures |= MDP_DECIMATION_EN;
+ } else if(!strncmp(tokens[i], "tile_format",
+ strlen("tile_format"))) {
+ if(enableMacroTile)
+ mMacroTileEnabled = true;
+ } else if(!strncmp(tokens[i], "src_split",
+ strlen("src_split"))) {
+ mSourceSplit = true;
+ } else if(!strncmp(tokens[i], "non_scalar_rgb",
+ strlen("non_scalar_rgb"))) {
+ mRGBHasNoScalar = true;
+ } else if(!strncmp(tokens[i], "rotator_downscale",
+ strlen("rotator_downscale"))) {
+ mRotDownscale = true;
+ }
+ }
+ }
+ }
+ }
+ free(line);
+ fclose(sysfsFd);
+ }
+
+ if(mMDPVersion >= qdutils::MDP_V4_2 and mMDPVersion < qdutils::MDSS_V5) {
+ mRotDownscale = true;
+ }
+
+ if(mSourceSplit) {
+ memset(sysfsPath, 0, sizeof(sysfsPath));
+ snprintf(sysfsPath , sizeof(sysfsPath),
+ "/sys/class/graphics/fb0/msm_fb_src_split_info");
+
+ sysfsFd = fopen(sysfsPath, "rb");
+ if (sysfsFd == NULL) {
+ ALOGE("%s: Opening file %s failed with error %s", __FUNCTION__,
+ sysfsPath, strerror(errno));
+ return false;
+ } else {
+ line = (char *) malloc(len);
+ if((read = getline(&line, &len, sysfsFd)) != -1) {
+ if(!strncmp(line, "src_split_always",
+ strlen("src_split_always"))) {
+ mSourceSplitAlways = true;
+ }
+ }
+ free(line);
+ fclose(sysfsFd);
+ }
+ }
+
+ ALOGD_IF(DEBUG, "%s: mMDPVersion: %d mMdpRev: %x mRGBPipes:%d,"
+ "mVGPipes:%d", __FUNCTION__, mMDPVersion, mMdpRev,
+ mRGBPipes, mVGPipes);
+ ALOGD_IF(DEBUG, "%s:mDMAPipes:%d \t mMDPDownscale:%d, mFeatures:%d",
+ __FUNCTION__, mDMAPipes, mMDPDownscale, mFeatures);
+ ALOGD_IF(DEBUG, "%s:mLowBw: %lu mHighBw: %lu", __FUNCTION__, mLowBw,
+ mHighBw);
+
+ return true;
+}
+
+// This function reads the sysfs node to read MDP capabilities
+// and parses and updates information accordingly.
+bool MDPVersion::updateSplitInfo() {
+ if(mMDPVersion >= MDSS_V5) {
+ char split[64] = {0};
+ FILE* fp = fopen("/sys/class/graphics/fb0/msm_fb_split", "r");
+ if(fp){
+ //Format "left right" space as delimiter
+ if(fread(split, sizeof(char), 64, fp)) {
+ split[sizeof(split) - 1] = '\0';
+ mSplit.mLeft = atoi(split);
+ ALOGI_IF(mSplit.mLeft, "Left Split=%d", mSplit.mLeft);
+ char *rght = strpbrk(split, " ");
+ if(rght)
+ mSplit.mRight = atoi(rght + 1);
+ ALOGI_IF(mSplit.mRight, "Right Split=%d", mSplit.mRight);
+ }
+ } else {
+ ALOGE("Failed to open mdss_fb_split node");
+ return false;
+ }
+ if(fp)
+ fclose(fp);
+ }
+ return true;
+}
+
+
+bool MDPVersion::hasMinCropWidthLimitation() const {
+ return mMdpRev <= MDSS_MDP_HW_REV_102;
+}
+
+bool MDPVersion::supportsDecimation() {
+ return mFeatures & MDP_DECIMATION_EN;
+}
+
+uint32_t MDPVersion::getMaxMDPDownscale() {
+ return mMDPDownscale;
+}
+
+uint32_t MDPVersion::getMaxMDPUpscale() {
+ return mMDPUpscale;
+}
+
+bool MDPVersion::supportsBWC() {
+ // BWC - Bandwidth Compression
+ return (mFeatures & MDP_BWC_EN);
+}
+
+bool MDPVersion::supportsMacroTile() {
+ // MACRO TILE support
+ return mMacroTileEnabled;
+}
+
+bool MDPVersion::isSrcSplit() const {
+ return mSourceSplit;
+}
+
+bool MDPVersion::isSrcSplitAlways() const {
+ return mSourceSplitAlways;
+}
+
+bool MDPVersion::isRGBScalarSupported() const {
+ return (!mRGBHasNoScalar);
+}
+
+bool MDPVersion::is8x26() {
+ return (mMdpRev >= MDSS_MDP_HW_REV_101 and
+ mMdpRev < MDSS_MDP_HW_REV_102);
+}
+
+bool MDPVersion::is8x74v2() {
+ return (mMdpRev >= MDSS_MDP_HW_REV_102 and
+ mMdpRev < MDSS_MDP_HW_REV_103);
+}
+
+bool MDPVersion::is8084() {
+ return (mMdpRev >= MDSS_MDP_HW_REV_103 and
+ mMdpRev < MDSS_MDP_HW_REV_104);
+}
+
+bool MDPVersion::is8092() {
+ return (mMdpRev >= MDSS_MDP_HW_REV_200 and
+ mMdpRev < MDSS_MDP_HW_REV_206);
+}
+
+bool MDPVersion::is8994() {
+ return (mMdpRev >= MDSS_MDP_HW_REV_105 and
+ mMdpRev < MDSS_MDP_HW_REV_106);
+}
+
+bool MDPVersion::is8x16() {
+ return (mMdpRev >= MDSS_MDP_HW_REV_106 and
+ mMdpRev < MDSS_MDP_HW_REV_107);
+}
+
+bool MDPVersion::is8x39() {
+ return (mMdpRev >= MDSS_MDP_HW_REV_108 and
+ mMdpRev < MDSS_MDP_HW_REV_109);
+}
+
+
+}; //namespace qdutils
+
diff --git a/msm8909/libqdutils/mdp_version.h b/msm8909/libqdutils/mdp_version.h
new file mode 100644
index 0000000..3c7f6a3
--- /dev/null
+++ b/msm8909/libqdutils/mdp_version.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2012-2013, The Linux Foundation. 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 The Linux Foundation 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_LIBQCOMUTILS_MDPVER
+#define INCLUDE_LIBQCOMUTILS_MDPVER
+
+#include <stdint.h>
+#include <utils/Singleton.h>
+#include <cutils/properties.h>
+
+/* This class gets the MSM type from the soc info
+*/
+using namespace android;
+namespace qdutils {
+// These panel definitions are available at mdss_mdp.h which is internal header
+// file and is not available at <linux/mdss_mdp.h>.
+// ToDo: once it is available at linux/mdss_mdp.h, these below definitions can
+// be removed.
+enum mdp_version {
+ MDP_V_UNKNOWN = 0,
+ MDP_V2_2 = 220,
+ MDP_V3_0 = 300,
+ MDP_V3_0_3 = 303,
+ MDP_V3_0_4 = 304,
+ MDP_V3_0_5 = 305,
+ MDP_V3_1 = 310,
+ MDP_V4_0 = 400,
+ MDP_V4_1 = 410,
+ MDP_V4_2 = 420,
+ MDP_V4_3 = 430,
+ MDP_V4_4 = 440,
+ MDSS_V5 = 500,
+};
+
+#define NO_PANEL '0'
+#define MDDI_PANEL '1'
+#define EBI2_PANEL '2'
+#define LCDC_PANEL '3'
+#define EXT_MDDI_PANEL '4'
+#define TV_PANEL '5'
+#define DTV_PANEL '7'
+#define MIPI_VIDEO_PANEL '8'
+#define MIPI_CMD_PANEL '9'
+#define WRITEBACK_PANEL 'a'
+#define LVDS_PANEL 'b'
+#define EDP_PANEL 'c'
+
+class MDPVersion;
+
+struct Split {
+ int mLeft;
+ int mRight;
+ Split() : mLeft(0), mRight(0){}
+ int left() { return mLeft; }
+ int right() { return mRight; }
+ friend class MDPVersion;
+};
+
+struct PanelInfo {
+ char mType; // Smart or Dumb
+ int mPartialUpdateEnable; // Partial update feature
+ int mLeftAlign; // ROI left alignment restriction
+ int mWidthAlign; // ROI width alignment restriction
+ int mTopAlign; // ROI top alignment restriction
+ int mHeightAlign; // ROI height alignment restriction
+ int mMinROIWidth; // Min width needed for ROI
+ int mMinROIHeight; // Min height needed for ROI
+ bool mNeedsROIMerge; // Merge ROI's of both the DSI's
+ bool mDynFpsSupported; // Panel Supports dyn fps
+ uint32_t mMinFps; // Min fps supported by panel
+ uint32_t mMaxFps; // Max fps supported by panel
+ PanelInfo() : mType(NO_PANEL), mPartialUpdateEnable(0),
+ mLeftAlign(0), mWidthAlign(0), mTopAlign(0), mHeightAlign(0),
+ mMinROIWidth(0), mMinROIHeight(0), mNeedsROIMerge(false),
+ mDynFpsSupported(0), mMinFps(0), mMaxFps(0) {}
+ friend class MDPVersion;
+};
+
+class MDPVersion : public Singleton <MDPVersion>
+{
+public:
+ MDPVersion();
+ ~MDPVersion();
+ int getMDPVersion() {return mMDPVersion;}
+ char getPanelType() {return mPanelInfo.mType;}
+ bool hasOverlay() {return mHasOverlay;}
+ uint8_t getTotalPipes() {
+ return (uint8_t)(mRGBPipes + mVGPipes + mDMAPipes);
+ }
+ uint8_t getRGBPipes() { return mRGBPipes; }
+ uint8_t getVGPipes() { return mVGPipes; }
+ uint8_t getDMAPipes() { return mDMAPipes; }
+ bool supportsDecimation();
+ uint32_t getMaxMDPDownscale();
+ uint32_t getMaxMDPUpscale();
+ bool supportsBWC();
+ bool supportsMacroTile();
+ int getLeftSplit() { return mSplit.left(); }
+ int getRightSplit() { return mSplit.right(); }
+ bool isPartialUpdateEnabled() { return mPanelInfo.mPartialUpdateEnable; }
+ int getLeftAlign() { return mPanelInfo.mLeftAlign; }
+ int getWidthAlign() { return mPanelInfo.mWidthAlign; }
+ int getTopAlign() { return mPanelInfo.mTopAlign; }
+ int getHeightAlign() { return mPanelInfo.mHeightAlign; }
+ int getMinROIWidth() { return mPanelInfo.mMinROIWidth; }
+ int getMinROIHeight() { return mPanelInfo.mMinROIHeight; }
+ bool needsROIMerge() { return mPanelInfo.mNeedsROIMerge; }
+ unsigned long getLowBw() { return mLowBw; }
+ unsigned long getHighBw() { return mHighBw; }
+ bool isRotDownscaleEnabled() { return mRotDownscale; }
+ bool isDynFpsSupported() { return mPanelInfo.mDynFpsSupported; }
+ uint32_t getMinFpsSupported() { return mPanelInfo.mMinFps; }
+ uint32_t getMaxFpsSupported() { return mPanelInfo.mMaxFps; }
+ uint32_t getMaxMixerWidth() const { return mMaxMixerWidth; }
+ bool hasMinCropWidthLimitation() const;
+ bool isSrcSplit() const;
+ bool isSrcSplitAlways() const;
+ bool isRGBScalarSupported() const;
+ bool is8x26();
+ bool is8x74v2();
+ bool is8084();
+ bool is8092();
+ bool is8994();
+ bool is8x16();
+ bool is8x39();
+
+private:
+ bool updateSysFsInfo();
+ void updatePanelInfo();
+ bool updateSplitInfo();
+ int tokenizeParams(char *inputParams, const char *delim,
+ char* tokenStr[], int *idx);
+ int mFd;
+ int mMDPVersion;
+ bool mHasOverlay;
+ uint32_t mMdpRev;
+ uint8_t mRGBPipes;
+ uint8_t mVGPipes;
+ uint8_t mDMAPipes;
+ uint32_t mFeatures;
+ uint32_t mMDPDownscale;
+ uint32_t mMDPUpscale;
+ bool mMacroTileEnabled;
+ Split mSplit;
+ PanelInfo mPanelInfo;
+ unsigned long mLowBw; //kbps
+ unsigned long mHighBw; //kbps
+ bool mSourceSplit;
+ //Additional property on top of source split
+ bool mSourceSplitAlways;
+ bool mRGBHasNoScalar;
+ bool mRotDownscale;
+ uint32_t mMaxMixerWidth; //maximum x-res of a given mdss mixer.
+};
+}; //namespace qdutils
+#endif //INCLUDE_LIBQCOMUTILS_MDPVER
diff --git a/msm8909/libqdutils/profiler.cpp b/msm8909/libqdutils/profiler.cpp
new file mode 100644
index 0000000..810b019
--- /dev/null
+++ b/msm8909/libqdutils/profiler.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2011-2012, The Linux Foundation. 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 The Linux Foundation 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_NDDEBUG 0
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
+
+#include "profiler.h"
+
+#ifdef DEBUG_CALC_FPS
+
+
+ANDROID_SINGLETON_STATIC_INSTANCE(qdutils::CalcFps) ;
+
+namespace qdutils {
+
+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 =
+ (unsigned int)(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;
+
+ debug_fps_metadata.curr_frame = 0;
+
+ ALOGD("period: %u", debug_fps_metadata.period);
+ ALOGD("ignorethresh_us: %" PRId64, 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("%" PRId64" %" PRId64" %" PRId64" %" PRId64" %" PRId64" %" PRId64,
+ 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 =
+ (unsigned int)(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(float(float(debug_fps_metadata.period * 1000000) /
+ (float)sum));
+ }
+ }
+ else if (debug_fps_metadata_t::DFM_TIME == debug_fps_metadata.type) {
+ debug_fps_metadata.time_elapsed += (float)((float)diff/1000.0);
+ if (debug_fps_metadata.time_elapsed >= debug_fps_metadata.time_period) {
+ float fps = float(1000.0 * debug_fps_metadata.curr_frame/
+ debug_fps_metadata.time_elapsed);
+ print_fps(fps);
+ }
+ }
+ return;
+}
+};//namespace qomutils
+#endif
diff --git a/msm8909/libqdutils/profiler.h b/msm8909/libqdutils/profiler.h
new file mode 100644
index 0000000..5f270b0
--- /dev/null
+++ b/msm8909/libqdutils/profiler.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2011-2012, The Linux Foundation. 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 The Linux Foundation 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 <stdio.h>
+#include <utils/Singleton.h>
+#include <cutils/properties.h>
+#include <cutils/log.h>
+
+#ifndef DEBUG_CALC_FPS
+#define CALC_FPS() ((void)0)
+#define CALC_INIT() ((void)0)
+#else
+#define CALC_FPS() qdutils::CalcFps::getInstance().Fps()
+#define CALC_INIT() qdutils::CalcFps::getInstance().Init()
+using namespace android;
+namespace qdutils {
+class CalcFps : public Singleton<CalcFps> {
+ 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;
+};
+};//namespace qdutils
+#endif
+
+#endif // INCLUDE_PROFILER
diff --git a/msm8909/libqdutils/qdMetaData.cpp b/msm8909/libqdutils/qdMetaData.cpp
new file mode 100644
index 0000000..88109c9
--- /dev/null
+++ b/msm8909/libqdutils/qdMetaData.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2012-2014, The Linux Foundation. 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 The Linux Foundation 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 <errno.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <cutils/log.h>
+#include <gralloc_priv.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
+#include "qdMetaData.h"
+
+int setMetaData(private_handle_t *handle, DispParamType paramType,
+ void *param) {
+ if (!handle) {
+ ALOGE("%s: Private handle is null!", __func__);
+ return -1;
+ }
+ if (handle->fd_metadata == -1) {
+ ALOGE("%s: Bad fd for extra data!", __func__);
+ return -1;
+ }
+ if (!param) {
+ ALOGE("%s: input param is null!", __func__);
+ return -1;
+ }
+ unsigned long size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));
+ void *base = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED,
+ handle->fd_metadata, 0);
+ if (base == reinterpret_cast<void*>(MAP_FAILED)) {
+ ALOGE("%s: mmap() failed: error is %s!", __func__, strerror(errno));
+ return -1;
+ }
+ MetaData_t *data = reinterpret_cast <MetaData_t *>(base);
+ data->operation |= paramType;
+ switch (paramType) {
+ case PP_PARAM_HSIC:
+ memcpy((void *)&data->hsicData, param, sizeof(HSICData_t));
+ break;
+ case PP_PARAM_SHARPNESS:
+ data->sharpness = *((int32_t *)param);
+ break;
+ case PP_PARAM_VID_INTFC:
+ data->video_interface = *((int32_t *)param);
+ break;
+ case PP_PARAM_INTERLACED:
+ data->interlaced = *((int32_t *)param);
+ break;
+ case PP_PARAM_IGC:
+ memcpy((void *)&data->igcData, param, sizeof(IGCData_t));
+ break;
+ case PP_PARAM_SHARP2:
+ memcpy((void *)&data->Sharp2Data, param, sizeof(Sharp2Data_t));
+ break;
+ case PP_PARAM_TIMESTAMP:
+ data->timestamp = *((int64_t *)param);
+ break;
+ case UPDATE_BUFFER_GEOMETRY:
+ memcpy((void *)&data->bufferDim, param, sizeof(BufferDim_t));
+ break;
+ case UPDATE_REFRESH_RATE:
+ data->refreshrate = *((uint32_t *)param);
+ break;
+ case UPDATE_COLOR_SPACE:
+ data->colorSpace = *((ColorSpace_t *)param);
+ break;
+ case MAP_SECURE_BUFFER:
+ data->mapSecureBuffer = *((int32_t *)param);
+ break;
+ default:
+ ALOGE("Unknown paramType %d", paramType);
+ break;
+ }
+ if(munmap(base, size))
+ ALOGE("%s: failed to unmap ptr %p, err %d", __func__, (void*)base,
+ errno);
+ return 0;
+}
diff --git a/msm8909/libqdutils/qdMetaData.h b/msm8909/libqdutils/qdMetaData.h
new file mode 100644
index 0000000..32d788e
--- /dev/null
+++ b/msm8909/libqdutils/qdMetaData.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2012-2014, The Linux Foundation. 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 The Linux Foundation 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 _QDMETADATA_H
+#define _QDMETADATA_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_IGC_LUT_ENTRIES 256
+
+enum ColorSpace_t{
+ ITU_R_601,
+ ITU_R_601_FR,
+ ITU_R_709,
+};
+
+struct HSICData_t {
+ int32_t hue;
+ float saturation;
+ int32_t intensity;
+ float contrast;
+};
+
+struct Sharp2Data_t {
+ int32_t strength;
+ uint32_t edge_thr;
+ uint32_t smooth_thr;
+ uint32_t noise_thr;
+};
+
+struct IGCData_t{
+ uint16_t c0[MAX_IGC_LUT_ENTRIES];
+ uint16_t c1[MAX_IGC_LUT_ENTRIES];
+ uint16_t c2[MAX_IGC_LUT_ENTRIES];
+};
+
+struct BufferDim_t {
+ int32_t sliceWidth;
+ int32_t sliceHeight;
+};
+
+struct MetaData_t {
+ int32_t operation;
+ int32_t interlaced;
+ struct BufferDim_t bufferDim;
+ struct HSICData_t hsicData;
+ int32_t sharpness;
+ int32_t video_interface;
+ struct IGCData_t igcData;
+ struct Sharp2Data_t Sharp2Data;
+ int64_t timestamp;
+ uint32_t refreshrate;
+ enum ColorSpace_t colorSpace;
+ /* Gralloc sets PRIV_SECURE_BUFFER flag to inform that the buffers are from
+ * ION_SECURE. which should not be mapped. However, for GPU post proc
+ * feature, GFX needs to map this buffer, in the client context and in SF
+ * context, it should not. Hence to differentiate, add this metadata field
+ * for clients to set, and GPU will to read and know when to map the
+ * SECURE_BUFFER(ION) */
+ int32_t mapSecureBuffer;
+};
+
+enum DispParamType {
+ PP_PARAM_HSIC = 0x0001,
+ PP_PARAM_SHARPNESS = 0x0002,
+ PP_PARAM_INTERLACED = 0x0004,
+ PP_PARAM_VID_INTFC = 0x0008,
+ PP_PARAM_IGC = 0x0010,
+ PP_PARAM_SHARP2 = 0x0020,
+ PP_PARAM_TIMESTAMP = 0x0040,
+ UPDATE_BUFFER_GEOMETRY = 0x0080,
+ UPDATE_REFRESH_RATE = 0x0100,
+ UPDATE_COLOR_SPACE = 0x0200,
+ MAP_SECURE_BUFFER = 0x400,
+};
+
+struct private_handle_t;
+int setMetaData(struct private_handle_t *handle, enum DispParamType paramType,
+ void *param);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _QDMETADATA_H */
+
diff --git a/msm8909/libqdutils/qd_utils.cpp b/msm8909/libqdutils/qd_utils.cpp
new file mode 100644
index 0000000..5726202
--- /dev/null
+++ b/msm8909/libqdutils/qd_utils.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. 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 The Linux Foundation 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 "qd_utils.h"
+#define QD_UTILS_DEBUG 0
+
+namespace qdutils {
+
+int getHDMINode(void)
+{
+ FILE *displayDeviceFP = NULL;
+ char fbType[MAX_FRAME_BUFFER_NAME_SIZE];
+ char msmFbTypePath[MAX_FRAME_BUFFER_NAME_SIZE];
+ int j = 0;
+
+ for(j = 0; j < HWC_NUM_DISPLAY_TYPES; j++) {
+ snprintf (msmFbTypePath, sizeof(msmFbTypePath),
+ "/sys/class/graphics/fb%d/msm_fb_type", j);
+ displayDeviceFP = fopen(msmFbTypePath, "r");
+ if(displayDeviceFP) {
+ fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE,
+ displayDeviceFP);
+ if(strncmp(fbType, "dtv panel", strlen("dtv panel")) == 0) {
+ ALOGD("%s: HDMI is at fb%d", __func__, j);
+ fclose(displayDeviceFP);
+ break;
+ }
+ fclose(displayDeviceFP);
+ } else {
+ ALOGE("%s: Failed to open fb node %d", __func__, j);
+ }
+ }
+
+ if (j < HWC_NUM_DISPLAY_TYPES)
+ return j;
+ else
+ ALOGE("%s: Failed to find HDMI node", __func__);
+
+ return -1;
+}
+
+int getEdidRawData(char *buffer)
+{
+ int size;
+ int edidFile;
+ char msmFbTypePath[MAX_FRAME_BUFFER_NAME_SIZE];
+ int node_id = getHDMINode();
+
+ if (node_id < 0) {
+ ALOGE("%s no HDMI node found", __func__);
+ return 0;
+ }
+
+ snprintf(msmFbTypePath, sizeof(msmFbTypePath),
+ "/sys/class/graphics/fb%d/edid_raw_data", node_id);
+
+ edidFile = open(msmFbTypePath, O_RDONLY, 0);
+
+ if (edidFile < 0) {
+ ALOGE("%s no edid raw data found", __func__);
+ return 0;
+ }
+
+ size = (int)read(edidFile, (char*)buffer, EDID_RAW_DATA_SIZE);
+ close(edidFile);
+ return size;
+}
+
+/* Calculates the aspect ratio for based on src & dest */
+void getAspectRatioPosition(int destWidth, int destHeight, int srcWidth,
+ int srcHeight, hwc_rect_t& rect) {
+ int x =0, y =0;
+
+ if (srcWidth * destHeight > destWidth * srcHeight) {
+ srcHeight = destWidth * srcHeight / srcWidth;
+ srcWidth = destWidth;
+ } else if (srcWidth * destHeight < destWidth * srcHeight) {
+ srcWidth = destHeight * srcWidth / srcHeight;
+ srcHeight = destHeight;
+ } else {
+ srcWidth = destWidth;
+ srcHeight = destHeight;
+ }
+ if (srcWidth > destWidth) srcWidth = destWidth;
+ if (srcHeight > destHeight) srcHeight = destHeight;
+ x = (destWidth - srcWidth) / 2;
+ y = (destHeight - srcHeight) / 2;
+ ALOGD_IF(QD_UTILS_DEBUG, "%s: AS Position: x = %d, y = %d w = %d h = %d",
+ __FUNCTION__, x, y, srcWidth , srcHeight);
+ // Convert it back to hwc_rect_t
+ rect.left = x;
+ rect.top = y;
+ rect.right = srcWidth + rect.left;
+ rect.bottom = srcHeight + rect.top;
+}
+
+}; //namespace qdutils
diff --git a/msm8909/libqdutils/qd_utils.h b/msm8909/libqdutils/qd_utils.h
new file mode 100644
index 0000000..1d4bc19
--- /dev/null
+++ b/msm8909/libqdutils/qd_utils.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2013, The Linux Foundation. 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 The Linux Foundation or 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 _QD_UTIL_MISC_H
+#define _QD_UTIL_MISC_H
+
+#include <utils/threads.h>
+#include <linux/fb.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <linux/fb.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/resource.h>
+#include <cutils/properties.h>
+#include <hardware/hwcomposer.h>
+
+namespace qdutils {
+#define EDID_RAW_DATA_SIZE 640
+
+enum qd_utils {
+ MAX_FRAME_BUFFER_NAME_SIZE = 128,
+ MAX_SYSFS_FILE_PATH = 255,
+ SUPPORTED_DOWNSCALE_AREA = (1920*1080)
+};
+
+int getHDMINode(void);
+int getEdidRawData(char *buffer);
+
+void getAspectRatioPosition(int destWidth, int destHeight, int srcWidth,
+ int srcHeight, hwc_rect_t& rect);
+}; //namespace qdutils
+#endif
diff --git a/msm8909/libqservice/Android.mk b/msm8909/libqservice/Android.mk
new file mode 100644
index 0000000..78b1d77
--- /dev/null
+++ b/msm8909/libqservice/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH := $(call my-dir)
+include $(LOCAL_PATH)/../common.mk
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libqservice
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
+LOCAL_SHARED_LIBRARIES := $(common_libs) libbinder
+LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdqservice\"
+LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
+LOCAL_SRC_FILES := QService.cpp \
+ IQService.cpp \
+ IQClient.cpp
+LOCAL_COPY_HEADERS_TO := $(common_header_export_path)
+LOCAL_COPY_HEADERS := IQService.h \
+ IQClient.h
+
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/msm8909/libqservice/IQClient.cpp b/msm8909/libqservice/IQClient.cpp
new file mode 100644
index 0000000..a6251c8
--- /dev/null
+++ b/msm8909/libqservice/IQClient.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are
+ * retained for attribution purposes only.
+
+ * 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 <sys/types.h>
+#include <binder/Parcel.h>
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+#include <utils/Errors.h>
+#include <IQClient.h>
+
+using namespace android;
+
+// ---------------------------------------------------------------------------
+// XXX: Since qservice currently runs as part of hwc instead of a standalone
+// process, the implementation below is overridden and the notifyCallback in
+// hwc_qclient is directly called.
+
+namespace qClient {
+
+enum {
+ NOTIFY_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BpQClient : public BpInterface<IQClient>
+{
+public:
+ BpQClient(const sp<IBinder>& impl)
+ : BpInterface<IQClient>(impl) {}
+
+ virtual status_t notifyCallback(uint32_t command,
+ const Parcel* inParcel,
+ Parcel* outParcel) {
+ Parcel data;
+ Parcel *reply = outParcel;
+ data.writeInterfaceToken(IQClient::getInterfaceDescriptor());
+ data.writeInt32(command);
+ if (inParcel->dataAvail())
+ data.appendFrom(inParcel, inParcel->dataPosition(),
+ inParcel->dataAvail());
+ status_t result = remote()->transact(NOTIFY_CALLBACK, data, reply);
+ return result;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(QClient, "android.display.IQClient");
+
+// ----------------------------------------------------------------------
+//Stub implementation - nothing needed here
+status_t BnQClient::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case NOTIFY_CALLBACK: {
+ CHECK_INTERFACE(IQClient, data, reply);
+ uint32_t command = data.readInt32();
+ notifyCallback(command, &data, reply);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+
+}
+
+}; // namespace qClient
diff --git a/msm8909/libqservice/IQClient.h b/msm8909/libqservice/IQClient.h
new file mode 100644
index 0000000..7d816d2
--- /dev/null
+++ b/msm8909/libqservice/IQClient.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are
+ * retained for attribution purposes only.
+
+ * 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_IQCLIENT_H
+#define ANDROID_IQCLIENT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <binder/IInterface.h>
+
+namespace qClient {
+// ----------------------------------------------------------------------------
+class IQClient : public android::IInterface
+{
+public:
+ DECLARE_META_INTERFACE(QClient);
+ virtual android::status_t notifyCallback(uint32_t command,
+ const android::Parcel* inParcel,
+ android::Parcel* outParcel) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnQClient : public android::BnInterface<IQClient>
+{
+public:
+ virtual android::status_t onTransact( uint32_t code,
+ const android::Parcel& data,
+ android::Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace qClient
+
+#endif // ANDROID_IQCLIENT_H
diff --git a/msm8909/libqservice/IQService.cpp b/msm8909/libqservice/IQService.cpp
new file mode 100644
index 0000000..9e2b0f5
--- /dev/null
+++ b/msm8909/libqservice/IQService.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are
+ * retained for attribution purposes only.
+
+ * 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 <fcntl.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <binder/Parcel.h>
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
+#include <utils/Errors.h>
+#include <private/android_filesystem_config.h>
+#include <IQService.h>
+
+#define QSERVICE_DEBUG 0
+
+using namespace android;
+using namespace qClient;
+
+// ---------------------------------------------------------------------------
+
+namespace qService {
+
+class BpQService : public BpInterface<IQService>
+{
+public:
+ BpQService(const sp<IBinder>& impl)
+ : BpInterface<IQService>(impl) {}
+
+ virtual void connect(const sp<IQClient>& client) {
+ ALOGD_IF(QSERVICE_DEBUG, "%s: connect client", __FUNCTION__);
+ Parcel data, reply;
+ data.writeInterfaceToken(IQService::getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(client));
+ remote()->transact(CONNECT, data, &reply);
+ }
+
+ virtual android::status_t dispatch(uint32_t command, const Parcel* inParcel,
+ Parcel* outParcel) {
+ ALOGD_IF(QSERVICE_DEBUG, "%s: dispatch in:%p", __FUNCTION__, inParcel);
+ status_t err = (status_t) android::FAILED_TRANSACTION;
+ Parcel data;
+ Parcel *reply = outParcel;
+ data.writeInterfaceToken(IQService::getInterfaceDescriptor());
+ if (inParcel && inParcel->dataSize() > 0)
+ data.appendFrom(inParcel, 0, inParcel->dataSize());
+ err = remote()->transact(command, data, reply);
+ return err;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(QService, "android.display.IQService");
+
+// ----------------------------------------------------------------------
+
+static void getProcName(int pid, char *buf, int size);
+
+status_t BnQService::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ ALOGD_IF(QSERVICE_DEBUG, "%s: code: %d", __FUNCTION__, code);
+ // IPC should be from certain processes only
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int callerPid = ipc->getCallingPid();
+ const int callerUid = ipc->getCallingUid();
+ const int MAX_BUF_SIZE = 1024;
+ char callingProcName[MAX_BUF_SIZE] = {0};
+
+ getProcName(callerPid, callingProcName, MAX_BUF_SIZE);
+
+ const bool permission = (callerUid == AID_MEDIA ||
+ callerUid == AID_GRAPHICS ||
+ callerUid == AID_ROOT ||
+ callerUid == AID_SYSTEM);
+
+ if (code == CONNECT) {
+ CHECK_INTERFACE(IQService, data, reply);
+ if(callerUid != AID_GRAPHICS) {
+ ALOGE("display.qservice CONNECT access denied: \
+ pid=%d uid=%d process=%s",
+ callerPid, callerUid, callingProcName);
+ return PERMISSION_DENIED;
+ }
+ sp<IQClient> client =
+ interface_cast<IQClient>(data.readStrongBinder());
+ connect(client);
+ return NO_ERROR;
+ } else if (code > COMMAND_LIST_START && code < COMMAND_LIST_END) {
+ if(!permission) {
+ ALOGE("display.qservice access denied: command=%d\
+ pid=%d uid=%d process=%s", code, callerPid,
+ callerUid, callingProcName);
+ return PERMISSION_DENIED;
+ }
+ CHECK_INTERFACE(IQService, data, reply);
+ dispatch(code, &data, reply);
+ return NO_ERROR;
+ } else {
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+//Helper
+static void getProcName(int pid, char *buf, int size) {
+ int fd = -1;
+ snprintf(buf, size, "/proc/%d/cmdline", pid);
+ fd = open(buf, O_RDONLY);
+ if (fd < 0) {
+ strlcpy(buf, "Unknown", size);
+ } else {
+ ssize_t len = read(fd, buf, size - 1);
+ if (len >= 0)
+ buf[len] = 0;
+
+ close(fd);
+ }
+}
+
+}; // namespace qService
diff --git a/msm8909/libqservice/IQService.h b/msm8909/libqservice/IQService.h
new file mode 100644
index 0000000..0f0dc4c
--- /dev/null
+++ b/msm8909/libqservice/IQService.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2015, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are
+ * retained for attribution purposes only.
+
+ * 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_IQSERVICE_H
+#define ANDROID_IQSERVICE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <binder/IInterface.h>
+#include <binder/IBinder.h>
+#include <IQClient.h>
+
+
+namespace qService {
+// ----------------------------------------------------------------------------
+
+class IQService : public android::IInterface
+{
+public:
+ DECLARE_META_INTERFACE(QService);
+ enum {
+ COMMAND_LIST_START = android::IBinder::FIRST_CALL_TRANSACTION,
+ SECURING, // Hardware securing start/end notification
+ UNSECURING, // Hardware unsecuring start/end notification
+ CONNECT, // Connect to qservice
+ SCREEN_REFRESH, // Refresh screen through SF invalidate
+ EXTERNAL_ORIENTATION, // Set external orientation
+ BUFFER_MIRRORMODE, // Buffer mirrormode
+ CHECK_EXTERNAL_STATUS, // Check status of external display
+ GET_DISPLAY_ATTRIBUTES, // Get display attributes
+ SET_HSIC_DATA, // Set HSIC on dspp
+ GET_DISPLAY_VISIBLE_REGION, // Get the visibleRegion for dpy
+ SET_SECONDARY_DISPLAY_STATUS, // Sets secondary display status
+ SET_PARTIAL_UPDATE, // Preference on partial update feature
+ SET_VIEW_FRAME, // Set view frame of display
+ DYNAMIC_DEBUG, // Enable more logging on the fly
+ SET_IDLE_TIMEOUT, // Set idle timeout for GPU fallback
+ /* Enable/Disable/Set refresh rate dynamically */
+ CONFIGURE_DYN_REFRESH_RATE,
+ QDCM_SVC_CMDS, // request QDCM services.
+ TOGGLE_SCREEN_UPDATE, // Provides ability to disable screen updates
+ COMMAND_LIST_END = 400,
+ };
+
+ enum {
+ END = 0,
+ START,
+ };
+
+ enum {
+ DEBUG_ALL,
+ DEBUG_MDPCOMP,
+ DEBUG_VSYNC,
+ DEBUG_VD,
+ DEBUG_PIPE_LIFECYCLE,
+ };
+
+ enum {
+ PREF_POST_PROCESSING,
+ PREF_PARTIAL_UPDATE,
+ ENABLE_PARTIAL_UPDATE,
+ };
+
+ // Register a client that can be notified
+ virtual void connect(const android::sp<qClient::IQClient>& client) = 0;
+ // Generic function to dispatch binder commands
+ // The type of command decides how the data is parceled
+ virtual android::status_t dispatch(uint32_t command,
+ const android::Parcel* inParcel,
+ android::Parcel* outParcel) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnQService : public android::BnInterface<IQService>
+{
+public:
+ virtual android::status_t onTransact( uint32_t code,
+ const android::Parcel& data,
+ android::Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace qService
+
+#endif // ANDROID_IQSERVICE_H
diff --git a/msm8909/libqservice/QService.cpp b/msm8909/libqservice/QService.cpp
new file mode 100644
index 0000000..12dd995
--- /dev/null
+++ b/msm8909/libqservice/QService.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2012-2014, The Linux Foundation. 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 The Linux Foundation 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 <QService.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+
+#define QSERVICE_DEBUG 0
+
+using namespace android;
+
+namespace qService {
+
+QService* QService::sQService = NULL;
+// ----------------------------------------------------------------------------
+QService::QService()
+{
+ ALOGD_IF(QSERVICE_DEBUG, "QService Constructor invoked");
+}
+
+QService::~QService()
+{
+ ALOGD_IF(QSERVICE_DEBUG,"QService Destructor invoked");
+}
+
+void QService::connect(const sp<qClient::IQClient>& client) {
+ ALOGD_IF(QSERVICE_DEBUG,"client connected");
+ mClient = client;
+}
+
+status_t QService::dispatch(uint32_t command, const Parcel* inParcel,
+ Parcel* outParcel) {
+ status_t err = (status_t) FAILED_TRANSACTION;
+ IPCThreadState* ipc = IPCThreadState::self();
+ //Rewind parcel in case we're calling from the same process
+ if (ipc->getCallingPid() == getpid())
+ inParcel->setDataPosition(0);
+ if (mClient.get()) {
+ ALOGD_IF(QSERVICE_DEBUG, "Dispatching command: %d", command);
+ err = mClient->notifyCallback(command, inParcel, outParcel);
+ }
+ return err;
+}
+
+void QService::init()
+{
+ if(!sQService) {
+ sQService = new QService();
+ sp<IServiceManager> sm = defaultServiceManager();
+ sm->addService(String16("display.qservice"), sQService);
+ if(sm->checkService(String16("display.qservice")) != NULL)
+ ALOGD_IF(QSERVICE_DEBUG, "adding display.qservice succeeded");
+ else
+ ALOGD_IF(QSERVICE_DEBUG, "adding display.qservice failed");
+ }
+}
+
+}
diff --git a/msm8909/libqservice/QService.h b/msm8909/libqservice/QService.h
new file mode 100644
index 0000000..a8e4cdb
--- /dev/null
+++ b/msm8909/libqservice/QService.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2012-2013, The Linux Foundation. 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 The Linux Foundation 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 ANDROID_QSERVICE_H
+#define ANDROID_QSERVICE_H
+
+#include <utils/Errors.h>
+#include <sys/types.h>
+#include <cutils/log.h>
+#include <binder/IServiceManager.h>
+#include <IQService.h>
+#include <IQClient.h>
+
+struct hwc_context_t;
+
+namespace qService {
+// ----------------------------------------------------------------------------
+
+class QService : public BnQService {
+public:
+ virtual ~QService();
+ virtual void connect(const android::sp<qClient::IQClient>& client);
+ virtual android::status_t dispatch(uint32_t command,
+ const android::Parcel* data,
+ android::Parcel* reply);
+ static void init();
+private:
+ QService();
+ android::sp<qClient::IQClient> mClient;
+ static QService *sQService;
+};
+}; // namespace qService
+#endif // ANDROID_QSERVICE_H
diff --git a/msm8909/libqservice/QServiceUtils.h b/msm8909/libqservice/QServiceUtils.h
new file mode 100644
index 0000000..ff09aa9
--- /dev/null
+++ b/msm8909/libqservice/QServiceUtils.h
@@ -0,0 +1,94 @@
+/*
+* Copyright (c) 2013-15 The Linux Foundation. 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 The Linux Foundation. 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 QSERVICEUTILS_H
+#define QSERVICEUTILS_H
+#include <binder/Parcel.h>
+#include <binder/IServiceManager.h>
+#include <utils/RefBase.h>
+#include <IQService.h>
+
+// ----------------------------------------------------------------------------
+// Helpers
+// ----------------------------------------------------------------------------
+inline android::sp<qService::IQService> getBinder() {
+ android::sp<android::IServiceManager> sm = android::defaultServiceManager();
+ android::sp<qService::IQService> binder =
+ android::interface_cast<qService::IQService>
+ (sm->getService(android::String16("display.qservice")));
+ if (binder == NULL) {
+ ALOGE("%s: invalid binder object", __FUNCTION__);
+ }
+ return binder;
+}
+
+inline android::status_t sendSingleParam(uint32_t command, uint32_t value) {
+ android::status_t err = (android::status_t) android::FAILED_TRANSACTION;
+ android::sp<qService::IQService> binder = getBinder();
+ android::Parcel inParcel, outParcel;
+ inParcel.writeInt32(value);
+ if(binder != NULL) {
+ err = binder->dispatch(command, &inParcel , &outParcel);
+ }
+ return err;
+}
+
+// ----------------------------------------------------------------------------
+// Convenience wrappers that clients can call
+// ----------------------------------------------------------------------------
+inline android::status_t securing(uint32_t startEnd) {
+ return sendSingleParam(qService::IQService::SECURING, startEnd);
+}
+
+inline android::status_t unsecuring(uint32_t startEnd) {
+ return sendSingleParam(qService::IQService::UNSECURING, startEnd);
+}
+
+inline android::status_t screenRefresh() {
+ return sendSingleParam(qService::IQService::SCREEN_REFRESH, 1);
+}
+
+inline android::status_t setPartialUpdate(uint32_t enable) {
+ return sendSingleParam(qService::IQService::SET_PARTIAL_UPDATE, enable);
+}
+
+inline android::status_t toggleScreenUpdate(uint32_t on) {
+ return sendSingleParam(qService::IQService::TOGGLE_SCREEN_UPDATE, on);
+}
+
+inline android::status_t setExtOrientation(uint32_t orientation) {
+ return sendSingleParam(qService::IQService::EXTERNAL_ORIENTATION,
+ orientation);
+}
+
+inline android::status_t setBufferMirrorMode(uint32_t enable) {
+ return sendSingleParam(qService::IQService::BUFFER_MIRRORMODE, enable);
+}
+
+#endif /* end of include guard: QSERVICEUTILS_H */