qcom/display: Update HALs

- Update the display HAL from Code Aurora Forum
- Add updated overlay library
- Enable HWC with basic video going through overlay
- Cleanup some files

Change-Id: Ia53650759d4fe99bde395b7b4e8e02e6e65845e0
This commit is contained in:
Naseer Ahmed 2012-06-14 00:56:20 -07:00 committed by Gohulan Balachandran
parent 2d968bf0cc
commit 7341799797
77 changed files with 15249 additions and 7521 deletions

View File

@ -1,11 +1,9 @@
#Enables the listed display HAL modules
#Libs to be built for all targets (including SDK)
display-hals := libqcomui
#libs to be built for QCOM targets only
#ifeq ($(call is-vendor-board-platform,QCOM),true)
display-hals += libgralloc libgenlock libcopybit
display-hals += libgralloc libgenlock libcopybit libhwcomposer liboverlay
#endif
include $(call all-named-subdir-makefiles,$(display-hals))

59
libcopybit/Android.mk Normal file
View File

@ -0,0 +1,59 @@
# Copyright (C) 2008 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
LOCAL_PATH:= $(call my-dir)
# HAL module implemenation, not prelinked and stored in
# hw/<COPYPIX_HARDWARE_MODULE_ID>.<ro.board.platform>.so
ifeq ($(TARGET_USES_C2D_COMPOSITION),true)
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog libdl libcutils libmemalloc libutils
LOCAL_SRC_FILES := copybit_c2d.cpp software_converter.cpp
LOCAL_MODULE := copybit.$(TARGET_BOARD_PLATFORM)
LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc
LOCAL_CFLAGS += -DCOPYBIT_Z180=1 -DC2D_SUPPORT_DISPLAY=1
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
else
ifneq ($(call is-chipset-in-board-platform,msm7630),true)
ifeq ($(call is-board-platform-in-list,$(MSM7K_BOARD_PLATFORMS)),true)
include $(CLEAR_VARS)
ifeq ($(ARCH_ARM_HAVE_NEON),true)
LOCAL_CFLAGS += -D__ARM_HAVE_NEON
endif
ifeq ($(call is-board-platform,msm7627a),true)
LOCAL_CFLAGS += -DTARGET_7x27A
endif
ifeq ($(TARGET_GRALLOC_USES_ASHMEM),true)
LOCAL_CFLAGS += -DUSE_ASHMEM
ifeq ($(call is-chipset-prefix-in-board-platform,msm7627),true)
LOCAL_CFLAGS += -DTARGET_7x27
endif
endif
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog libmemalloc
LOCAL_SRC_FILES := software_converter.cpp copybit.cpp
LOCAL_MODULE := copybit.$(TARGET_BOARD_PLATFORM)
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/qcom/display/libgralloc
LOCAL_CFLAGS += -DCOPYBIT_MSM7K=1
include $(BUILD_SHARED_LIBRARY)
endif
endif
endif

View File

189
libcopybit/NOTICE Normal file
View File

@ -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

618
libcopybit/c2d2.h Normal file
View File

@ -0,0 +1,618 @@
/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __c2d2_h_
#define __c2d2_h_
#ifdef __cplusplus
extern "C" {
#endif
#ifndef C2D_API
#define C2D_API /* define API export as needed */
#endif
#if !defined(int32) && !defined(_INT32_DEFINED)
typedef int int32;
#define _INT32_DEFINED
#endif
#if !defined(uint32) && !defined(_UINT32_DEFINED)
typedef unsigned int uint32;
#define _UINT32_DEFINED
#endif
/*****************************************************************************/
/*********************** Blit definitions *****************************/
/*****************************************************************************/
/* Status codes, returned by any blit function */
typedef enum {
C2D_STATUS_OK = 0,
C2D_STATUS_NOT_SUPPORTED = 1,
C2D_STATUS_OUT_OF_MEMORY = 2,
C2D_STATUS_INVALID_PARAM = 3,
C2D_STATUS_SURFACE_IN_USE = 4,
} C2D_STATUS;
/* Definitions of color format modes, used together with color formats */
typedef enum {
C2D_FORMAT_PACK_INTO_32BIT = (1 << 8), /* pack into dword if set */
C2D_FORMAT_SWAP_ENDIANNESS = (1 << 9), /* swaps the order */
C2D_FORMAT_LINEAR_SPACE = (1 << 10), /* linear color space */
C2D_FORMAT_PREMULTIPLIED = (1 << 11), /* alpha premultiplied */
C2D_FORMAT_INVERT_ALPHA = (1 << 12), /* inverts alpha */
C2D_FORMAT_DISABLE_ALPHA = (1 << 13), /* disables alpha */
C2D_FORMAT_INTERLACED = (1 << 14), /* YUV line-interlaced */
C2D_FORMAT_TRANSPARENT = (1 << 15), /* YUV 1-bit alpha in Y */
C2D_FORMAT_MACROTILED = (1 << 16), /* tiled in macro level */
C2D_FORMAT_TILED_4x4 = (1 << 17), /* 4x4 tiled format */
C2D_FORMAT_SWAP_RB = (1 << 18), /* Swap R & B color components */
} C2D_FORMAT_MODE;
/* Definitions of supported RGB formats, used in C2D_RGB_SURFACE_DEF.
* The bits of each color channel are packed into a machine word
* representing a single pixel from left to right (MSB to LSB) in the
* order indicated by format name. For the sub-byte formats the pixels
* are packed into bytes from left to right (MSbit to LSBit).
* If the C2D_FORMAT_PACK_INTO_32BIT bit is set, the minimal
* machine word used for pixel storage is 32-bit and the whole word
* is reversed if endianness is swapped.
* If the C2D_FORMAT_SWAP_ENDIANNESS bit is set, the order within a
* minimal machine word representing a pixel
* is reversed for both sub-byte and multi-byte formats.
* If the C2D_FORMAT_LINEAR_SPACE bit is set, the color space of
* the formats below is considered linear, if applicable.
* If the C2D_FORMAT_PREMULTIPLIED bit is set, the color channels
* are premultiplied with the alpha, if applicable.
* If the C2D_FORMAT_INVERT_ALPHA bit is set, the alpha interpretation
* is inverted: 0 - opaque, 1 - transparent, if applicable.
* If the C2D_FORMAT_DISABLE_ALPHA bit is set, the alpha channel serves
* as a placeholder and is ignored during blit, if applicable.
* If the C2D_FORMAT_MACROTILED bit is set, the surface is in the
* tiled format : 64x32 for 8bpp, 32x32 for 16bpp formats */
typedef enum {
C2D_COLOR_FORMAT_1 = 0, /* 1-bit alpha/color expansion */
C2D_COLOR_FORMAT_2_PALETTE = 1, /* 2-bit indices for palette */
C2D_COLOR_FORMAT_4_PALETTE = 2, /* 4-bit indices for palette */
C2D_COLOR_FORMAT_8_PALETTE = 3, /* 8-bit indices for palette */
C2D_COLOR_FORMAT_2_L = 4, /* 2-bit grayscale */
C2D_COLOR_FORMAT_4_L = 5, /* 4-bit grayscale */
C2D_COLOR_FORMAT_8_L = 6, /* 8-bit grayscale */
C2D_COLOR_FORMAT_2_A = 7, /* 2-bit alpha only */
C2D_COLOR_FORMAT_4_A = 8, /* 4-bit alpha only */
C2D_COLOR_FORMAT_8_A = 9, /* 8-bit alpha only */
C2D_COLOR_FORMAT_444_RGB = 10, /* 12-bit colors */
C2D_COLOR_FORMAT_565_RGB = 11, /* 16-bit colors */
C2D_COLOR_FORMAT_888_RGB = 12, /* 24-bit colors */
C2D_COLOR_FORMAT_1555_ARGB = 13, /* 16-bit colors (1-bit alpha) */
C2D_COLOR_FORMAT_4444_ARGB = 14, /* 16-bit colors (4-bit alpha) */
C2D_COLOR_FORMAT_8565_ARGB = 15, /* 24-bit colors (8-bit alpha) */
C2D_COLOR_FORMAT_8888_ARGB = 16, /* 32-bit colors (8-bit alpha) */
C2D_COLOR_FORMAT_5551_RGBA = 17, /* 16-bit colors (1-bit alpha) */
C2D_COLOR_FORMAT_4444_RGBA = 18, /* 16-bit colors (4-bit alpha) */
C2D_COLOR_FORMAT_5658_RGBA = 19, /* 24-bit colors (8-bit alpha) */
C2D_COLOR_FORMAT_8888_RGBA = 20, /* 32-bit colors (8-bit alpha) */
/* derived RGB color formats (base format + mode bits) */
} C2D_RGB_FORMAT;
/* Definitions of supported YUV formats, used in C2D_YUV_SURFACE_DEF.
* Each of Y,U,V channels usually takes 1 byte and therefore is
* individually addressable. The definitions below show how Y,U,V
* channels are packed into macropixels for each particular format.
* The order is from left (smaller byte addresses) to right (larger
* byte addresses). The first three digits (4xx) denote the chroma
* subsampling in standard YUV notation. The digits in the macropixel
* denote that the whole block (from the previous digit or from the
* beginning) has to be repeated the number of times. Underscores
* between Y,U,V channels are used to describe separate planes for
* planar YUV formats. Formats are mapped to numbers so that future
* versions with various YUV permutations are easy to add.
* If the C2D_FORMAT_INTERLACED bit is set, the line order is
* interlaced: 0,2,4,...1,3,5... if applicable.
* If the C2D_FORMAT_TRANSPARENT bit is set, the least significant
* bit of Y channel serves as alpha: 0 - transparent, 1 - opaque. */
typedef enum {
C2D_COLOR_FORMAT_411_YYUYYV = 110, /* packed, 12-bit */
C2D_COLOR_FORMAT_411_YUYYVY = 111, /* packed, 12-bit */
C2D_COLOR_FORMAT_411_UYYVYY = 112, /* packed, 12-bit, "Y411" */
C2D_COLOR_FORMAT_411_YUYV2Y4 = 116, /* packed, 12-bit */
C2D_COLOR_FORMAT_411_UYVY2Y4 = 117, /* packed, 12-bit, "Y41P" */
C2D_COLOR_FORMAT_422_YUYV = 120, /* packed, 16-bit, "YUY2" */
C2D_COLOR_FORMAT_422_UYVY = 121, /* packed, 16-bit, "UYVY" */
C2D_COLOR_FORMAT_422_YVYU = 122, /* packed, 16-bit, "YVYU" */
C2D_COLOR_FORMAT_422_VYUY = 123, /* packed, 16-bit */
C2D_COLOR_FORMAT_444_YUV = 130, /* packed, 24-bit */
C2D_COLOR_FORMAT_444_UYV = 131, /* packed, 24-bit, "IYU2" */
C2D_COLOR_FORMAT_444_AYUV = 136, /* packed, 24-bit, "AYUV" */
C2D_COLOR_FORMAT_410_Y_UV = 150, /* planar, Y + interleaved UV */
C2D_COLOR_FORMAT_411_Y_UV = 151, /* planar, Y + interleaved UV */
C2D_COLOR_FORMAT_420_Y_UV = 152, /* planar, Y + interleaved UV */
C2D_COLOR_FORMAT_422_Y_UV = 153, /* planar, Y + interleaved UV */
C2D_COLOR_FORMAT_444_Y_UV = 154, /* planar, Y + interleaved UV */
C2D_COLOR_FORMAT_410_Y_VU = 160, /* planar, Y + interleaved VU */
C2D_COLOR_FORMAT_411_Y_VU = 161, /* planar, Y + interleaved VU */
C2D_COLOR_FORMAT_420_Y_VU = 162, /* planar, Y + interleaved VU */
C2D_COLOR_FORMAT_422_Y_VU = 163, /* planar, Y + interleaved VU */
C2D_COLOR_FORMAT_444_Y_VU = 164, /* planar, Y + interleaved VU */
C2D_COLOR_FORMAT_410_Y_U_V = 170, /* planar, Y + U + V separate */
C2D_COLOR_FORMAT_411_Y_U_V = 171, /* planar, Y + U + V separate */
C2D_COLOR_FORMAT_420_Y_V_U = 172, /* planar, Y + V + U separate */
C2D_COLOR_FORMAT_420_Y_U_V = 173, /* planar, Y + U + V separate */
C2D_COLOR_FORMAT_422_Y_U_V = 174, /* planar, Y + U + V separate */
C2D_COLOR_FORMAT_444_Y_U_V = 175, /* planar, Y + U + V separate */
C2D_COLOR_FORMAT_800_Y = 190, /* planar, Y only, grayscale */
/* derived YUV color formats (base format + mode bits), FOURCC */
C2D_COLOR_FORMAT_411_Y411 = 112,
C2D_COLOR_FORMAT_411_Y41P = 117,
C2D_COLOR_FORMAT_411_IY41 = 117 | (1 << 14),
C2D_COLOR_FORMAT_411_Y41T = 117 | (1 << 15),
C2D_COLOR_FORMAT_422_YUY2 = 120,
C2D_COLOR_FORMAT_422_IUYV = 121 | (1 << 14),
C2D_COLOR_FORMAT_422_Y42T = 121 | (1 << 15),
C2D_COLOR_FORMAT_444_IYU2 = 131,
C2D_COLOR_FORMAT_420_NV12 = 152,
C2D_COLOR_FORMAT_420_NV21 = 162,
C2D_COLOR_FORMAT_410_YUV9 = 170,
C2D_COLOR_FORMAT_410_YVU9 = 170,
C2D_COLOR_FORMAT_411_Y41B = 171,
C2D_COLOR_FORMAT_420_YV12 = 172,
C2D_COLOR_FORMAT_420_IYUV = 173,
C2D_COLOR_FORMAT_420_I420 = 173,
C2D_COLOR_FORMAT_422_YV16 = 174,
C2D_COLOR_FORMAT_422_Y42B = 174,
C2D_COLOR_FORMAT_800_Y800 = 190,
} C2D_YUV_FORMAT;
/* Configuration bits, used in the config_mask field of C2D_OBJECT struct */
typedef enum {
C2D_SOURCE_RECT_BIT = (1 << 0), /* enables source_rect field */
C2D_MIRROR_H_BIT = (1 << 1), /* enables horizontal flipping */
C2D_MIRROR_V_BIT = (1 << 2), /* enables vertical flipping */
C2D_SOURCE_TILE_BIT = (1 << 3), /* enables source surface tiling */
C2D_TARGET_RECT_BIT = (1 << 4), /* enables target_rect field */
C2D_ROTATE_BIT = (1 << 5), /* enables all rotation fields */
C2D_SCISSOR_RECT_BIT = (1 << 6), /* enables scissor_rect field */
C2D_MASK_SURFACE_BIT = (1 << 7), /* enables mask_surface_id field */
C2D_MASK_ALIGN_BIT = (1 << 8), /* aligns mask to source_rect */
C2D_MASK_SCALE_BIT = (1 << 9), /* enables mask surface scaling */
C2D_MASK_TILE_BIT = (1 << 10), /* enables mask surface tiling */
C2D_GLOBAL_ALPHA_BIT = (1 << 11), /* enables global_alpha field */
C2D_COLOR_KEY_BIT = (1 << 12), /* enables color_key field */
C2D_NO_PIXEL_ALPHA_BIT = (1 << 13), /* disables source alpha channel */
C2D_NO_BILINEAR_BIT = (1 << 14), /* disables bilinear on scaling */
C2D_NO_ANTIALIASING_BIT = (1 << 15), /* disables antialiasing on edges */
C2D_DRAW_LINE_BIT = (1 << 16), /* enables line drawing with source rectangle */
C2D_DRAW_LINE_NOLAST = (1 << 17), /* disable last pixel draw for line */
} C2D_SOURCE_CONFIG;
/* Target configuration bits, defines rotation + mirroring.
* Mirror is applied prior to rotation if enabled. */
typedef enum {
C2D_TARGET_MIRROR_H = (1 << 0), /* horizontal flip */
C2D_TARGET_MIRROR_V = (1 << 1), /* vertical flip */
C2D_TARGET_ROTATE_0 = (0 << 2), /* no rotation */
C2D_TARGET_ROTATE_90 = (1 << 2), /* 90 degree rotation */
C2D_TARGET_ROTATE_180 = (2 << 2), /* 180 degree rotation */
C2D_TARGET_ROTATE_270 = (3 << 2), /* 270 degree rotation, 90 + 180 */
C2D_TARGET_MASK_ALIGN = (1 << 4), /* aligns mask to target scissor */
C2D_TARGET_MASK_SCALE = (1 << 5), /* enables mask scaling */
C2D_TARGET_MASK_TILE = (1 << 6), /* enables mask tiling */
C2D_TARGET_COLOR_KEY = (1 << 7), /* enables target_color_key */
C2D_TARGET_NO_PIXEL_ALPHA = (1 << 8), /* disables target alpha channel */
} C2D_TARGET_CONFIG;
#define C2D_TARGET_ROTATION_MASK (C2D_TARGET_ROTATE_90*3)
/* Additional blend modes, can be used with both source and target configs.
If none of the below is set, the default "SRC over DST" is applied. */
typedef enum {
C2D_ALPHA_BLEND_SRC_OVER = (0 << 20), /* Default, Porter-Duff "SRC over DST" */
C2D_ALPHA_BLEND_SRC = (1 << 20), /* Porter-Duff "SRC" */
C2D_ALPHA_BLEND_SRC_IN = (2 << 20), /* Porter-Duff "SRC in DST" */
C2D_ALPHA_BLEND_DST_IN = (3 << 20), /* Porter-Duff "DST in SRC" */
C2D_ALPHA_BLEND_SRC_OUT = (4 << 20), /* Porter-Duff "SRC out DST" */
C2D_ALPHA_BLEND_DST_OUT = (5 << 20), /* Porter-Duff "DST out SRC" */
C2D_ALPHA_BLEND_DST_OVER = (6 << 20), /* Porter-Duff "DST over SRC" */
C2D_ALPHA_BLEND_SRC_ATOP = (7 << 20), /* Porter-Duff "SRC ATOP" */
C2D_ALPHA_BLEND_DST_ATOP = (8 << 20), /* Porter-Duff "DST ATOP" */
C2D_ALPHA_BLEND_XOR = (9 << 20), /* Xor */
C2D_ALPHA_BLEND_MULTIPLY = (10 << 20), /* OpenVG "MULTIPLY" */
C2D_ALPHA_BLEND_SCREEN = (11 << 20), /* OpenVG "SCREEN" */
C2D_ALPHA_BLEND_DARKEN = (12 << 20), /* OpenVG "DARKEN" */
C2D_ALPHA_BLEND_LIGHTEN = (13 << 20), /* OpenVG "LIGHTEN" */
C2D_ALPHA_BLEND_ADDITIVE = (14 << 20), /* OpenVG "ADDITIVE" */
C2D_ALPHA_BLEND_DIRECT = (15 << 20), /* Direct alpha blitting */
C2D_ALPHA_BLEND_INVERTC = (16 << 20), /* Invert color */
C2D_ALPHA_BLEND_NONE = (1 << 25), /* disables alpha blending */
} C2D_ALPHA_BLEND_MODE;
/* Surface caps enumeration */
typedef enum {
C2D_SOURCE = (1 << 0), /* allows to use as a source */
C2D_TARGET = (1 << 1), /* allows to use as a target */
C2D_MASK = (1 << 2), /* allows to use as a mask */
C2D_PALETTE = (1 << 3), /* allows to use as a palette */
} C2D_SURFACE_BITS;
/* Surface type enumeration */
typedef enum {
C2D_SURFACE_RGB_HOST = 1, /* Host memory RGB surface */
C2D_SURFACE_RGB_EXT = 2, /* External memory RGB surface */
C2D_SURFACE_YUV_HOST = 3, /* Host memory YUV surface */
C2D_SURFACE_YUV_EXT = 4, /* External memory YUV surface */
C2D_SURFACE_WITH_PHYS = (1<<3), /* physical address already mapped */
/* this bit is valid with HOST types */
C2D_SURFACE_WITH_PHYS_DUMMY = (1<<4), /* physical address already mapped */
/* this bit is valid with HOST types */
} C2D_SURFACE_TYPE;
/* Structure for registering a RGB buffer as a blit surface */
typedef struct {
uint32 format; /* RGB color format plus additional mode bits */
uint32 width; /* defines width in pixels */
uint32 height; /* defines height in pixels */
void *buffer; /* pointer to the RGB buffer */
void *phys; /* physical address */
int32 stride; /* defines stride in bytes, negative stride is allowed */
} C2D_RGB_SURFACE_DEF;
/* Structure for registering a YUV plane(s) as a blit surface */
typedef struct {
uint32 format; /* YUV color format plus additional mode bits */
uint32 width; /* defines width in pixels */
uint32 height; /* defines height in pixels */
void *plane0; /* holds the whole buffer if YUV format is not planar */
void *phys0; /* physical address */
int32 stride0; /* stride in bytes if YUV format is not planar */
void *plane1; /* holds UV or VU plane for planar interleaved */
void *phys1; /* physical address */
int32 stride1; /* stride for UV or VU plane for planar interleaved */
void *plane2; /* holds the 3. plane, ignored if YUV format is not planar */
void *phys2; /* physical address */
int32 stride2; /* stride for the 3. plane, ignored if YUV format is not planar */
} C2D_YUV_SURFACE_DEF;
/* Rectangle definition */
typedef struct {
int32 x; /* upper-left x */
int32 y; /* upper-left y */
int32 width; /* width */
int32 height; /* height */
} C2D_RECT;
/* C2D_OBJECT encapsulates the blit parameters for a source surface.
* The fg_color defines color in target format for bits equal to 1
* in the source C2D_COLOR_FORMAT_1 format. It also defines rendering
* color for all alpha-only source formats. If the surface_id is 0
* the fg_color defines a constant fill color used instead of the surface.
* The bg_color defines color in target format for bits equal to 0
* in the source C2D_COLOR_FORMAT_1 format, otherwise both are ignored.
* The palette_id is used for all palette source formats, otherwise ignored.
* The source_rect first defines the content of the source surface,
* it is then horizontally/vertically flipped if C2D_MIRROR_*_BIT is set,
* then scaled with bilinear interpolation to exactly fit target_rect
* or repeated across target_rect if C2D_SOURCE_TILE_BIT is set,
* target_rect is then rotated clockwise by an arbitrary angle in degrees
* around the rot_orig_x/y, defined relative to target_rect's top left point,
* and then clipped to scissor_rect defined in target coordinate system.
* Finally alpha blending is applied before pixels get written into the target.
* Surface's pixel alpha is combined with mask alpha and with global alpha.
* Mask surface follows all transformations applied to the source surface.
* Source color key defines transparent color, applied together with alpha. */
typedef struct C2D_OBJECT_STR {
uint32 surface_id; /* source surface */
uint32 fg_color; /* foreground color */
uint32 bg_color; /* background color */
uint32 palette_id; /* one-dimensional horizontal palette surface */
uint32 config_mask; /* defines which fields below are enabled */
C2D_RECT source_rect; /* region of the source surface, 16.16 fp */
C2D_RECT target_rect; /* position and scaling in target, 16.16 fp */
int32 rot_orig_x; /* rotation origin relative to target_rect's... */
int32 rot_orig_y; /* ...top left point, both are 16.16 fp */
int32 rotation; /* clock-wise rotation in degrees, 16.16 fp */
C2D_RECT scissor_rect; /* defines the clip rectangle in target surface */
uint32 mask_surface_id; /* source alpha-mask surface */
uint32 global_alpha; /* 0 = fully transparent, 255 = fully opaque */
uint32 color_key; /* transparent color for the source surface */
struct C2D_OBJECT_STR *next; /* pointer to the next object or NULL */
} C2D_OBJECT;
/*****************************************************************************/
/**************************** C2D API 2.0 ********************************/
/*****************************************************************************/
/******************************************************************************
* Functions to create/destroy surfaces */
/* Creates a generic blit surface according to its type.
* Pass a combination of desired surface bits according to planned usage.
* Accepted values for surface_bits may include bits from C2D_SURFACE_BITS,
* and also from C2D_DISPLAY for compatibility with HW display controller.
* For host memory types the memory is preallocated outside the API
* and should remain valid until surface is destroyed.
* For external memory types the memory is allocated within API.
* On success, the non-zero surface identifier is returned.
* All numbers greater that 0 are valid surface identifiers, 0 is invalid.
* Host memory RGB surface:
* surface_type = C2D_SURFACE_RGB_HOST
* surface_definition = C2D_RGB_SURFACE_DEF
* all fields in definition structure should be set
* External memory RGB surface:
* surface_type = C2D_SURFACE_RGB_EXT
* surface_definition = C2D_RGB_SURFACE_DEF
* buffer field in definition structure is ignored
* Host memory YUV surface:
* surface_type = C2D_SURFACE_YUV_HOST
* surface_definition = C2D_YUV_SURFACE_DEF
* one or all plane and stride fields in definition structure
* should be set depending on whether the format is planar or not
* External memory YUV surface:
* surface_type = C2D_SURFACE_YUV_EXT
* surface_definition = C2D_YUV_SURFACE_DEF
* all plane and stride fields in definition structure are ignored */
C2D_API C2D_STATUS c2dCreateSurface( uint32 *surface_id,
uint32 surface_bits,
C2D_SURFACE_TYPE surface_type,
void *surface_definition );
/* Requests properties of the specified surface. */
C2D_API C2D_STATUS c2dQuerySurface( uint32 surface_id,
uint32 *surface_bits,
C2D_SURFACE_TYPE *surface_type,
uint32 *width, uint32 *height,
uint32 *format );
/* Destroys a generic blit surface.
* For external memory surfaces also deallocates the memory.
* It is safe to free any external resources associated with a given
* surface on c2dCreateSurface call after this function returns. */
C2D_API C2D_STATUS c2dDestroySurface( uint32 surface_id );
/******************************************************************************
* Functions to modify/exchange surface data */
/* The format of fill_color is the same as color format being used
* for specified surface. If fill_rect is NULL the whole surface is filled.
* Alpha-blending is not performed while filling.
* The operation is complete when function returns. */
C2D_API C2D_STATUS c2dFillSurface( uint32 surface_id,
uint32 fill_color,
C2D_RECT *fill_rect );
/* Writes data located in host memory into the specified surface.
* The chunk of host memory is identified with surface_type and
* surface_definition, no surface registration needed in this case.
* Only C2D_SURFACE_RGB_HOST, C2D_SURFACE_YUV_HOST are accepted.
* If only part of the host memory buffer should be loaded, it should
* be configured in surface_definition using width, height and stride.
* The x and y are defined in target surface coordinate space.
* Color conversion has to be done, if color formats differ.
* Alpha-blending is not performed while writing.
* The operation is complete when function returns. */
C2D_API C2D_STATUS c2dWriteSurface( uint32 surface_id,
C2D_SURFACE_TYPE surface_type,
void *surface_definition,
int32 x, int32 y );
/* Reads data from the specified surface into the host memory.
* The chunk of host memory is identified with surface_type and
* surface_definition, no surface registration needed in this case.
* Only C2D_SURFACE_RGB_HOST, C2D_SURFACE_YUV_HOST are accepted.
* If only part of the surface should be read, it should
* be configured in surface_definition using width, height and stride.
* The x and y are defined in source surface coordinate space.
* Color conversion has to be done, if color formats differ.
* Alpha-blending is not performed while reading.
* The operation is complete when function returns. */
C2D_API C2D_STATUS c2dReadSurface( uint32 surface_id,
C2D_SURFACE_TYPE surface_type,
void *surface_definition,
int32 x, int32 y );
/* Notifies c2d imlementation that surface has been updated from outside the API,
* if updated_rect is NULL then the whole surface has been updated. */
C2D_API C2D_STATUS c2dSurfaceUpdated( uint32 surface_id,
C2D_RECT *updated_rect );
/* Updates surface information.
* Could be called only for host surfaces set with parameter "C2D_SURFACE_WITH_PHYS".
* Count for surface planes have to be same than for already allocated surface */
C2D_API C2D_STATUS c2dUpdateSurface( uint32 surface_id,
uint32 surface_bits,
C2D_SURFACE_TYPE surface_type,
void *surface_definition );
/******************************************************************************
* Functions to do actual blit */
/* Draw a list of blit objects into the given target.
* The target_config is a bitwise OR of values from C2D_TARGET_CONFIG.
* The target transformation creates the effect that target surface
* is transformed before the blit and then transformed back
* after blit, however no physical target transform is performed.
* The objects_list is a linked list of blit objects, no more
* than num_objects is drawn from the given list.
* If num_objects is 0, the whole list is drawn.
* The blit is not guaranteed to complete after function returns. */
C2D_API C2D_STATUS c2dDraw( uint32 target_id,
uint32 target_config, C2D_RECT *target_scissor,
uint32 target_mask_id, uint32 target_color_key,
C2D_OBJECT *objects_list, uint32 num_objects );
/* timstamp set in the blit commands flush */
typedef void* c2d_ts_handle;
/* Forces any pending blit to complete for a given target.
* Non-blocking. All input surfaces for this target except those
* which are shared with other targets are expected to be immediately
* writable after client has been waiting returned timestamp with
* c2dWaitTimestamp funtion or c2dFinish has been called for same target */
C2D_API C2D_STATUS c2dFlush( uint32 target_id, c2d_ts_handle *timestamp);
/* Waits the pending timestamp */
C2D_API C2D_STATUS c2dWaitTimestamp( c2d_ts_handle timestamp );
/* Forces any pending blit to complete for a given target.
* Blocking version, returns when blit is done.
* All input surfaces for this target except those which are shared with
* other targets are expected to be immediately
* writable after this function returns. */
C2D_API C2D_STATUS c2dFinish( uint32 target_id );
/*****************************************************************************/
/****************************** Display API **********************************/
/*****************************************************************************/
/* Display input enumeration */
typedef enum {
C2D_DISPLAY_INPUT_0 = 0, /*!< default input */
C2D_DISPLAY_INPUT_1 = (1<<16), /*!< Overlay 1 */
C2D_DISPLAY_INPUT_2 = (1<<17), /*!< Overlay 2... */
} C2D_DISPLAY_INPUT;
/******************************************************************************
* Functions for display output. */
/* Functionality described in this section is optional and is
* provided only for the cases when blit HW
* is tightly bound to the display controller. */
/* Display enumeration, may also be used in surface caps */
typedef enum {
C2D_DISPLAY_MAIN = (1 << 10), /* main display */
C2D_DISPLAY_SECONDARY = (1 << 11), /* secondary display */
C2D_DISPLAY_TV_OUT = (1 << 12), /* tv-out */
} C2D_DISPLAY;
/* Display window enumeration */
typedef enum {
C2D_DISPLAY_OVERLAY = C2D_DISPLAY_INPUT_1, /*!< Overlay window bit. This defines display input.
When defined the surface is set on the overlay window
otherwise the surface is set on the background window. */
} C2D_DISPLAY_WINDOW; /*!< Window bit set with display parameter */
/* Display update modes */
typedef enum {
C2D_DISPLAY_MODE_TEAR_SYNC = (1 << 0), /* enables tearing sync */
C2D_DISPLAY_MODE_SURF_REMOVE = (1 << 1), /* Remove surface from given display + input */
} C2D_DISPLAY_MODE;
/* Sets the given surface as a current display front buffer.
* Several displays can be specified as an output if supported.
* Still only one input can be specified at a time fro display/displays.
* The surface remains shown until it gets replaced with another one. */
C2D_API C2D_STATUS c2dDisplaySetSurface( uint32 display,
uint32 surface_id, uint32 mode );
/* Returns the current surface for a particular display.
* Only one display can be specified at a time.
* The latest surface set with compDisplaySetSurface or
* the default pre-allocated surface is returned. */
C2D_API C2D_STATUS c2dDisplayGetSurface( uint32 display,
uint32 *surface_id );
/* Returns the properties for a particular display.
* Only one display can be specified at a time. */
C2D_API C2D_STATUS c2dDisplayGetProperties( uint32 display,
uint32 *width, uint32 *height,
uint32 *format );
/* Sets the properties for a particular display input.
* Only one display + input can be specified at a time.
* C2D_OBJECT used to set input rect(target rect),
* blending operations, rotation...etc for display source */
C2D_API C2D_STATUS c2dDisplaySetObject( uint32 display,
uint32 target_config, uint32 target_color_key,
C2D_OBJECT * c2dObject, uint32 mode);
/* allows user to map a memory region to the gpu. only supported on linux
* mem_fd is the fd of the memory region, hostptr is the host pointer to the region,
* len and offset are the size and offset of the memory.
* flags is one of the memory types supported by gsl
* gpaddr is passed by refernce back to the user
*/
C2D_API C2D_STATUS c2dMapAddr ( int mem_fd, void * hostptr, uint32 len, uint32 offset, uint32 flags, void ** gpuaddr);
/* allows user to unmap memory region mapped by c2dMapAddr.
* gpaddr is the gpuaddr to unmap */
C2D_API C2D_STATUS c2dUnMapAddr (void * gpuaddr);
/*****************************************************************************/
#ifdef __cplusplus
}
#endif
#endif /* __c2d2_h_ */

553
libcopybit/copybit.cpp Normal file
View File

@ -0,0 +1,553 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (c) 2010 - 2011, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "copybit"
#include <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"
#define DEBUG_MDP_ERRORS 1
/******************************************************************************/
#if defined(COPYBIT_MSM7K)
#define MAX_SCALE_FACTOR (4)
#define MAX_DIMENSION (4096)
#elif defined(COPYBIT_QSD8K)
#define MAX_SCALE_FACTOR (8)
#define MAX_DIMENSION (2048)
#else
#error "Unsupported MDP version"
#endif
/******************************************************************************/
/** State information for each device instance */
struct copybit_context_t {
struct copybit_device_t device;
int mFD;
uint8_t mAlpha;
int mFlags;
};
/**
* Common hardware methods
*/
static int open_copybit(const struct hw_module_t* module, const char* name,
struct hw_device_t** device);
static struct hw_module_methods_t copybit_module_methods = {
open: open_copybit
};
/*
* The COPYBIT Module
*/
struct copybit_module_t HAL_MODULE_INFO_SYM = {
common: {
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: COPYBIT_HARDWARE_MODULE_ID,
name: "QCT MSM7K COPYBIT Module",
author: "Google, Inc.",
methods: &copybit_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);
}
/** convert COPYBIT_FORMAT to MDP format */
static int get_format(int format) {
switch (format) {
case HAL_PIXEL_FORMAT_RGB_565: return MDP_RGB_565;
case HAL_PIXEL_FORMAT_RGBX_8888: return MDP_RGBX_8888;
case HAL_PIXEL_FORMAT_RGB_888: return MDP_RGB_888;
case HAL_PIXEL_FORMAT_RGBA_8888: return MDP_RGBA_8888;
case HAL_PIXEL_FORMAT_BGRA_8888: return MDP_BGRA_8888;
case HAL_PIXEL_FORMAT_YCrCb_422_SP: return MDP_Y_CBCR_H2V1;
case HAL_PIXEL_FORMAT_YCrCb_420_SP: return MDP_Y_CBCR_H2V2;
case HAL_PIXEL_FORMAT_YCbCr_422_SP: return MDP_Y_CRCB_H2V1;
case HAL_PIXEL_FORMAT_YCbCr_420_SP: return MDP_Y_CRCB_H2V2;
case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: return MDP_Y_CBCR_H2V2_ADRENO;
}
return -1;
}
/** convert from copybit image to mdp image structure */
static void set_image(struct mdp_img *img, const struct copybit_image_t *rhs)
{
private_handle_t* hnd = (private_handle_t*)rhs->handle;
if(hnd == NULL){
ALOGE("copybit: Invalid handle");
return;
}
img->width = rhs->w;
img->height = rhs->h;
img->format = get_format(rhs->format);
img->offset = hnd->offset;
img->memory_id = hnd->fd;
}
/** setup rectangles */
static void set_rects(struct copybit_context_t *dev,
struct mdp_blit_req *e,
const struct copybit_rect_t *dst,
const struct copybit_rect_t *src,
const struct copybit_rect_t *scissor,
uint32_t horiz_padding,
uint32_t vert_padding) {
struct copybit_rect_t clip;
intersect(&clip, scissor, dst);
e->dst_rect.x = clip.l;
e->dst_rect.y = clip.t;
e->dst_rect.w = clip.r - clip.l;
e->dst_rect.h = clip.b - clip.t;
uint32_t W, H, delta_x, delta_y;
if (dev->mFlags & COPYBIT_TRANSFORM_ROT_90) {
delta_x = (clip.t - dst->t);
delta_y = (dst->r - clip.r);
e->src_rect.w = (clip.b - clip.t);
e->src_rect.h = (clip.r - clip.l);
W = dst->b - dst->t;
H = dst->r - dst->l;
} else {
delta_x = (clip.l - dst->l);
delta_y = (clip.t - dst->t);
e->src_rect.w = (clip.r - clip.l);
e->src_rect.h = (clip.b - clip.t);
W = dst->r - dst->l;
H = dst->b - dst->t;
}
MULDIV(&delta_x, &e->src_rect.w, src->r - src->l, W);
MULDIV(&delta_y, &e->src_rect.h, src->b - src->t, H);
e->src_rect.x = delta_x + src->l;
e->src_rect.y = delta_y + src->t;
if (dev->mFlags & COPYBIT_TRANSFORM_FLIP_V) {
if (dev->mFlags & COPYBIT_TRANSFORM_ROT_90) {
e->src_rect.x = (src->l + src->r) - (e->src_rect.x + e->src_rect.w);
}else{
e->src_rect.y = (src->t + src->b) - (e->src_rect.y + e->src_rect.h);
}
}
if (dev->mFlags & COPYBIT_TRANSFORM_FLIP_H) {
if (dev->mFlags & COPYBIT_TRANSFORM_ROT_90) {
e->src_rect.y = (src->t + src->b) - (e->src_rect.y + e->src_rect.h);
}else{
e->src_rect.x = (src->l + src->r) - (e->src_rect.x + e->src_rect.w);
}
}
}
/** setup mdp request */
static void set_infos(struct copybit_context_t *dev,
struct mdp_blit_req *req, int flags)
{
req->alpha = dev->mAlpha;
req->transp_mask = MDP_TRANSP_NOP;
req->flags = dev->mFlags | flags;
#if defined(COPYBIT_QSD8K)
req->flags |= MDP_BLEND_FG_PREMULT;
#endif
}
/** copy the bits */
static int msm_copybit(struct copybit_context_t *dev, void const *list)
{
int err = ioctl(dev->mFD, MSMFB_BLIT,
(struct mdp_blit_req_list const*)list);
ALOGE_IF(err<0, "copyBits failed (%s)", strerror(errno));
if (err == 0) {
return 0;
} else {
#if DEBUG_MDP_ERRORS
struct mdp_blit_req_list const* l =
(struct mdp_blit_req_list const*)list;
for (int i=0 ; 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=%08lx"
,
i,
l->req[i].src.width,
l->req[i].src.height,
l->req[i].src.format,
l->req[i].src_rect.x,
l->req[i].src_rect.y,
l->req[i].src_rect.w,
l->req[i].src_rect.h,
l->req[i].dst.width,
l->req[i].dst.height,
l->req[i].dst.format,
l->req[i].dst_rect.x,
l->req[i].dst_rect.y,
l->req[i].dst_rect.w,
l->req[i].dst_rect.h,
l->req[i].flags
);
}
#endif
return -errno;
}
}
/*****************************************************************************/
/** Set a parameter to value */
static int set_parameter_copybit(
struct copybit_device_t *dev,
int name,
int value)
{
struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
int status = 0;
if (ctx) {
switch(name) {
case COPYBIT_ROTATION_DEG:
switch (value) {
case 0:
ctx->mFlags &= ~0x7;
break;
case 90:
ctx->mFlags &= ~0x7;
ctx->mFlags |= MDP_ROT_90;
break;
case 180:
ctx->mFlags &= ~0x7;
ctx->mFlags |= MDP_ROT_180;
break;
case 270:
ctx->mFlags &= ~0x7;
ctx->mFlags |= MDP_ROT_270;
break;
default:
ALOGE("Invalid value for COPYBIT_ROTATION_DEG");
status = -EINVAL;
break;
}
break;
case COPYBIT_PLANE_ALPHA:
if (value < 0) value = MDP_ALPHA_NOP;
if (value >= 256) value = 255;
ctx->mAlpha = value;
break;
case COPYBIT_DITHER:
if (value == COPYBIT_ENABLE) {
ctx->mFlags |= MDP_DITHER;
} else if (value == COPYBIT_DISABLE) {
ctx->mFlags &= ~MDP_DITHER;
}
break;
case COPYBIT_BLUR:
if (value == COPYBIT_ENABLE) {
ctx->mFlags |= MDP_BLUR;
} else if (value == COPYBIT_DISABLE) {
ctx->mFlags &= ~MDP_BLUR;
}
break;
case COPYBIT_PREMULTIPLIED_ALPHA:
if(value == COPYBIT_ENABLE) {
ctx->mFlags |= MDP_BLEND_FG_PREMULT;
} else if (value == COPYBIT_DISABLE) {
ctx->mFlags &= ~MDP_BLEND_FG_PREMULT;
}
break;
case COPYBIT_TRANSFORM:
ctx->mFlags &= ~0x7;
ctx->mFlags |= value & 0x7;
break;
default:
status = -EINVAL;
break;
}
} else {
status = -EINVAL;
}
return status;
}
/** Get a static info value */
static int get(struct copybit_device_t *dev, int name)
{
struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
int value;
if (ctx) {
switch(name) {
case COPYBIT_MINIFICATION_LIMIT:
value = MAX_SCALE_FACTOR;
break;
case COPYBIT_MAGNIFICATION_LIMIT:
value = MAX_SCALE_FACTOR;
break;
case COPYBIT_SCALING_FRAC_BITS:
value = 32;
break;
case COPYBIT_ROTATION_STEP_DEG:
value = 90;
break;
default:
value = -EINVAL;
}
} else {
value = -EINVAL;
}
return value;
}
/** do a stretch blit type operation */
static int stretch_copybit(
struct copybit_device_t *dev,
struct copybit_image_t const *dst,
struct copybit_image_t const *src,
struct copybit_rect_t const *dst_rect,
struct copybit_rect_t const *src_rect,
struct copybit_region_t const *region)
{
struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
int status = 0;
private_handle_t *yv12_handle = NULL;
if (ctx) {
struct {
uint32_t count;
struct mdp_blit_req req[12];
} list;
if (ctx->mAlpha < 255) {
switch (src->format) {
// we don't support plane alpha with RGBA formats
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_BGRA_8888:
case HAL_PIXEL_FORMAT_RGBA_5551:
case HAL_PIXEL_FORMAT_RGBA_4444:
ALOGE ("%s : Unsupported Pixel format %d", __FUNCTION__,
src->format);
return -EINVAL;
}
}
if (src_rect->l < 0 || src_rect->r > src->w ||
src_rect->t < 0 || src_rect->b > src->h) {
// this is always invalid
ALOGE ("%s : Invalid source rectangle : src_rect l %d t %d r %d b %d",\
__FUNCTION__, src_rect->l, src_rect->t, src_rect->r, src_rect->b);
return -EINVAL;
}
if (src->w > MAX_DIMENSION || src->h > MAX_DIMENSION) {
ALOGE ("%s : Invalid source dimensions w %d h %d", __FUNCTION__, src->w, src->h);
return -EINVAL;
}
if (dst->w > MAX_DIMENSION || dst->h > MAX_DIMENSION) {
ALOGE ("%s : Invalid DST dimensions w %d h %d", __FUNCTION__, dst->w, dst->h);
return -EINVAL;
}
if(src->format == HAL_PIXEL_FORMAT_YV12) {
int usage = GRALLOC_USAGE_PRIVATE_ADSP_HEAP |
GRALLOC_USAGE_PRIVATE_MM_HEAP;
if (0 == alloc_buffer(&yv12_handle,src->w,src->h,
src->format, usage)){
if(0 == convertYV12toYCrCb420SP(src,yv12_handle)){
(const_cast<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 = sizeof(list.req)/sizeof(list.req[0]);
const struct copybit_rect_t bounds = { 0, 0, dst->w, dst->h };
struct copybit_rect_t clip;
list.count = 0;
status = 0;
while ((status == 0) && region->next(region, &clip)) {
intersect(&clip, &bounds, &clip);
mdp_blit_req* req = &list.req[list.count];
int flags = 0;
private_handle_t* src_hnd = (private_handle_t*)src->handle;
if(src_hnd != NULL && src_hnd->flags & private_handle_t::PRIV_FLAGS_DO_NOT_FLUSH) {
flags |= MDP_BLIT_NON_CACHED;
}
set_infos(ctx, req, flags);
set_image(&req->dst, dst);
set_image(&req->src, src);
set_rects(ctx, req, dst_rect, src_rect, &clip, src->horiz_padding, src->vert_padding);
if (req->src_rect.w<=0 || req->src_rect.h<=0)
continue;
if (req->dst_rect.w<=0 || req->dst_rect.h<=0)
continue;
if (++list.count == maxCount) {
status = msm_copybit(ctx, &list);
list.count = 0;
}
}
if ((status == 0) && list.count) {
status = msm_copybit(ctx, &list);
}
} else {
ALOGE ("%s : Invalid COPYBIT context", __FUNCTION__);
status = -EINVAL;
}
if(yv12_handle)
free_buffer(yv12_handle);
return status;
}
/** Perform a blit type operation */
static int blit_copybit(
struct copybit_device_t *dev,
struct copybit_image_t const *dst,
struct copybit_image_t const *src,
struct copybit_region_t const *region)
{
struct copybit_rect_t dr = { 0, 0, dst->w, dst->h };
struct copybit_rect_t sr = { 0, 0, src->w, src->h };
return stretch_copybit(dev, dst, src, &dr, &sr, region);
}
/*****************************************************************************/
/** Close the copybit device */
static int close_copybit(struct hw_device_t *dev)
{
struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
if (ctx) {
close(ctx->mFD);
free(ctx);
}
return 0;
}
/** Open a new instance of a copybit device using name */
static int open_copybit(const struct hw_module_t* module, const char* name,
struct hw_device_t** device)
{
int status = -EINVAL;
copybit_context_t *ctx;
ctx = (copybit_context_t *)malloc(sizeof(copybit_context_t));
memset(ctx, 0, sizeof(*ctx));
ctx->device.common.tag = HARDWARE_DEVICE_TAG;
ctx->device.common.version = 1;
ctx->device.common.module = const_cast<hw_module_t*>(module);
ctx->device.common.close = close_copybit;
ctx->device.set_parameter = set_parameter_copybit;
ctx->device.get = get;
ctx->device.blit = blit_copybit;
ctx->device.stretch = stretch_copybit;
ctx->mAlpha = MDP_ALPHA_NOP;
ctx->mFlags = 0;
ctx->mFD = open("/dev/graphics/fb0", O_RDWR, 0);
if (ctx->mFD < 0) {
status = errno;
ALOGE("Error opening frame buffer errno=%d (%s)",
status, strerror(status));
status = -status;
} else {
struct fb_fix_screeninfo finfo;
if (ioctl(ctx->mFD, FBIOGET_FSCREENINFO, &finfo) == 0) {
if (strncmp(finfo.id, "msmfb", 5) == 0) {
/* Success */
status = 0;
} else {
ALOGE("Error not msm frame buffer");
status = -EINVAL;
}
} else {
ALOGE("Error executing ioctl for screen info");
status = -errno;
}
}
if (status == 0) {
*device = &ctx->device.common;
} else {
close_copybit(&ctx->device.common);
}
return status;
}

230
libcopybit/copybit.h Normal file
View File

@ -0,0 +1,230 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_COPYBIT_INTERFACE_H
#define ANDROID_COPYBIT_INTERFACE_H
#include <hardware/hardware.h>
#include <stdint.h>
#include <sys/cdefs.h>
#include <sys/types.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_RGBA_5551 = HAL_PIXEL_FORMAT_RGBA_5551,
COPYBIT_FORMAT_RGBA_4444 = HAL_PIXEL_FORMAT_RGBA_4444,
COPYBIT_FORMAT_YCbCr_422_SP = 0x10,
COPYBIT_FORMAT_YCrCb_420_SP = 0x11,
};
/* name for copybit_set_parameter */
enum {
/* rotation of the source image in degrees (0 to 359) */
COPYBIT_ROTATION_DEG = 1,
/* plane alpha value */
COPYBIT_PLANE_ALPHA = 2,
/* enable or disable dithering */
COPYBIT_DITHER = 3,
/* transformation applied (this is a superset of COPYBIT_ROTATION_DEG) */
COPYBIT_TRANSFORM = 4,
/* blurs the copied bitmap. The amount of blurring cannot be changed
* at this time. */
COPYBIT_BLUR = 5,
/* Informs the copybit that the source and destination contains
premultiplied alpha */
COPYBIT_PREMULTIPLIED_ALPHA = 6,
/* FB width */
COPYBIT_FRAMEBUFFER_WIDTH = 7,
/* FB height */
COPYBIT_FRAMEBUFFER_HEIGHT = 8,
};
/* values for copybit_set_parameter(COPYBIT_TRANSFORM) */
enum {
/* flip source image horizontally */
COPYBIT_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H,
/* flip source image vertically */
COPYBIT_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
/* rotate source image 90 degres */
COPYBIT_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
/* rotate source image 180 degres */
COPYBIT_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
/* rotate source image 270 degres */
COPYBIT_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
};
/* enable/disable value copybit_set_parameter */
enum {
COPYBIT_DISABLE = 0,
COPYBIT_ENABLE = 1
};
/* use get_static_info() to query static informations about the hardware */
enum {
/* Maximum amount of minification supported by the hardware*/
COPYBIT_MINIFICATION_LIMIT = 1,
/* Maximum amount of magnification supported by the hardware */
COPYBIT_MAGNIFICATION_LIMIT = 2,
/* Number of fractional bits support by the scaling engine */
COPYBIT_SCALING_FRAC_BITS = 3,
/* Supported rotation step in degres. */
COPYBIT_ROTATION_STEP_DEG = 4,
};
/* Image structure */
struct copybit_image_t {
/* width */
uint32_t w;
/* height */
uint32_t h;
/* format COPYBIT_FORMAT_xxx */
int32_t format;
/* base of buffer with image */
void *base;
/* handle to the image */
native_handle_t* handle;
/* number of pixels added for the stride */
uint32_t horiz_padding;
/* number of pixels added for the vertical stride */
uint32_t vert_padding;
};
/* Rectangle */
struct copybit_rect_t {
/* left */
int l;
/* top */
int t;
/* right */
int r;
/* bottom */
int b;
};
/* Region */
struct copybit_region_t {
int (*next)(struct copybit_region_t const *region, struct copybit_rect_t *rect);
};
/**
* Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
* and the fields of this data structure must begin with hw_module_t
* followed by module specific information.
*/
struct copybit_module_t {
struct hw_module_t common;
};
/**
* Every device data structure must begin with hw_device_t
* followed by module specific public methods and attributes.
*/
struct copybit_device_t {
struct hw_device_t common;
/**
* Set a copybit parameter.
*
* @param dev from open
* @param name one for the COPYBIT_NAME_xxx
* @param value one of the COPYBIT_VALUE_xxx
*
* @return 0 if successful
*/
int (*set_parameter)(struct copybit_device_t *dev, int name, int value);
/**
* Get a static copybit information.
*
* @param dev from open
* @param name one of the COPYBIT_STATIC_xxx
*
* @return value or -EINVAL if error
*/
int (*get)(struct copybit_device_t *dev, int name);
/**
* Execute the bit blit copy operation
*
* @param dev from open
* @param dst is the destination image
* @param src is the source image
* @param region the clip region
*
* @return 0 if successful
*/
int (*blit)(struct copybit_device_t *dev,
struct copybit_image_t const *dst,
struct copybit_image_t const *src,
struct copybit_region_t const *region);
/**
* Execute the stretch bit blit copy operation
*
* @param dev from open
* @param dst is the destination image
* @param src is the source image
* @param dst_rect is the destination rectangle
* @param src_rect is the source rectangle
* @param region the clip region
*
* @return 0 if successful
*/
int (*stretch)(struct copybit_device_t *dev,
struct copybit_image_t const *dst,
struct copybit_image_t const *src,
struct copybit_rect_t const *dst_rect,
struct copybit_rect_t const *src_rect,
struct copybit_region_t const *region);
};
/** convenience API for opening and closing a device */
static inline int copybit_open(const struct hw_module_t* module,
struct copybit_device_t** device) {
return module->methods->open(module,
COPYBIT_HARDWARE_COPYBIT0, (struct hw_device_t**)device);
}
static inline int copybit_close(struct copybit_device_t* device) {
return device->common.close(&device->common);
}
__END_DECLS
#endif // ANDROID_COPYBIT_INTERFACE_H

1477
libcopybit/copybit_c2d.cpp Normal file

File diff suppressed because it is too large Load Diff

56
libcopybit/copybit_priv.h Normal file
View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <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;
};

View File

@ -0,0 +1,263 @@
/*
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LOG_TAG "copybit"
#include <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, 16);
unsigned int c_size = c_width * src->h/2;
unsigned int chromaPadding = c_width - width/2;
unsigned int chromaSize = c_size * 2;
unsigned char* newChroma = (unsigned char *)(yv12_handle->base + y_size);
unsigned char* oldChroma = (unsigned char*)(hnd->base + y_size);
memcpy((char *)yv12_handle->base,(char *)hnd->base,y_size);
#ifdef __ARM_HAVE_NEON
/* interleave */
if(!chromaPadding) {
unsigned char * t1 = newChroma;
unsigned char * t2 = oldChroma;
unsigned char * t3 = t2 + chromaSize/2;
for(unsigned int i=0; i < (chromaSize/2)>>3; i++) {
__asm__ __volatile__ (
"vld1.u8 d0, [%0]! \n"
"vld1.u8 d1, [%1]! \n"
"vst2.u8 {d0, d1}, [%2]! \n"
:"+r"(t2), "+r"(t3), "+r"(t1)
:
:"memory","d0","d1"
);
}
}
#else //__ARM_HAVE_NEON
if(!chromaPadding) {
for(unsigned int i = 0; i< chromaSize/2; i++) {
newChroma[i*2] = oldChroma[i];
newChroma[i*2+1] = oldChroma[i+chromaSize/2];
}
}
#endif
// If the image is not aligned to 16 pixels,
// convert using the C routine below
// r1 tracks the row of the source buffer
// r2 tracks the row of the destination buffer
// The width/2 checks are to avoid copying
// from the padding
if(chromaPadding) {
unsigned int r1 = 0, r2 = 0, i = 0, j = 0;
while(r1 < height/2) {
if(j == width) {
j = 0;
r2++;
continue;
}
if (j+1 == width) {
newChroma[r2*width + j] = oldChroma[r1*c_width+i];
r2++;
newChroma[r2*width] = oldChroma[r1*c_width+i+c_size];
j = 1;
} else {
newChroma[r2*width + j] = oldChroma[r1*c_width+i];
newChroma[r2*width + j + 1] = oldChroma[r1*c_width+i+c_size];
j+=2;
}
i++;
if (i == width/2 ) {
i = 0;
r1++;
}
}
}
return 0;
}
struct copyInfo{
int width;
int height;
int src_stride;
int dst_stride;
int src_plane1_offset;
int src_plane2_offset;
int dst_plane1_offset;
int dst_plane2_offset;
};
/* Internal function to do the actual copy of source to destination */
static int copy_source_to_destination(const int src_base, const int dst_base,
copyInfo& info)
{
if (!src_base || !dst_base) {
ALOGE("%s: invalid memory src_base = 0x%x dst_base=0x%x",
__FUNCTION__, src_base, dst_base);
return COPYBIT_FAILURE;
}
int width = info.width;
int height = info.height;
unsigned char *src = (unsigned char*)src_base;
unsigned char *dst = (unsigned char*)dst_base;
// Copy the luma
for (int i = 0; i < height; i++) {
memcpy(dst, src, width);
src += info.src_stride;
dst += info.dst_stride;
}
// Copy plane 1
src = (unsigned char*)(src_base + info.src_plane1_offset);
dst = (unsigned char*)(dst_base + info.dst_plane1_offset);
width = width/2;
height = height/2;
for (int i = 0; i < height; i++) {
memcpy(dst, src, info.src_stride);
src += info.src_stride;
dst += info.dst_stride;
}
return 0;
}
/*
* Function to convert the c2d format into an equivalent Android format
*
* @param: source buffer handle
* @param: destination image
*
* @return: return status
*/
int convert_yuv_c2d_to_yuv_android(private_handle_t *hnd,
struct copybit_image_t const *rhs)
{
ALOGD("Enter %s", __FUNCTION__);
if (!hnd || !rhs) {
ALOGE("%s: invalid inputs hnd=%p rhs=%p", __FUNCTION__, hnd, rhs);
return COPYBIT_FAILURE;
}
int ret = COPYBIT_SUCCESS;
private_handle_t *dst_hnd = (private_handle_t *)rhs->handle;
copyInfo info;
info.width = rhs->w;
info.height = rhs->h;
info.src_stride = ALIGN(info.width, 32);
info.dst_stride = ALIGN(info.width, 16);
switch(rhs->format) {
case HAL_PIXEL_FORMAT_YCbCr_420_SP:
case HAL_PIXEL_FORMAT_YCrCb_420_SP: {
info.src_plane1_offset = info.src_stride*info.height;
info.dst_plane1_offset = info.dst_stride*info.height;
} break;
case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: {
// Chroma is 2K aligned for the NV12 encodeable format.
info.src_plane1_offset = ALIGN(info.src_stride*info.height, 2048);
info.dst_plane1_offset = ALIGN(info.dst_stride*info.height, 2048);
} break;
default:
ALOGE("%s: unsupported format (format=0x%x)", __FUNCTION__,
rhs->format);
return COPYBIT_FAILURE;
}
ret = copy_source_to_destination(hnd->base, dst_hnd->base, info);
return ret;
}
/*
* Function to convert the Android format into an equivalent C2D format
*
* @param: source buffer handle
* @param: destination image
*
* @return: return status
*/
int convert_yuv_android_to_yuv_c2d(private_handle_t *hnd,
struct copybit_image_t const *rhs)
{
if (!hnd || !rhs) {
ALOGE("%s: invalid inputs hnd=%p rhs=%p", __FUNCTION__, hnd, rhs);
return COPYBIT_FAILURE;
}
int ret = COPYBIT_SUCCESS;
private_handle_t *dst_hnd = (private_handle_t *)rhs->handle;
copyInfo info;
info.width = rhs->w;
info.height = rhs->h;
info.src_stride = ALIGN(hnd->width, 16);
info.dst_stride = ALIGN(info.width, 32);
switch(rhs->format) {
case HAL_PIXEL_FORMAT_YCbCr_420_SP:
case HAL_PIXEL_FORMAT_YCrCb_420_SP: {
info.src_plane1_offset = info.src_stride*info.height;
info.dst_plane1_offset = info.dst_stride*info.height;
} break;
case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: {
// Chroma is 2K aligned for the NV12 encodeable format.
info.src_plane1_offset = ALIGN(info.src_stride*info.height, 2048);
info.dst_plane1_offset = ALIGN(info.dst_stride*info.height, 2048);
} break;
default:
ALOGE("%s: unsupported format (format=0x%x)", __FUNCTION__,
rhs->format);
return -1;
}
ret = copy_source_to_destination(hnd->base, dst_hnd->base, info);
return ret;
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <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);

View File

@ -4,8 +4,7 @@ include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
LOCAL_SHARED_LIBRARIES := liblog libcutils
LOCAL_C_INCLUDES :=
LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc
LOCAL_C_INCLUDES := hardware/qcom/display/libgralloc
LOCAL_ADDITIONAL_DEPENDENCIES :=
LOCAL_SRC_FILES := genlock.cpp
LOCAL_CFLAGS:= -DLOG_TAG=\"libgenlock\"

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -43,7 +43,7 @@
#endif
namespace {
/* Internal function to map the userspace locks to the kernel lock types */
/* Internal function to map the userspace locks to the kernel lock types */
int get_kernel_lock_type(genlock_lock_type lockType)
{
int kLockType = 0;
@ -62,7 +62,7 @@ namespace {
/* Internal function to perform the actual lock/unlock operations */
genlock_status_t perform_lock_unlock_operation(native_handle_t *buffer_handle,
int lockType, int timeout)
int lockType, int timeout)
{
if (private_handle_t::validate(buffer_handle)) {
ALOGE("%s: handle is invalid", __FUNCTION__);
@ -73,7 +73,7 @@ namespace {
if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
if (hnd->genlockPrivFd < 0) {
ALOGE("%s: the lock has not been created, or has not been attached",
__FUNCTION__);
__FUNCTION__);
return GENLOCK_FAILURE;
}
@ -85,7 +85,7 @@ namespace {
if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_LOCK, &lock)) {
ALOGE("%s: GENLOCK_IOC_LOCK failed (lockType0x%x, err=%s fd=%d)", __FUNCTION__,
lockType, strerror(errno), hnd->fd);
lockType, strerror(errno), hnd->fd);
if (ETIMEDOUT == errno)
return GENLOCK_TIMEDOUT;
@ -132,7 +132,7 @@ genlock_status_t genlock_create_lock(native_handle_t *buffer_handle)
int fd = open(GENLOCK_DEVICE, O_RDWR);
if (fd < 0) {
ALOGE("%s: open genlock device failed (err=%s)", __FUNCTION__,
strerror(errno));
strerror(errno));
return GENLOCK_FAILURE;
}
@ -140,7 +140,7 @@ genlock_status_t genlock_create_lock(native_handle_t *buffer_handle)
genlock_lock lock;
if (ioctl(fd, GENLOCK_IOC_NEW, NULL)) {
ALOGE("%s: GENLOCK_IOC_NEW failed (error=%s)", __FUNCTION__,
strerror(errno));
strerror(errno));
close_genlock_fd_and_handle(fd, lock.fd);
ret = GENLOCK_FAILURE;
}
@ -149,7 +149,7 @@ genlock_status_t genlock_create_lock(native_handle_t *buffer_handle)
if (GENLOCK_FAILURE != ret) {
if (ioctl(fd, GENLOCK_IOC_EXPORT, &lock)) {
ALOGE("%s: GENLOCK_IOC_EXPORT failed (error=%s)", __FUNCTION__,
strerror(errno));
strerror(errno));
close_genlock_fd_and_handle(fd, lock.fd);
ret = GENLOCK_FAILURE;
}
@ -219,7 +219,7 @@ genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle)
int fd = open(GENLOCK_DEVICE, O_RDWR);
if (fd < 0) {
ALOGE("%s: open genlock device failed (err=%s)", __FUNCTION__,
strerror(errno));
strerror(errno));
return GENLOCK_FAILURE;
}
@ -228,7 +228,7 @@ genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle)
lock.fd = hnd->genlockHandle;
if (ioctl(fd, GENLOCK_IOC_ATTACH, &lock)) {
ALOGE("%s: GENLOCK_IOC_ATTACH failed (err=%s)", __FUNCTION__,
strerror(errno));
strerror(errno));
close_genlock_fd_and_handle(fd, lock.fd);
ret = GENLOCK_FAILURE;
}
@ -253,8 +253,8 @@ genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle)
* @return error status.
*/
genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle,
genlock_lock_type_t lockType,
int timeout)
genlock_lock_type_t lockType,
int timeout)
{
genlock_status_t ret = GENLOCK_NO_ERROR;
#ifdef USE_GENLOCK
@ -280,7 +280,7 @@ genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle,
*
* @param: handle of the buffer to be unlocked.
* @return: error status.
*/
*/
genlock_status_t genlock_unlock_buffer(native_handle_t *buffer_handle)
{
genlock_status_t ret = GENLOCK_NO_ERROR;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -36,80 +36,80 @@
extern "C" {
#endif
/* Genlock lock types */
typedef enum genlock_lock_type{
GENLOCK_READ_LOCK = 1<<0, // Read lock
GENLOCK_WRITE_LOCK = 1<<1, // Write lock
}genlock_lock_type_t;
/* Genlock lock types */
typedef enum genlock_lock_type{
GENLOCK_READ_LOCK = 1<<0, // Read lock
GENLOCK_WRITE_LOCK = 1<<1, // Write lock
}genlock_lock_type_t;
/* Genlock return values */
typedef enum genlock_status{
GENLOCK_NO_ERROR = 0,
GENLOCK_TIMEDOUT,
GENLOCK_FAILURE,
} genlock_status_t;
/* Genlock return values */
typedef enum genlock_status{
GENLOCK_NO_ERROR = 0,
GENLOCK_TIMEDOUT,
GENLOCK_FAILURE,
} genlock_status_t;
/* Genlock defines */
/* Genlock defines */
#define GENLOCK_MAX_TIMEOUT 1000 // Max 1s timeout
/*
* Create a genlock lock. The genlock lock file descriptor and the lock
* handle are stored in the buffer_handle.
*
* @param: handle of the buffer
* @return error status.
*/
genlock_status_t genlock_create_lock(native_handle_t *buffer_handle);
/*
* Create a genlock lock. The genlock lock file descriptor and the lock
* handle are stored in the buffer_handle.
*
* @param: handle of the buffer
* @return error status.
*/
genlock_status_t genlock_create_lock(native_handle_t *buffer_handle);
/*
* Release a genlock lock associated with the handle.
*
* @param: handle of the buffer
* @return error status.
*/
genlock_status_t genlock_release_lock(native_handle_t *buffer_handle);
/*
* Release a genlock lock associated with the handle.
*
* @param: handle of the buffer
* @return error status.
*/
genlock_status_t genlock_release_lock(native_handle_t *buffer_handle);
/*
* Attach a lock to the buffer handle passed via an IPC.
*
* @param: handle of the buffer
* @return error status.
*/
genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle);
/*
* Attach a lock to the buffer handle passed via an IPC.
*
* @param: handle of the buffer
* @return error status.
*/
genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle);
/*
* Lock the buffer specified by the buffer handle. The lock held by the buffer
* is specified by the lockType. This function will block if a write lock is
* requested on the buffer which has previously been locked for a read or write
* operation. A buffer can be locked by multiple clients for read. An optional
* timeout value can be specified. By default, there is no timeout.
*
* @param: handle of the buffer
* @param: type of lock to be acquired by the buffer.
* @param: timeout value in ms. GENLOCK_MAX_TIMEOUT is the maximum timeout value.
* @return error status.
*/
genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle,
genlock_lock_type_t lockType,
int timeout);
/*
* Lock the buffer specified by the buffer handle. The lock held by the buffer
* is specified by the lockType. This function will block if a write lock is
* requested on the buffer which has previously been locked for a read or write
* operation. A buffer can be locked by multiple clients for read. An optional
* timeout value can be specified. By default, there is no timeout.
*
* @param: handle of the buffer
* @param: type of lock to be acquired by the buffer.
* @param: timeout value in ms. GENLOCK_MAX_TIMEOUT is the maximum timeout value.
* @return error status.
*/
genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle,
genlock_lock_type_t lockType,
int timeout);
/*
* Unlocks a buffer that has previously been locked by the client.
*
* @param: handle of the buffer to be unlocked.
* @return: error status.
*/
genlock_status_t genlock_unlock_buffer(native_handle_t *buffer_handle);
/*
* Unlocks a buffer that has previously been locked by the client.
*
* @param: handle of the buffer to be unlocked.
* @return: error status.
*/
genlock_status_t genlock_unlock_buffer(native_handle_t *buffer_handle);
/*
* Blocks the calling process until the lock held on the handle is unlocked.
*
* @param: handle of the buffer
* @param: timeout value for the wait.
* return: error status.
*/
genlock_status_t genlock_wait(native_handle_t *buffer_handle, int timeout);
/*
* Blocks the calling process until the lock held on the handle is unlocked.
*
* @param: handle of the buffer
* @param: timeout value for the wait.
* return: error status.
*/
genlock_status_t genlock_wait(native_handle_t *buffer_handle, int timeout);
#ifdef __cplusplus
}

View File

@ -11,65 +11,48 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Use this flag until pmem/ashmem is implemented in the new gralloc
LOCAL_PATH := $(call my-dir)
# HAL module implemenation, not prelinked and stored in
# hw/<OVERLAY_HARDWARE_MODULE_ID>.<ro.product.board>.so
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog libcutils libGLESv1_CM libutils libmemalloc libQcomUI
LOCAL_SHARED_LIBRARIES += libgenlock
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libmemalloc
LOCAL_SHARED_LIBRARIES += libgenlock libQcomUI libGLESv1_CM
LOCAL_C_INCLUDES := hardware/qcom/display/liboverlay/
LOCAL_C_INCLUDES += hardware/qcom/display/libgenlock
LOCAL_C_INCLUDES += hardware/qcom/display/libqcomui
LOCAL_MODULE := gralloc.$(TARGET_BOARD_PLATFORM)
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS := -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).gralloc\" \
-DDEBUG_CALC_FPS
LOCAL_SRC_FILES := gpu.cpp gralloc.cpp framebuffer.cpp mapper.cpp
LOCAL_C_INCLUDES += hardware/qcom/display/libgenlock
LOCAL_C_INCLUDES += hardware/qcom/display/libqcomui
LOCAL_ADDITIONAL_DEPENDENCIES +=
LOCAL_SRC_FILES := framebuffer.cpp \
gpu.cpp \
gralloc.cpp \
mapper.cpp
ifeq ($(TARGET_USES_POST_PROCESSING),true)
LOCAL_CFLAGS += -DUSES_POST_PROCESSING
LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/pp/inc
endif
LOCAL_MODULE := gralloc.$(TARGET_BOARD_PLATFORM)
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).gralloc\" -DHOST -DDEBUG_CALC_FPS
ifeq ($(call is-board-platform,msm7627_surf msm7627_6x),true)
LOCAL_CFLAGS += -DTARGET_MSM7x27
ifeq ($(TARGET_USES_MDP3), true)
LOCAL_CFLAGS += -DUSE_MDP3
endif
ifeq ($(TARGET_HAVE_HDMI_OUT),true)
LOCAL_CFLAGS += -DHDMI_DUAL_DISPLAY
LOCAL_C_INCLUDES += hardware/qcom/display/liboverlay
LOCAL_SHARED_LIBRARIES += liboverlay
endif
ifeq ($(TARGET_USES_SF_BYPASS),true)
LOCAL_CFLAGS += -DSF_BYPASS
endif
ifeq ($(TARGET_GRALLOC_USES_ASHMEM),true)
LOCAL_CFLAGS += -DUSE_ASHMEM
endif
include $(BUILD_SHARED_LIBRARY)
#MemAlloc Library
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
LOCAL_C_INCLUDES += hardware/qcom/display/libqcomui
LOCAL_ADDITIONAL_DEPENDENCIES +=
LOCAL_C_INCLUDES := hardware/qcom/display/libqcomui
LOCAL_SHARED_LIBRARIES := liblog libcutils libutils
LOCAL_SRC_FILES := ionalloc.cpp \
alloc_controller.cpp
LOCAL_SRC_FILES := ionalloc.cpp alloc_controller.cpp
LOCAL_CFLAGS:= -DLOG_TAG=\"memalloc\"
ifeq ($(TARGET_USES_ION),true)
LOCAL_CFLAGS += -DUSE_ION
endif
LOCAL_CFLAGS += -DUSE_ION
LOCAL_MODULE := libmemalloc
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)

View File

@ -34,24 +34,26 @@
#include "alloc_controller.h"
#include "memalloc.h"
#include "ionalloc.h"
#include "pmemalloc.h"
#include "ashmemalloc.h"
#include "gr.h"
#include "qcomutils/comptype.h"
using namespace gralloc;
using android::sp;
const int GRALLOC_HEAP_MASK = GRALLOC_USAGE_PRIVATE_ADSP_HEAP |
GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP |
GRALLOC_USAGE_PRIVATE_SMI_HEAP |
GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP |
GRALLOC_USAGE_PRIVATE_IOMMU_HEAP |
GRALLOC_USAGE_PRIVATE_MM_HEAP |
GRALLOC_USAGE_PRIVATE_WRITEBACK_HEAP |
GRALLOC_USAGE_PRIVATE_CAMERA_HEAP;
const int GRALLOC_HEAP_MASK = GRALLOC_USAGE_PRIVATE_ADSP_HEAP |
GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP |
GRALLOC_USAGE_PRIVATE_SMI_HEAP |
GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP |
GRALLOC_USAGE_PRIVATE_IOMMU_HEAP |
GRALLOC_USAGE_PRIVATE_MM_HEAP |
GRALLOC_USAGE_PRIVATE_WRITEBACK_HEAP |
GRALLOC_USAGE_PRIVATE_CAMERA_HEAP;
//Common functions
static bool canFallback(int compositionType, int usage, bool triedSystem)
static bool canFallback(int usage, bool triedSystem)
{
// Fallback to system heap when alloc fails unless
// 1. Composition type is MDP
@ -60,11 +62,12 @@ static bool canFallback(int compositionType, int usage, bool triedSystem)
// 4. The heap type is protected
// 5. The buffer is meant for external display only
if(compositionType == MDP_COMPOSITION)
if(QCCompositionType::getInstance().getCompositionType() & COMPOSITION_TYPE_MDP)
return false;
if(triedSystem)
return false;
if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_PROTECTED))
if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_PROTECTED |
GRALLOC_USAGE_PRIVATE_CP_BUFFER))
return false;
if(usage & (GRALLOC_HEAP_MASK | GRALLOC_USAGE_EXTERNAL_ONLY))
return false;
@ -107,13 +110,15 @@ IonController::IonController()
}
int IonController::allocate(alloc_data& data, int usage,
int compositionType)
int compositionType)
{
int ionFlags = 0;
int ret;
bool noncontig = false;
data.uncached = useUncached(usage);
data.allocType = 0;
if(usage & GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP)
ionFlags |= ION_HEAP(ION_SF_HEAP_ID);
@ -134,11 +139,13 @@ int IonController::allocate(alloc_data& data, int usage,
if(usage & GRALLOC_USAGE_PRIVATE_CAMERA_HEAP)
ionFlags |= ION_HEAP(ION_CAMERA_HEAP_ID);
if(usage & GRALLOC_USAGE_PROTECTED)
if(usage & GRALLOC_USAGE_PRIVATE_CP_BUFFER)
ionFlags |= ION_SECURE;
if(usage & GRALLOC_USAGE_PRIVATE_DO_NOT_MAP)
data.allocType = private_handle_t::PRIV_FLAGS_NOT_MAPPED;
data.allocType |= private_handle_t::PRIV_FLAGS_NOT_MAPPED;
else
data.allocType &= ~(private_handle_t::PRIV_FLAGS_NOT_MAPPED);
// if no flags are set, default to
// SF + IOMMU heaps, so that bypass can work
@ -149,9 +156,9 @@ int IonController::allocate(alloc_data& data, int usage,
data.flags = ionFlags;
ret = mIonAlloc->alloc_buffer(data);
// Fallback
if(ret < 0 && canFallback(compositionType,
usage,
if(ret < 0 && canFallback(usage,
(ionFlags & ION_SYSTEM_HEAP_ID)))
{
ALOGW("Falling back to system heap");
@ -161,7 +168,7 @@ int IonController::allocate(alloc_data& data, int usage,
}
if(ret >= 0 ) {
data.allocType = private_handle_t::PRIV_FLAGS_USES_ION;
data.allocType |= private_handle_t::PRIV_FLAGS_USES_ION;
if(noncontig)
data.allocType |= private_handle_t::PRIV_FLAGS_NONCONTIGUOUS_MEM;
if(ionFlags & ION_SECURE)
@ -183,14 +190,14 @@ sp<IMemAlloc> IonController::getAllocator(int flags)
return memalloc;
}
#if 0
//-------------- PmemKernelController-----------------------//
//XXX: Remove - we're not using pmem anymore
#if 0
PmemKernelController::PmemKernelController()
{
mPmemAdspAlloc = new PmemKernelAlloc(DEVICE_PMEM_ADSP);
// XXX: Right now, there is no need to maintain an instance
// of the SMI allocator as we need it only in a few cases
mPmemAdspAlloc = new PmemKernelAlloc(DEVICE_PMEM_ADSP);
// XXX: Right now, there is no need to maintain an instance
// of the SMI allocator as we need it only in a few cases
}
PmemKernelController::~PmemKernelController()
@ -198,7 +205,7 @@ PmemKernelController::~PmemKernelController()
}
int PmemKernelController::allocate(alloc_data& data, int usage,
int compositionType)
int compositionType)
{
int ret = 0;
bool adspFallback = false;
@ -258,12 +265,13 @@ PmemAshmemController::~PmemAshmemController()
}
int PmemAshmemController::allocate(alloc_data& data, int usage,
int compositionType)
int compositionType)
{
int ret = 0;
data.allocType = 0;
// Make buffers cacheable by default
data.uncached = false;
data.uncached = false;
// Override if we explicitly need uncached buffers
if (usage & GRALLOC_USAGE_PRIVATE_UNCACHED)
@ -298,7 +306,7 @@ int PmemAshmemController::allocate(alloc_data& data, int usage,
// Fallback
if(ret >= 0 ) {
data.allocType = private_handle_t::PRIV_FLAGS_USES_PMEM;
} else if(ret < 0 && canFallback(compositionType, usage, false)) {
} else if(ret < 0 && canFallback(usage, false)) {
ALOGW("Falling back to ashmem");
ret = mAshmemAlloc->alloc_buffer(data);
if(ret >= 0) {
@ -327,9 +335,8 @@ sp<IMemAlloc> PmemAshmemController::getAllocator(int flags)
return memalloc;
}
#endif
size_t getBufferSizeAndDimensions(int width, int height, int format,
int& alignedw, int &alignedh)
int& alignedw, int &alignedh)
{
size_t size;
@ -376,16 +383,25 @@ size_t getBufferSizeAndDimensions(int width, int height, int format,
if (HAL_PIXEL_FORMAT_NV12_ENCODEABLE == format) {
// The encoder requires a 2K aligned chroma offset.
size = ALIGN(alignedw*alignedh, 2048) +
(ALIGN(alignedw/2, 16) * (alignedh/2))*2;
(ALIGN(alignedw/2, 16) * (alignedh/2))*2;
} else {
size = alignedw*alignedh +
(ALIGN(alignedw/2, 16) * (alignedh/2))*2;
}
size = ALIGN(size, 4096);
break;
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
case HAL_PIXEL_FORMAT_YCrCb_422_SP:
if(width & 1) {
ALOGE("width is odd for the YUV422_SP format");
return -EINVAL;
}
alignedw = ALIGN(width, 16);
alignedh = height;
size = ALIGN(alignedw * alignedh * 2, 4096);
break;
default:
ALOGE("unrecognized pixel format: %d", format);
ALOGE("unrecognized pixel format: 0x%x", format);
return -EINVAL;
}
@ -397,31 +413,31 @@ size_t getBufferSizeAndDimensions(int width, int height, int format,
// to free the buffer using the free_buffer function
int alloc_buffer(private_handle_t **pHnd, int w, int h, int format, int usage)
{
alloc_data data;
int alignedw, alignedh;
android::sp<gralloc::IAllocController> sAlloc =
gralloc::IAllocController::getInstance(false);
data.base = 0;
data.fd = -1;
data.offset = 0;
data.size = getBufferSizeAndDimensions(w, h, format, alignedw, alignedh);
data.align = getpagesize();
data.uncached = useUncached(usage);
int allocFlags = usage;
alloc_data data;
int alignedw, alignedh;
android::sp<gralloc::IAllocController> sAlloc =
gralloc::IAllocController::getInstance(false);
data.base = 0;
data.fd = -1;
data.offset = 0;
data.size = getBufferSizeAndDimensions(w, h, format, alignedw, alignedh);
data.align = getpagesize();
data.uncached = useUncached(usage);
int allocFlags = usage;
int err = sAlloc->allocate(data, allocFlags, 0);
if (0 != err) {
ALOGE("%s: allocate failed", __FUNCTION__);
return -ENOMEM;
}
int err = sAlloc->allocate(data, allocFlags, 0);
if (0 != err) {
ALOGE("%s: allocate failed", __FUNCTION__);
return -ENOMEM;
}
private_handle_t* hnd = new private_handle_t(data.fd, data.size,
data.allocType, 0, format, alignedw, alignedh);
hnd->base = (int) data.base;
hnd->offset = data.offset;
hnd->gpuaddr = 0;
*pHnd = hnd;
return 0;
private_handle_t* hnd = new private_handle_t(data.fd, data.size,
data.allocType, 0, format, alignedw, alignedh);
hnd->base = (int) data.base;
hnd->offset = data.offset;
hnd->gpuaddr = 0;
*pHnd = hnd;
return 0;
}
void free_buffer(private_handle_t *hnd)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -33,82 +33,82 @@
namespace gralloc {
struct alloc_data;
class IMemAlloc;
class IonAlloc;
struct alloc_data;
class IMemAlloc;
class IonAlloc;
class IAllocController : public android::RefBase {
class IAllocController : public android::RefBase {
public:
/* Allocate using a suitable method
* Returns the type of buffer allocated
*/
virtual int allocate(alloc_data& data, int usage,
int compositionType) = 0;
public:
/* Allocate using a suitable method
* Returns the type of buffer allocated
*/
virtual int allocate(alloc_data& data, int usage,
int compositionType) = 0;
virtual android::sp<IMemAlloc> getAllocator(int flags) = 0;
virtual android::sp<IMemAlloc> getAllocator(int flags) = 0;
virtual ~IAllocController() {};
virtual ~IAllocController() {};
static android::sp<IAllocController> getInstance(bool useMasterHeap);
static android::sp<IAllocController> getInstance(bool useMasterHeap);
private:
static android::sp<IAllocController> sController;
private:
static android::sp<IAllocController> sController;
};
};
class IonController : public IAllocController {
class IonController : public IAllocController {
public:
virtual int allocate(alloc_data& data, int usage,
int compositionType);
public:
virtual int allocate(alloc_data& data, int usage,
int compositionType);
virtual android::sp<IMemAlloc> getAllocator(int flags);
virtual android::sp<IMemAlloc> getAllocator(int flags);
IonController();
IonController();
private:
android::sp<IonAlloc> mIonAlloc;
private:
android::sp<IonAlloc> mIonAlloc;
};
};
class PmemKernelController : public IAllocController {
class PmemKernelController : public IAllocController {
public:
virtual int allocate(alloc_data& data, int usage,
int compositionType);
public:
virtual int allocate(alloc_data& data, int usage,
int compositionType);
virtual android::sp<IMemAlloc> getAllocator(int flags);
virtual android::sp<IMemAlloc> getAllocator(int flags);
PmemKernelController ();
PmemKernelController ();
~PmemKernelController ();
~PmemKernelController ();
private:
android::sp<IMemAlloc> mPmemAdspAlloc;
private:
android::sp<IMemAlloc> mPmemAdspAlloc;
};
};
// Main pmem controller - this should only
// be used within gralloc
class PmemAshmemController : public IAllocController {
// Main pmem controller - this should only
// be used within gralloc
class PmemAshmemController : public IAllocController {
public:
virtual int allocate(alloc_data& data, int usage,
int compositionType);
public:
virtual int allocate(alloc_data& data, int usage,
int compositionType);
virtual android::sp<IMemAlloc> getAllocator(int flags);
virtual android::sp<IMemAlloc> getAllocator(int flags);
PmemAshmemController();
PmemAshmemController();
~PmemAshmemController();
~PmemAshmemController();
private:
android::sp<IMemAlloc> mPmemUserspaceAlloc;
android::sp<IMemAlloc> mAshmemAlloc;
android::sp<IAllocController> mPmemKernelCtrl;
private:
android::sp<IMemAlloc> mPmemUserspaceAlloc;
android::sp<IMemAlloc> mAshmemAlloc;
android::sp<IAllocController> mPmemKernelCtrl;
};
};
} //end namespace gralloc
#endif // GRALLOC_ALLOCCONTROLLER_H

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -53,14 +53,14 @@ int AshmemAlloc::alloc_buffer(alloc_data& data)
} else {
if (ashmem_set_prot_region(fd, prot) < 0) {
ALOGE("ashmem_set_prot_region(fd=%d, prot=%x) failed (%s)",
fd, prot, strerror(errno));
fd, prot, strerror(errno));
close(fd);
err = -errno;
} else {
base = mmap(0, data.size, prot, MAP_SHARED|MAP_POPULATE|MAP_LOCKED, fd, 0);
if (base == MAP_FAILED) {
ALOGE("alloc mmap(fd=%d, size=%d, prot=%x) failed (%s)",
fd, data.size, prot, strerror(errno));
fd, data.size, prot, strerror(errno));
close(fd);
err = -errno;
} else {
@ -74,7 +74,7 @@ int AshmemAlloc::alloc_buffer(alloc_data& data)
data.offset = offset;
clean_buffer(base, data.size, offset, fd);
ALOGD("ashmem: Allocated buffer base:%p size:%d fd:%d",
base, data.size, fd);
base, data.size, fd);
}
return err;
@ -84,7 +84,7 @@ int AshmemAlloc::alloc_buffer(alloc_data& data)
int AshmemAlloc::free_buffer(void* base, size_t size, int offset, int fd)
{
ALOGD("ashmem: Freeing buffer base:%p size:%d fd:%d",
base, size, fd);
base, size, fd);
int err = 0;
if(!base) {
@ -102,15 +102,15 @@ int AshmemAlloc::map_buffer(void **pBase, size_t size, int offset, int fd)
void *base = 0;
base = mmap(0, size, PROT_READ| PROT_WRITE,
MAP_SHARED|MAP_POPULATE, fd, 0);
MAP_SHARED|MAP_POPULATE, fd, 0);
*pBase = base;
if(base == MAP_FAILED) {
ALOGE("ashmem: Failed to map memory in the client: %s",
strerror(errno));
strerror(errno));
err = -errno;
} else {
ALOGD("ashmem: Mapped buffer base:%p size:%d fd:%d",
base, size, fd);
base, size, fd);
}
return err;
}
@ -121,7 +121,7 @@ int AshmemAlloc::unmap_buffer(void *base, size_t size, int offset)
int err = munmap(base, size);
if(err) {
ALOGE("ashmem: Failed to unmap memory at %p: %s",
base, strerror(errno));
base, strerror(errno));
}
return err;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -34,23 +34,23 @@
#include <linux/ion.h>
namespace gralloc {
class AshmemAlloc : public IMemAlloc {
class AshmemAlloc : public IMemAlloc {
public:
virtual int alloc_buffer(alloc_data& data);
public:
virtual int alloc_buffer(alloc_data& data);
virtual int free_buffer(void *base, size_t size,
int offset, int fd);
virtual int free_buffer(void *base, size_t size,
int offset, int fd);
virtual int map_buffer(void **pBase, size_t size,
int offset, int fd);
virtual int map_buffer(void **pBase, size_t size,
int offset, int fd);
virtual int unmap_buffer(void *base, size_t size,
int offset);
virtual int unmap_buffer(void *base, size_t size,
int offset);
virtual int clean_buffer(void*base, size_t size,
int offset, int fd);
virtual int clean_buffer(void*base, size_t size,
int offset, int fd);
};
};
}
#endif /* GRALLOC_ASHMEMALLOC_H */

181
libgralloc/fb_priv.h Normal file
View File

@ -0,0 +1,181 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FB_PRIV_H
#define FB_PRIV_H
#include <linux/fb.h>
#define NUM_FRAMEBUFFERS_MIN 2
//XXX: Enable triple framebuffers
#define NUM_FRAMEBUFFERS_MAX 2
#define NO_SURFACEFLINGER_SWAPINTERVAL
#define COLOR_FORMAT(x) (x & 0xFFF) // Max range for colorFormats is 0 - FFF
#ifdef __cplusplus
template <class T>
struct Node
{
T data;
Node<T> *next;
};
template <class T>
class Queue
{
public:
Queue(): front(NULL), back(NULL), len(0) {dummy = new T;}
~Queue()
{
clear();
delete dummy;
}
void push(const T& item) //add an item to the back of the queue
{
if(len != 0) { //if the queue is not empty
back->next = new Node<T>; //create a new node
back = back->next; //set the new node as the back node
back->data = item;
back->next = NULL;
} else {
back = new Node<T>;
back->data = item;
back->next = NULL;
front = back;
}
len++;
}
void pop() //remove the first item from the queue
{
if (isEmpty())
return; //if the queue is empty, no node to dequeue
T item = front->data;
Node<T> *tmp = front;
front = front->next;
delete tmp;
if(front == NULL) //if the queue is empty, update the back pointer
back = NULL;
len--;
return;
}
T& getHeadValue() const //return the value of the first item in the queue
{ //without modification to the structure
if (isEmpty()) {
ALOGE("Error can't get head of empty queue");
return *dummy;
}
return front->data;
}
bool isEmpty() const //returns true if no elements are in the queue
{
return (front == NULL);
}
size_t size() const //returns the amount of elements in the queue
{
return len;
}
private:
Node<T> *front;
Node<T> *back;
size_t len;
void clear()
{
while (!isEmpty())
pop();
}
T *dummy;
};
#endif
enum hdmi_mirroring_state {
HDMI_NO_MIRRORING,
HDMI_UI_MIRRORING,
};
struct private_handle_t;
struct qbuf_t {
buffer_handle_t buf;
int idx;
};
enum buf_state {
SUB,
REF,
AVL
};
enum {
// flag to indicate we'll post this buffer
PRIV_USAGE_LOCKED_FOR_POST = 0x80000000,
PRIV_MIN_SWAP_INTERVAL = 0,
PRIV_MAX_SWAP_INTERVAL = 1,
};
struct avail_t {
pthread_mutex_t lock;
pthread_cond_t cond;
bool is_avail;
buf_state state;
};
struct private_module_t {
gralloc_module_t base;
struct private_handle_t* framebuffer;
uint32_t fbFormat;
uint32_t flags;
uint32_t numBuffers;
uint32_t bufferMask;
pthread_mutex_t lock;
buffer_handle_t currentBuffer;
struct fb_var_screeninfo info;
struct fb_fix_screeninfo finfo;
float xdpi;
float ydpi;
float fps;
uint32_t swapInterval;
Queue<struct qbuf_t> disp; // non-empty when buffer is ready for display
int currentIdx;
struct avail_t avail[NUM_FRAMEBUFFERS_MAX];
pthread_mutex_t qlock;
pthread_cond_t qpost;
#if defined(__cplusplus) && defined(HDMI_DUAL_DISPLAY)
int orientation;
int videoOverlay; // VIDEO_OVERLAY - 2D or 3D
int secureVideoOverlay; // VideoOverlay is secure
uint32_t currentOffset;
int enableHDMIOutput; // holds the type of external display
bool trueMirrorSupport;
bool exitHDMIUILoop;
float actionsafeWidthRatio;
float actionsafeHeightRatio;
bool hdmiStateChanged;
hdmi_mirroring_state hdmiMirroringState;
pthread_mutex_t overlayLock;
pthread_cond_t overlayPost;
#endif
};
#endif /* FB_PRIV_H */

File diff suppressed because it is too large Load Diff

56
libgralloc/gpu.cpp Executable file → Normal file
View File

@ -32,34 +32,12 @@ using namespace gralloc;
using android::sp;
gpu_context_t::gpu_context_t(const private_module_t* module,
sp<IAllocController> alloc_ctrl ) :
sp<IAllocController> alloc_ctrl ) :
mAllocCtrl(alloc_ctrl)
{
// Zero out the alloc_device_t
memset(static_cast<alloc_device_t*>(this), 0, sizeof(alloc_device_t));
char property[PROPERTY_VALUE_MAX];
if (property_get("debug.sf.hw", property, NULL) > 0) {
if(atoi(property) == 0) {
//debug.sf.hw = 0
compositionType = CPU_COMPOSITION;
} else { //debug.sf.hw = 1
// Get the composition type
property_get("debug.composition.type", property, NULL);
if (property == NULL) {
compositionType = GPU_COMPOSITION;
} else if ((strncmp(property, "mdp", 3)) == 0) {
compositionType = MDP_COMPOSITION;
} else if ((strncmp(property, "c2d", 3)) == 0) {
compositionType = C2D_COMPOSITION;
} else {
compositionType = GPU_COMPOSITION;
}
}
} else { //debug.sf.hw is not set. Use cpu composition
compositionType = CPU_COMPOSITION;
}
// Initialize the procs
common.tag = HARDWARE_DEVICE_TAG;
common.version = 0;
@ -74,7 +52,7 @@ gpu_context_t::gpu_context_t(const private_module_t* module,
}
int gpu_context_t::gralloc_alloc_framebuffer_locked(size_t size, int usage,
buffer_handle_t* pHandle)
buffer_handle_t* pHandle)
{
private_module_t* m = reinterpret_cast<private_module_t*>(common.module);
@ -136,7 +114,7 @@ int gpu_context_t::gralloc_alloc_framebuffer_locked(size_t size, int usage,
int gpu_context_t::gralloc_alloc_framebuffer(size_t size, int usage,
buffer_handle_t* pHandle)
buffer_handle_t* pHandle)
{
private_module_t* m = reinterpret_cast<private_module_t*>(common.module);
pthread_mutex_lock(&m->lock);
@ -162,7 +140,7 @@ int gpu_context_t::gralloc_alloc_buffer(size_t size, int usage,
else
data.align = getpagesize();
data.pHandle = (unsigned int) pHandle;
err = mAllocCtrl->allocate(data, usage, compositionType);
err = mAllocCtrl->allocate(data, usage, 0);
if (usage & GRALLOC_USAGE_PRIVATE_UNSYNCHRONIZED) {
flags |= private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED;
@ -179,7 +157,8 @@ int gpu_context_t::gralloc_alloc_buffer(size_t size, int usage,
if (err == 0) {
flags |= data.allocType;
private_handle_t* hnd = new private_handle_t(data.fd, size, flags,
bufferType, format, width, height);
bufferType, format, width,
height);
hnd->offset = data.offset;
hnd->base = int(data.base) + data.offset;
@ -217,7 +196,8 @@ void gpu_context_t::getGrallocInformationFromFormat(int inputFormat,
}
int gpu_context_t::alloc_impl(int w, int h, int format, int usage,
buffer_handle_t* pHandle, int* pStride, size_t bufferSize) {
buffer_handle_t* pHandle, int* pStride,
size_t bufferSize) {
if (!pHandle || !pStride)
return -EINVAL;
@ -234,8 +214,9 @@ int gpu_context_t::alloc_impl(int w, int h, int format, int usage,
// All buffers marked as protected or for external
// display need to go to overlay
if ((usage & GRALLOC_USAGE_EXTERNAL_DISP) ||
(usage & GRALLOC_USAGE_PROTECTED)) {
bufferType = BUFFER_TYPE_VIDEO;
(usage & GRALLOC_USAGE_PROTECTED) ||
(usage & GRALLOC_USAGE_PRIVATE_CP_BUFFER)) {
bufferType = BUFFER_TYPE_VIDEO;
}
int err;
if (usage & GRALLOC_USAGE_HW_FB) {
@ -268,12 +249,12 @@ int gpu_context_t::free_impl(private_handle_t const* hnd) {
int index = (hnd->base - m->framebuffer->base) / bufferSize;
m->bufferMask &= ~(1<<index);
} else {
terminateBuffer(&m->base, const_cast<private_handle_t*>(hnd));
sp<IMemAlloc> memalloc = mAllocCtrl->getAllocator(hnd->flags);
int err = memalloc->free_buffer((void*)hnd->base, (size_t) hnd->size,
hnd->offset, hnd->fd);
hnd->offset, hnd->fd);
if(err)
return err;
terminateBuffer(&m->base, const_cast<private_handle_t*>(hnd));
}
// Release the genlock
@ -287,7 +268,8 @@ int gpu_context_t::free_impl(private_handle_t const* hnd) {
}
int gpu_context_t::gralloc_alloc(alloc_device_t* dev, int w, int h, int format,
int usage, buffer_handle_t* pHandle, int* pStride)
int usage, buffer_handle_t* pHandle,
int* pStride)
{
if (!dev) {
return -EINVAL;
@ -295,8 +277,10 @@ int gpu_context_t::gralloc_alloc(alloc_device_t* dev, int w, int h, int format,
gpu_context_t* gpu = reinterpret_cast<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)
int gpu_context_t::gralloc_alloc_size(alloc_device_t* dev, int w, int h,
int format, int usage,
buffer_handle_t* pHandle, int* pStride,
int bufferSize)
{
if (!dev) {
return -EINVAL;
@ -307,7 +291,7 @@ int gpu_context_t::gralloc_alloc_size(alloc_device_t* dev, int w, int h, int for
int gpu_context_t::gralloc_free(alloc_device_t* dev,
buffer_handle_t handle)
buffer_handle_t handle)
{
if (private_handle_t::validate(handle) < 0)
return -EINVAL;

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (c) 2011 Code Aurora Forum. All rights reserved.
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -28,54 +28,51 @@
#include <utils/RefBase.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,
android::sp<IAllocController>alloc_ctrl);
class IAllocController;
class gpu_context_t : public alloc_device_t {
public:
gpu_context_t(const private_module_t* module,
android::sp<IAllocController>alloc_ctrl);
int gralloc_alloc_framebuffer_locked(size_t size, int usage,
buffer_handle_t* pHandle);
int gralloc_alloc_framebuffer_locked(size_t size, int usage,
buffer_handle_t* pHandle);
int gralloc_alloc_framebuffer(size_t size, int usage,
buffer_handle_t* pHandle);
int gralloc_alloc_framebuffer(size_t size, int usage,
buffer_handle_t* pHandle);
int gralloc_alloc_buffer(size_t size, int usage,
buffer_handle_t* pHandle,
int bufferType, int format,
int width, int height);
int gralloc_alloc_buffer(size_t size, int usage,
buffer_handle_t* pHandle,
int bufferType, int format,
int width, int height);
int free_impl(private_handle_t const* hnd);
int free_impl(private_handle_t const* hnd);
int alloc_impl(int w, int h, int format, int usage,
buffer_handle_t* pHandle, int* pStride,
size_t bufferSize = 0);
int alloc_impl(int w, int h, int format, int usage,
buffer_handle_t* pHandle, int* pStride,
size_t bufferSize = 0);
static int gralloc_alloc(alloc_device_t* dev, int w, int h,
int format, int usage,
buffer_handle_t* pHandle,
int* pStride);
static int gralloc_alloc(alloc_device_t* dev, int w, int h,
int format, int usage,
buffer_handle_t* pHandle,
int* pStride);
static int gralloc_free(alloc_device_t* dev, buffer_handle_t handle);
static int gralloc_free(alloc_device_t* dev, buffer_handle_t handle);
static int gralloc_alloc_size(alloc_device_t* dev,
int w, int h, int format,
int usage, buffer_handle_t* pHandle,
int* pStride, int bufferSize);
static int gralloc_alloc_size(alloc_device_t* dev,
int w, int h, int format,
int usage, buffer_handle_t* pHandle,
int* pStride, int bufferSize);
static int gralloc_close(struct hw_device_t *dev);
static int gralloc_close(struct hw_device_t *dev);
int get_composition_type() const { return compositionType; }
private:
android::sp<IAllocController> mAllocCtrl;
int compositionType;
void getGrallocInformationFromFormat(int inputFormat,
int *colorFormat,
int *bufferType);
};
private:
android::sp<IAllocController> mAllocCtrl;
void getGrallocInformationFromFormat(int inputFormat,
int *colorFormat,
int *bufferType);
};
}
#endif // GRALLOC_GPU_H

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (c) 2011 Code Aurora Forum. All rights reserved.
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -51,11 +51,11 @@ inline size_t ALIGN(size_t x, size_t align) {
int mapFrameBufferLocked(struct private_module_t* module);
int terminateBuffer(gralloc_module_t const* module, private_handle_t* hnd);
size_t getBufferSizeAndDimensions(int width, int height, int format,
int& alignedw, int &alignedh);
int& alignedw, int &alignedh);
int decideBufferHandlingMechanism(int format, const char *compositionUsed,
int hasBlitEngine, int *needConversion,
int *useBufferDirectly);
int hasBlitEngine, int *needConversion,
int *useBufferDirectly);
// Allocate buffer from width, height, format into a private_handle_t
// It is the responsibility of the caller to free the buffer
@ -66,10 +66,10 @@ void free_buffer(private_handle_t *hnd);
class Locker {
pthread_mutex_t mutex;
public:
public:
class Autolock {
Locker& locker;
public:
public:
inline Autolock(Locker& locker) : locker(locker) { locker.lock(); }
inline ~Autolock() { locker.unlock(); }
};

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2008, The Android Open Source Project
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -36,71 +36,71 @@ using namespace gralloc;
using android::sp;
int fb_device_open(const hw_module_t* module, const char* name,
hw_device_t** device);
hw_device_t** device);
static int gralloc_device_open(const hw_module_t* module, const char* name,
hw_device_t** device);
hw_device_t** device);
extern int gralloc_lock(gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
void** vaddr);
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
void** vaddr);
extern int gralloc_unlock(gralloc_module_t const* module,
buffer_handle_t handle);
buffer_handle_t handle);
extern int gralloc_register_buffer(gralloc_module_t const* module,
buffer_handle_t handle);
buffer_handle_t handle);
extern int gralloc_unregister_buffer(gralloc_module_t const* module,
buffer_handle_t handle);
buffer_handle_t handle);
extern int gralloc_perform(struct gralloc_module_t const* module,
int operation, ... );
int operation, ... );
// HAL module methods
static struct hw_module_methods_t gralloc_module_methods = {
open: gralloc_device_open
open: gralloc_device_open
};
// HAL module initialize
struct private_module_t HAL_MODULE_INFO_SYM = {
base: {
common: {
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: GRALLOC_HARDWARE_MODULE_ID,
name: "Graphics Memory Allocator Module",
author: "The Android Open Source Project",
methods: &gralloc_module_methods,
dso: 0,
reserved: {0},
},
registerBuffer: gralloc_register_buffer,
unregisterBuffer: gralloc_unregister_buffer,
lock: gralloc_lock,
unlock: gralloc_unlock,
perform: gralloc_perform,
reserved_proc: {0},
},
framebuffer: 0,
fbFormat: 0,
flags: 0,
numBuffers: 0,
bufferMask: 0,
lock: PTHREAD_MUTEX_INITIALIZER,
currentBuffer: 0,
base: {
common: {
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: GRALLOC_HARDWARE_MODULE_ID,
name: "Graphics Memory Allocator Module",
author: "The Android Open Source Project",
methods: &gralloc_module_methods,
dso: 0,
reserved: {0},
},
registerBuffer: gralloc_register_buffer,
unregisterBuffer: gralloc_unregister_buffer,
lock: gralloc_lock,
unlock: gralloc_unlock,
perform: gralloc_perform,
reserved_proc: {0},
},
framebuffer: 0,
fbFormat: 0,
flags: 0,
numBuffers: 0,
bufferMask: 0,
lock: PTHREAD_MUTEX_INITIALIZER,
currentBuffer: 0,
};
// Open Gralloc device
int gralloc_device_open(const hw_module_t* module, const char* name,
hw_device_t** device)
hw_device_t** device)
{
int status = -EINVAL;
if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
const private_module_t* m = reinterpret_cast<const private_module_t*>(
module);
module);
gpu_context_t *dev;
sp<IAllocController> alloc_ctrl = IAllocController::getInstance(true);
dev = new gpu_context_t(m, alloc_ctrl);

View File

@ -28,13 +28,6 @@
#include <cutils/native_handle.h>
#include <linux/fb.h>
#if defined(__cplusplus) && defined(HDMI_DUAL_DISPLAY)
#include "overlayLib.h"
using namespace overlay;
#endif
#include <cutils/log.h>
enum {
@ -87,6 +80,14 @@ enum {
* other EXTERNAL_ONLY buffers are available. Used during suspend.
*/
GRALLOC_USAGE_EXTERNAL_BLOCK = 0x00020000,
/* Use this flag to request content protected buffers. Please note
* that this flag is different from the GRALLOC_USAGE_PROTECTED flag
* which can be used for buffers that are not secured for DRM
* but still need to be protected from screen captures
* 0x00040000 is reserved and these values are subject to change.
*/
GRALLOC_USAGE_PRIVATE_CP_BUFFER = 0x00080000,
};
enum {
@ -96,107 +97,12 @@ enum {
};
enum {
GPU_COMPOSITION,
C2D_COMPOSITION,
MDP_COMPOSITION,
CPU_COMPOSITION,
};
/* numbers of max buffers for page flipping */
#define NUM_FRAMEBUFFERS_MIN 2
#define NUM_FRAMEBUFFERS_MAX 3
/* number of default bufers for page flipping */
#define NUM_DEF_FRAME_BUFFERS 2
#define NO_SURFACEFLINGER_SWAPINTERVAL
#define INTERLACE_MASK 0x80
#define S3D_FORMAT_MASK 0xFF000
#define COLOR_FORMAT(x) (x & 0xFFF) // Max range for colorFormats is 0 - FFF
#define DEVICE_PMEM "/dev/pmem"
#define DEVICE_PMEM_ADSP "/dev/pmem_adsp"
#define DEVICE_PMEM_SMIPOOL "/dev/pmem_smipool"
/*****************************************************************************/
#ifdef __cplusplus
//XXX: Remove framebuffer specific classes and defines to a different header
template <class T>
struct Node
{
T data;
Node<T> *next;
};
template <class T>
class Queue
{
public:
Queue(): front(NULL), back(NULL), len(0) {dummy = new T;}
~Queue()
{
clear();
delete dummy;
}
void push(const T& item) //add an item to the back of the queue
{
if(len != 0) { //if the queue is not empty
back->next = new Node<T>; //create a new node
back = back->next; //set the new node as the back node
back->data = item;
back->next = NULL;
} else {
back = new Node<T>;
back->data = item;
back->next = NULL;
front = back;
}
len++;
}
void pop() //remove the first item from the queue
{
if (isEmpty())
return; //if the queue is empty, no node to dequeue
T item = front->data;
Node<T> *tmp = front;
front = front->next;
delete tmp;
if(front == NULL) //if the queue is empty, update the back pointer
back = NULL;
len--;
return;
}
T& getHeadValue() const //return the value of the first item in the queue
{ //without modification to the structure
if (isEmpty()) {
ALOGE("Error can't get head of empty queue");
return *dummy;
}
return front->data;
}
bool isEmpty() const //returns true if no elements are in the queue
{
return (front == NULL);
}
size_t size() const //returns the amount of elements in the queue
{
return len;
}
private:
Node<T> *front;
Node<T> *back;
size_t len;
void clear()
{
while (!isEmpty())
pop();
}
T *dummy;
};
#endif
enum {
/* OEM specific HAL formats */
HAL_PIXEL_FORMAT_NV12_ENCODEABLE = 0x102,
@ -206,6 +112,8 @@ enum {
HAL_PIXEL_FORMAT_YCrCb_422_SP = 0x10B,
HAL_PIXEL_FORMAT_R_8 = 0x10D,
HAL_PIXEL_FORMAT_RG_88 = 0x10E,
HAL_PIXEL_FORMAT_YCbCr_444_SP = 0x10F,
HAL_PIXEL_FORMAT_YCrCb_444_SP = 0x110,
HAL_PIXEL_FORMAT_INTERLACE = 0x180,
};
@ -224,89 +132,8 @@ enum {
};
enum {
BUFFER_TYPE_UI = 0,
BUFFER_TYPE_VIDEO
};
#if defined(HDMI_DUAL_DISPLAY)
enum hdmi_mirroring_state {
HDMI_NO_MIRRORING,
HDMI_UI_MIRRORING,
HDMI_ORIGINAL_RESOLUTION_MIRRORING
};
#endif
/*****************************************************************************/
struct private_module_t;
struct private_handle_t;
struct PmemAllocator;
struct qbuf_t {
buffer_handle_t buf;
int idx;
};
enum buf_state {
SUB,
REF,
AVL
};
struct avail_t {
pthread_mutex_t lock;
pthread_cond_t cond;
#ifdef __cplusplus
bool is_avail;
buf_state state;
#endif
};
struct private_module_t {
gralloc_module_t base;
struct private_handle_t* framebuffer;
uint32_t fbFormat;
uint32_t flags;
uint32_t numBuffers;
uint32_t bufferMask;
pthread_mutex_t lock;
buffer_handle_t currentBuffer;
struct fb_var_screeninfo info;
struct fb_fix_screeninfo finfo;
float xdpi;
float ydpi;
float fps;
int swapInterval;
#ifdef __cplusplus
Queue<struct qbuf_t> disp; // non-empty when buffer is ready for display
#endif
int currentIdx;
struct avail_t avail[NUM_FRAMEBUFFERS_MAX];
pthread_mutex_t qlock;
pthread_cond_t qpost;
enum {
// flag to indicate we'll post this buffer
PRIV_USAGE_LOCKED_FOR_POST = 0x80000000,
PRIV_MIN_SWAP_INTERVAL = 0,
PRIV_MAX_SWAP_INTERVAL = 1,
};
#if defined(__cplusplus) && defined(HDMI_DUAL_DISPLAY)
Overlay* pobjOverlay;
int orientation;
bool videoOverlay;
uint32_t currentOffset;
int enableHDMIOutput; // holds the type of external display
bool trueMirrorSupport;
bool exitHDMIUILoop;
float actionsafeWidthRatio;
float actionsafeHeightRatio;
bool hdmiStateChanged;
hdmi_mirroring_state hdmiMirroringState;
pthread_mutex_t overlayLock;
pthread_cond_t overlayPost;
#endif
BUFFER_TYPE_UI = 0,
BUFFER_TYPE_VIDEO
};
/*****************************************************************************/
@ -314,87 +141,114 @@ struct private_module_t {
#ifdef __cplusplus
struct private_handle_t : public native_handle {
#else
struct private_handle_t {
native_handle_t nativeHandle;
struct private_handle_t {
native_handle_t nativeHandle;
#endif
enum {
PRIV_FLAGS_FRAMEBUFFER = 0x00000001,
PRIV_FLAGS_USES_PMEM = 0x00000002,
PRIV_FLAGS_USES_PMEM_ADSP = 0x00000004,
PRIV_FLAGS_USES_ION = 0x00000008,
PRIV_FLAGS_USES_ASHMEM = 0x00000010,
PRIV_FLAGS_NEEDS_FLUSH = 0x00000020,
PRIV_FLAGS_DO_NOT_FLUSH = 0x00000040,
PRIV_FLAGS_SW_LOCK = 0x00000080,
PRIV_FLAGS_NONCONTIGUOUS_MEM = 0x00000100,
PRIV_FLAGS_HWC_LOCK = 0x00000200, // Set by HWC when storing the handle
PRIV_FLAGS_SECURE_BUFFER = 0x00000400,
PRIV_FLAGS_UNSYNCHRONIZED = 0x00000800, // For explicit synchronization
PRIV_FLAGS_NOT_MAPPED = 0x00001000, // Not mapped in userspace
PRIV_FLAGS_EXTERNAL_ONLY = 0x00002000, // Display on external only
PRIV_FLAGS_EXTERNAL_BLOCK = 0x00004000, // Display only this buffer on external
};
enum {
PRIV_FLAGS_FRAMEBUFFER = 0x00000001,
PRIV_FLAGS_USES_PMEM = 0x00000002,
PRIV_FLAGS_USES_PMEM_ADSP = 0x00000004,
PRIV_FLAGS_USES_ION = 0x00000008,
PRIV_FLAGS_USES_ASHMEM = 0x00000010,
PRIV_FLAGS_NEEDS_FLUSH = 0x00000020,
PRIV_FLAGS_DO_NOT_FLUSH = 0x00000040,
PRIV_FLAGS_SW_LOCK = 0x00000080,
PRIV_FLAGS_NONCONTIGUOUS_MEM = 0x00000100,
// Set by HWC when storing the handle
PRIV_FLAGS_HWC_LOCK = 0x00000200,
PRIV_FLAGS_SECURE_BUFFER = 0x00000400,
// For explicit synchronization
PRIV_FLAGS_UNSYNCHRONIZED = 0x00000800,
// Not mapped in userspace
PRIV_FLAGS_NOT_MAPPED = 0x00001000,
// Display on external only
PRIV_FLAGS_EXTERNAL_ONLY = 0x00002000,
// Display only this buffer on external
PRIV_FLAGS_EXTERNAL_BLOCK = 0x00004000,
};
// file-descriptors
int fd;
int genlockHandle; // genlock handle to be dup'd by the binder
// ints
int magic;
int flags;
int size;
int offset;
int bufferType;
// FIXME: the attributes below should be out-of-line
int base;
int gpuaddr; // The gpu address mapped into the mmu. If using ashmem, set to 0 They don't care
int pid;
int format;
int width;
int height;
int genlockPrivFd; // local fd of the genlock device.
// file-descriptors
int fd;
// genlock handle to be dup'd by the binder
int genlockHandle;
// ints
int magic;
int flags;
int size;
int offset;
int bufferType;
int base;
// The gpu address mapped into the mmu.
// If using ashmem, set to 0, they don't care
int gpuaddr;
int pid;
int format;
int width;
int height;
// local fd of the genlock device.
int genlockPrivFd;
#ifdef __cplusplus
static const int sNumInts = 12;
static const int sNumFds = 2;
static const int sMagic = 'gmsm';
static const int sNumInts = 12;
static const int sNumFds = 2;
static const int sMagic = 'gmsm';
private_handle_t(int fd, int size, int flags, int bufferType, int format, int width, int height) :
fd(fd), genlockHandle(-1), magic(sMagic), flags(flags), size(size), offset(0),
bufferType(bufferType), base(0), gpuaddr(0), pid(getpid()), format(format),
width(width), height(height), genlockPrivFd(-1)
{
version = sizeof(native_handle);
numInts = sNumInts;
numFds = sNumFds;
}
~private_handle_t() {
magic = 0;
}
private_handle_t(int fd, int size, int flags, int bufferType,
int format,int width, int height) :
fd(fd), genlockHandle(-1), magic(sMagic),
flags(flags), size(size), offset(0),
bufferType(bufferType), base(0), gpuaddr(0),
pid(getpid()), format(format),
width(width), height(height), genlockPrivFd(-1)
{
version = sizeof(native_handle);
numInts = sNumInts;
numFds = sNumFds;
}
~private_handle_t() {
magic = 0;
}
bool usesPhysicallyContiguousMemory() {
return (flags & PRIV_FLAGS_USES_PMEM) != 0;
}
bool usesPhysicallyContiguousMemory() {
return (flags & PRIV_FLAGS_USES_PMEM) != 0;
}
static int validate(const native_handle* h) {
const private_handle_t* hnd = (const private_handle_t*)h;
if (!h || h->version != sizeof(native_handle) ||
static int validate(const native_handle* h) {
const private_handle_t* hnd = (const private_handle_t*)h;
if (!h || h->version != sizeof(native_handle) ||
h->numInts != sNumInts || h->numFds != sNumFds ||
hnd->magic != sMagic)
{
ALOGE("invalid gralloc handle (at %p)", h);
return -EINVAL;
{
ALOGD("Invalid gralloc handle (at %p): "
"ver(%d/%d) ints(%d/%d) fds(%d/%d) magic(%c%c%c%c/%c%c%c%c)",
h,
h ? h->version : -1, sizeof(native_handle),
h ? h->numInts : -1, sNumInts,
h ? h->numFds : -1, sNumFds,
hnd ? (((hnd->magic >> 24) & 0xFF)?
((hnd->magic >> 24) & 0xFF) : '-') : '?',
hnd ? (((hnd->magic >> 16) & 0xFF)?
((hnd->magic >> 16) & 0xFF) : '-') : '?',
hnd ? (((hnd->magic >> 8) & 0xFF)?
((hnd->magic >> 8) & 0xFF) : '-') : '?',
hnd ? (((hnd->magic >> 0) & 0xFF)?
((hnd->magic >> 0) & 0xFF) : '-') : '?',
(sMagic >> 24) & 0xFF,
(sMagic >> 16) & 0xFF,
(sMagic >> 8) & 0xFF,
(sMagic >> 0) & 0xFF);
return -EINVAL;
}
return 0;
}
return 0;
}
static private_handle_t* dynamicCast(const native_handle* in) {
if (validate(in) == 0) {
return (private_handle_t*) in;
static private_handle_t* dynamicCast(const native_handle* in) {
if (validate(in) == 0) {
return (private_handle_t*) in;
}
return NULL;
}
return NULL;
}
#endif
};
};
#endif /* GRALLOC_PRIV_H_ */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -48,7 +48,7 @@ int IonAlloc::open_device()
if(mIonFd < 0 ) {
ALOGE("%s: Failed to open ion device - %s",
__FUNCTION__, strerror(errno));
__FUNCTION__, strerror(errno));
mIonFd = FD_INIT;
return -errno;
}
@ -64,6 +64,7 @@ void IonAlloc::close_device()
int IonAlloc::alloc_buffer(alloc_data& data)
{
Locker::Autolock _l(mLock);
int err = 0;
int ionSyncFd = FD_INIT;
int iFd = FD_INIT;
@ -84,12 +85,11 @@ int IonAlloc::alloc_buffer(alloc_data& data)
if(data.uncached) {
// Use the sync FD to alloc and map
// when we need uncached memory
// FIX: ОDSYNC defined to open uncached - add that in kernel
//ionSyncFd = open(ION_DEVICE, O_RDONLY|O_DSYNC);
ionSyncFd = open(ION_DEVICE, O_RDONLY);
// XXX: Change O_SYNC to O_DSYNC when available in bionic
ionSyncFd = open(ION_DEVICE, O_RDONLY|O_SYNC);
if(ionSyncFd < 0) {
ALOGE("%s: Failed to open ion device - %s",
__FUNCTION__, strerror(errno));
__FUNCTION__, strerror(errno));
return -errno;
}
iFd = ionSyncFd;
@ -111,7 +111,7 @@ int IonAlloc::alloc_buffer(alloc_data& data)
if(ioctl(iFd, ION_IOC_MAP, &fd_data)) {
err = -errno;
ALOGE("%s: ION_IOC_MAP failed with error - %s",
__FUNCTION__, strerror(errno));
__FUNCTION__, strerror(errno));
ioctl(mIonFd, ION_IOC_FREE, &handle_data);
if(ionSyncFd >= 0)
close(ionSyncFd);
@ -119,15 +119,15 @@ int IonAlloc::alloc_buffer(alloc_data& data)
return err;
}
//if(!(data.flags & ION_SECURE) &&
if(!(data.allocType & private_handle_t::PRIV_FLAGS_NOT_MAPPED)) {
if(!(data.flags & ION_SECURE) &&
!(data.allocType & private_handle_t::PRIV_FLAGS_NOT_MAPPED)) {
base = mmap(0, ionAllocData.len, PROT_READ|PROT_WRITE,
MAP_SHARED, fd_data.fd, 0);
MAP_SHARED, fd_data.fd, 0);
if(base == MAP_FAILED) {
err = -errno;
ALOGE("%s: Failed to map the allocated memory: %s",
__FUNCTION__, strerror(errno));
__FUNCTION__, strerror(errno));
ioctl(mIonFd, ION_IOC_FREE, &handle_data);
ionSyncFd = FD_INIT;
return err;
@ -146,15 +146,16 @@ int IonAlloc::alloc_buffer(alloc_data& data)
data.fd = fd_data.fd;
ioctl(mIonFd, ION_IOC_FREE, &handle_data);
ALOGD("ion: Allocated buffer base:%p size:%d fd:%d",
data.base, ionAllocData.len, data.fd);
data.base, ionAllocData.len, data.fd);
return 0;
}
int IonAlloc::free_buffer(void* base, size_t size, int offset, int fd)
{
Locker::Autolock _l(mLock);
ALOGD("ion: Freeing buffer base:%p size:%d fd:%d",
base, size, fd);
base, size, fd);
int err = 0;
err = open_device();
if (err)
@ -177,15 +178,15 @@ int IonAlloc::map_buffer(void **pBase, size_t size, int offset, int fd)
return err;
base = mmap(0, size, PROT_READ| PROT_WRITE,
MAP_SHARED, fd, 0);
MAP_SHARED, fd, 0);
*pBase = base;
if(base == MAP_FAILED) {
err = -errno;
ALOGD("ion: Failed to map memory in the client: %s",
strerror(errno));
strerror(errno));
} else {
ALOGD("ion: Mapped buffer base:%p size:%d offset:%d fd:%d",
base, size, offset, fd);
base, size, offset, fd);
}
return err;
}
@ -197,7 +198,7 @@ int IonAlloc::unmap_buffer(void *base, size_t size, int offset)
if(munmap(base, size)) {
err = -errno;
ALOGE("ion: Failed to unmap memory at %p : %s",
base, strerror(errno));
base, strerror(errno));
}
return err;
@ -218,7 +219,7 @@ int IonAlloc::clean_buffer(void *base, size_t size, int offset, int fd)
if (ioctl(mIonFd, ION_IOC_IMPORT, &fd_data)) {
err = -errno;
ALOGE("%s: ION_IOC_IMPORT failed with error - %s",
__FUNCTION__, strerror(errno));
__FUNCTION__, strerror(errno));
return err;
}
@ -230,7 +231,7 @@ int IonAlloc::clean_buffer(void *base, size_t size, int offset, int fd)
if(ioctl(mIonFd, ION_IOC_CLEAN_INV_CACHES, &flush_data)) {
err = -errno;
ALOGE("%s: ION_IOC_CLEAN_INV_CACHES failed with error - %s",
__FUNCTION__, strerror(errno));
__FUNCTION__, strerror(errno));
ioctl(mIonFd, ION_IOC_FREE, &handle_data);
return err;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -31,39 +31,44 @@
#define GRALLOC_IONALLOC_H
#include "memalloc.h"
#include "gr.h"
//#include <linux/ion.h>
//XXX: Move to bionic
#include "ion_msm.h"
namespace gralloc {
class IonAlloc : public IMemAlloc {
class IonAlloc : public IMemAlloc {
public:
virtual int alloc_buffer(alloc_data& data);
public:
virtual int alloc_buffer(alloc_data& data);
virtual int free_buffer(void *base, size_t size,
int offset, int fd);
virtual int free_buffer(void *base, size_t size,
int offset, int fd);
virtual int map_buffer(void **pBase, size_t size,
int offset, int fd);
virtual int map_buffer(void **pBase, size_t size,
int offset, int fd);
virtual int unmap_buffer(void *base, size_t size,
int offset);
virtual int unmap_buffer(void *base, size_t size,
int offset);
virtual int clean_buffer(void*base, size_t size,
int offset, int fd);
virtual int clean_buffer(void*base, size_t size,
int offset, int fd);
IonAlloc() { mIonFd = FD_INIT; }
IonAlloc() { mIonFd = FD_INIT; }
~IonAlloc() { close_device(); }
~IonAlloc() { close_device(); }
private:
int mIonFd;
private:
int mIonFd;
int open_device();
int open_device();
void close_device();
void close_device();
};
mutable Locker mLock;
};
}

53
libgralloc/mapper.cpp Executable file → Normal file
View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (c) 2011 Code Aurora Forum. All rights reserved.
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -58,8 +58,8 @@ static sp<IMemAlloc> getAllocator(int flags)
}
static int gralloc_map(gralloc_module_t const* module,
buffer_handle_t handle,
void** vaddr)
buffer_handle_t handle,
void** vaddr)
{
private_handle_t* hnd = (private_handle_t*)handle;
void *mappedAddress;
@ -68,22 +68,22 @@ static int gralloc_map(gralloc_module_t const* module,
size_t size = hnd->size;
sp<IMemAlloc> memalloc = getAllocator(hnd->flags) ;
int err = memalloc->map_buffer(&mappedAddress, size,
hnd->offset, hnd->fd);
hnd->offset, hnd->fd);
if(err) {
ALOGE("Could not mmap handle %p, fd=%d (%s)",
handle, hnd->fd, strerror(errno));
handle, hnd->fd, strerror(errno));
hnd->base = 0;
return -errno;
}
if (mappedAddress == MAP_FAILED) {
ALOGE("Could not mmap handle %p, fd=%d (%s)",
handle, hnd->fd, strerror(errno));
handle, hnd->fd, strerror(errno));
hnd->base = 0;
return -errno;
}
hnd->base = intptr_t(mappedAddress) + hnd->offset;
//ALOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p",
//LOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p",
// hnd->fd, hnd->offset, hnd->size, mappedAddress);
}
*vaddr = (void*)hnd->base;
@ -91,7 +91,7 @@ static int gralloc_map(gralloc_module_t const* module,
}
static int gralloc_unmap(gralloc_module_t const* module,
buffer_handle_t handle)
buffer_handle_t handle)
{
private_handle_t* hnd = (private_handle_t*)handle;
if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
@ -116,7 +116,7 @@ static pthread_mutex_t sMapLock = PTHREAD_MUTEX_INITIALIZER;
/*****************************************************************************/
int gralloc_register_buffer(gralloc_module_t const* module,
buffer_handle_t handle)
buffer_handle_t handle)
{
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
@ -164,7 +164,7 @@ int gralloc_register_buffer(gralloc_module_t const* module,
}
int gralloc_unregister_buffer(gralloc_module_t const* module,
buffer_handle_t handle)
buffer_handle_t handle)
{
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
@ -195,7 +195,7 @@ int gralloc_unregister_buffer(gralloc_module_t const* module,
}
int terminateBuffer(gralloc_module_t const* module,
private_handle_t* hnd)
private_handle_t* hnd)
{
/*
* If the buffer has been mapped during a lock operation, it's time
@ -215,7 +215,8 @@ int terminateBuffer(gralloc_module_t const* module,
gralloc_unmap(module, hnd);
}
} else {
ALOGE("terminateBuffer: unmapping a non pmem/ashmem buffer flags = 0x%x", hnd->flags);
ALOGE("terminateBuffer: unmapping a non pmem/ashmem buffer flags = 0x%x",
hnd->flags);
gralloc_unmap(module, hnd);
}
}
@ -224,9 +225,9 @@ int terminateBuffer(gralloc_module_t const* module,
}
int gralloc_lock(gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
void** vaddr)
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
void** vaddr)
{
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
@ -254,10 +255,10 @@ int gralloc_lock(gralloc_module_t const* module,
int timeout = GENLOCK_MAX_TIMEOUT;
if (GENLOCK_NO_ERROR != genlock_lock_buffer((native_handle_t *)handle,
(genlock_lock_type)lockType,
timeout)) {
(genlock_lock_type)lockType,
timeout)) {
ALOGE("%s: genlock_lock_buffer (lockType=0x%x) failed", __FUNCTION__,
lockType);
lockType);
return -EINVAL;
} else {
// Mark this buffer as locked for SW read/write operation.
@ -274,7 +275,7 @@ int gralloc_lock(gralloc_module_t const* module,
}
int gralloc_unlock(gralloc_module_t const* module,
buffer_handle_t handle)
buffer_handle_t handle)
{
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
@ -285,9 +286,9 @@ int gralloc_unlock(gralloc_module_t const* module,
int err;
sp<IMemAlloc> memalloc = getAllocator(hnd->flags) ;
err = memalloc->clean_buffer((void*)hnd->base,
hnd->size, hnd->offset, hnd->fd);
hnd->size, hnd->offset, hnd->fd);
ALOGE_IF(err < 0, "cannot flush handle %p (offs=%x len=%x, flags = 0x%x) err=%s\n",
hnd, hnd->offset, hnd->size, hnd->flags, strerror(errno));
hnd, hnd->offset, hnd->size, hnd->flags, strerror(errno));
hnd->flags &= ~private_handle_t::PRIV_FLAGS_NEEDS_FLUSH;
}
@ -305,7 +306,7 @@ int gralloc_unlock(gralloc_module_t const* module,
/*****************************************************************************/
int gralloc_perform(struct gralloc_module_t const* module,
int operation, ... )
int operation, ... )
{
int res = -EINVAL;
va_list args;
@ -324,12 +325,12 @@ int gralloc_perform(struct gralloc_module_t const* module,
native_handle_t** handle = va_arg(args, native_handle_t**);
int memoryFlags = va_arg(args, int);
private_handle_t* hnd = (private_handle_t*)native_handle_create(
private_handle_t::sNumFds, private_handle_t::sNumInts);
private_handle_t::sNumFds, private_handle_t::sNumInts);
hnd->magic = private_handle_t::sMagic;
hnd->fd = fd;
unsigned int contigFlags = GRALLOC_USAGE_PRIVATE_ADSP_HEAP |
GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP |
GRALLOC_USAGE_PRIVATE_SMI_HEAP;
GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP |
GRALLOC_USAGE_PRIVATE_SMI_HEAP;
if (memoryFlags & contigFlags) {
// check if the buffer is a pmem buffer
@ -338,7 +339,7 @@ int gralloc_perform(struct gralloc_module_t const* module,
hnd->flags = private_handle_t::PRIV_FLAGS_USES_ION;
else
hnd->flags = private_handle_t::PRIV_FLAGS_USES_PMEM |
private_handle_t::PRIV_FLAGS_DO_NOT_FLUSH;
private_handle_t::PRIV_FLAGS_DO_NOT_FLUSH;
} else {
if (memoryFlags & GRALLOC_USAGE_PRIVATE_ION)
hnd->flags = private_handle_t::PRIV_FLAGS_USES_ION;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -35,50 +35,50 @@
namespace gralloc {
struct alloc_data {
void *base;
int fd;
int offset;
size_t size;
size_t align;
unsigned int pHandle;
bool uncached;
unsigned int flags;
int allocType;
struct alloc_data {
void *base;
int fd;
int offset;
size_t size;
size_t align;
unsigned int pHandle;
bool uncached;
unsigned int flags;
int allocType;
};
class IMemAlloc : public android::RefBase {
public:
// Allocate buffer - fill in the alloc_data
// structure and pass it in. Mapped address
// and fd are returned in the alloc_data struct
virtual int alloc_buffer(alloc_data& data) = 0;
// Free buffer
virtual int free_buffer(void *base, size_t size,
int offset, int fd) = 0;
// Map buffer
virtual int map_buffer(void **pBase, size_t size,
int offset, int fd) = 0;
// Unmap buffer
virtual int unmap_buffer(void *base, size_t size,
int offset) = 0;
// Clean and invalidate
virtual int clean_buffer(void *base, size_t size,
int offset, int fd) = 0;
// Destructor
virtual ~IMemAlloc() {};
enum {
FD_INIT = -1,
};
class IMemAlloc : public android::RefBase {
public:
// Allocate buffer - fill in the alloc_data
// structure and pass it in. Mapped address
// and fd are returned in the alloc_data struct
virtual int alloc_buffer(alloc_data& data) = 0;
// Free buffer
virtual int free_buffer(void *base, size_t size,
int offset, int fd) = 0;
// Map buffer
virtual int map_buffer(void **pBase, size_t size,
int offset, int fd) = 0;
// Unmap buffer
virtual int unmap_buffer(void *base, size_t size,
int offset) = 0;
// Clean and invalidate
virtual int clean_buffer(void *base, size_t size,
int offset, int fd) = 0;
// Destructor
virtual ~IMemAlloc() {};
enum {
FD_INIT = -1,
};
};
};
} // end gralloc namespace
#endif // GRALLOC_MEMALLOC_H

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2009 The Android Open Source Project
* Copyright (c) 2011 Code Aurora Forum. All rights reserved.
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -24,12 +24,12 @@
const int SimpleBestFitAllocator::kMemoryAlign = 32;
SimpleBestFitAllocator::SimpleBestFitAllocator()
: mHeapSize(0)
: mHeapSize(0)
{
}
SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size)
: mHeapSize(0)
: mHeapSize(0)
{
setSize(size);
}
@ -113,13 +113,13 @@ ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags)
mList.insertBefore(free_chunk, split);
}
LOGE_IF(((free_chunk->start*kMemoryAlign)&(pagesize-1)),
"page is not aligned!!!");
ALOGE_IF(((free_chunk->start*kMemoryAlign)&(pagesize-1)),
"page is not aligned!!!");
const ssize_t tail_free = free_size - (size+extra);
if (tail_free > 0) {
chunk_t* split = new chunk_t(
free_chunk->start + free_chunk->size, tail_free);
free_chunk->start + free_chunk->size, tail_free);
mList.insertAfter(free_chunk, split);
}
}
@ -128,33 +128,33 @@ ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags)
// we are out of PMEM. Print pmem stats
// check if there is any leak or fragmentation
LOGD (" Out of PMEM. Dumping PMEM stats for debugging");
LOGD (" ------------- PRINT PMEM STATS --------------");
ALOGD (" Out of PMEM. Dumping PMEM stats for debugging");
ALOGD (" ------------- PRINT PMEM STATS --------------");
cur = mList.head();
static uint32_t node_count;
static uint64_t allocated, free_space;
while (cur) {
LOGD (" Node %d -> Start Address : %u Size %u Free info %d",\
node_count++, cur->start, cur->size, cur->free);
ALOGD (" Node %d -> Start Address : %u Size %u Free info %d",\
node_count++, cur->start, cur->size, cur->free);
// if cur-> free is 1 , the node is free
// calculate the total allocated and total free stats also
// if cur-> free is 1 , the node is free
// calculate the total allocated and total free stats also
if (cur->free)
free_space += cur->size;
else
allocated += cur->size;
// read next node
cur = cur->next;
if (cur->free)
free_space += cur->size;
else
allocated += cur->size;
// read next node
cur = cur->next;
}
LOGD (" Total Allocated: %l Total Free: %l", allocated, free_space );
ALOGD (" Total Allocated: %l Total Free: %l", allocated, free_space );
node_count = 0;
allocated = 0;
free_space = 0;
LOGD ("----------------------------------------------");
ALOGD ("----------------------------------------------");
return -ENOMEM;
}
@ -164,9 +164,9 @@ SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start)
chunk_t* cur = mList.head();
while (cur) {
if (cur->start == start) {
LOG_FATAL_IF(cur->free,
"block at offset 0x%08lX of size 0x%08lX already freed",
cur->start*kMemoryAlign, cur->size*kMemoryAlign);
ALOG_FATAL_IF(cur->free,
"block at offset 0x%08lX of size 0x%08lX already freed",
cur->start*kMemoryAlign, cur->size*kMemoryAlign);
// merge freed blocks together
chunk_t* freed = cur;
@ -183,9 +183,9 @@ SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start)
cur = n;
} while (cur && cur->free);
LOG_FATAL_IF(!freed->free,
"freed block at offset 0x%08lX of size 0x%08lX is not free!",
freed->start * kMemoryAlign, freed->size * kMemoryAlign);
ALOG_FATAL_IF(!freed->free,
"freed block at offset 0x%08lX of size 0x%08lX is not free!",
freed->start * kMemoryAlign, freed->size * kMemoryAlign);
return freed;
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2009 The Android Open Source Project
* Copyright (c) 2011 Code Aurora Forum. All rights reserved.
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -36,8 +36,8 @@ class LinkedList
NODE* mFirst;
NODE* mLast;
public:
LinkedList() : mFirst(0), mLast(0) { }
public:
LinkedList() : mFirst(0), mLast(0) { }
bool isEmpty() const { return mFirst == 0; }
NODE const* head() const { return mFirst; }
NODE* head() { return mFirst; }
@ -53,11 +53,11 @@ public:
}
void insertBefore(NODE* node, NODE* newNode) {
newNode->prev = node->prev;
newNode->next = node;
if (node->prev == 0) mFirst = newNode;
else node->prev->next = newNode;
node->prev = newNode;
newNode->prev = node->prev;
newNode->next = node;
if (node->prev == 0) mFirst = newNode;
else node->prev->next = newNode;
node->prev = newNode;
}
void insertHead(NODE* newNode) {
@ -94,36 +94,36 @@ public:
class SimpleBestFitAllocator : public gralloc::PmemUserspaceAlloc::Allocator
{
public:
public:
SimpleBestFitAllocator();
SimpleBestFitAllocator(size_t size);
virtual ~SimpleBestFitAllocator();
SimpleBestFitAllocator();
SimpleBestFitAllocator(size_t size);
virtual ~SimpleBestFitAllocator();
virtual ssize_t setSize(size_t size);
virtual ssize_t setSize(size_t size);
virtual ssize_t allocate(size_t size, uint32_t flags = 0);
virtual ssize_t deallocate(size_t offset);
virtual size_t size() const;
virtual ssize_t allocate(size_t size, uint32_t flags = 0);
virtual ssize_t deallocate(size_t offset);
virtual size_t size() const;
private:
struct chunk_t {
chunk_t(size_t start, size_t size)
: start(start), size(size), free(1), prev(0), next(0) {
}
size_t start;
size_t size : 28;
int free : 4;
mutable chunk_t* prev;
mutable chunk_t* next;
};
private:
struct chunk_t {
chunk_t(size_t start, size_t size)
: start(start), size(size), free(1), prev(0), next(0) {
}
size_t start;
size_t size : 28;
int free : 4;
mutable chunk_t* prev;
mutable chunk_t* next;
};
ssize_t alloc(size_t size, uint32_t flags);
chunk_t* dealloc(size_t start);
ssize_t alloc(size_t size, uint32_t flags);
chunk_t* dealloc(size_t start);
static const int kMemoryAlign;
mutable Locker mLock;
LinkedList<chunk_t> mList;
size_t mHeapSize;
static const int kMemoryAlign;
mutable Locker mLock;
LinkedList<chunk_t> mList;
size_t mHeapSize;
};
#endif /* GRALLOC_ALLOCATOR_H_ */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -126,17 +126,17 @@ int PmemUserspaceAlloc::init_pmem_area_locked()
ALOGD("%s: Total pmem size: %d", __FUNCTION__, size);
if (err < 0) {
ALOGE("%s: PMEM_GET_TOTAL_SIZE failed (%d), limp mode", mPmemDev,
err);
err);
size = 8<<20; // 8 MiB
}
mAllocator->setSize(size);
void* base = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd,
0);
0);
if (base == MAP_FAILED) {
err = -errno;
ALOGE("%s: Failed to map pmem master fd: %s", mPmemDev,
strerror(errno));
strerror(errno));
base = 0;
close(fd);
fd = -1;
@ -147,7 +147,7 @@ int PmemUserspaceAlloc::init_pmem_area_locked()
} else {
err = -errno;
ALOGE("%s: Failed to open pmem device: %s", mPmemDev,
strerror(errno));
strerror(errno));
}
return err;
}
@ -203,13 +203,13 @@ int PmemUserspaceAlloc::alloc_buffer(alloc_data& data)
if (err < 0) {
ALOGE("%s: Failed to initialize pmem sub-heap: %d", mPmemDev,
err);
err);
close(fd);
mAllocator->deallocate(offset);
fd = -1;
} else {
ALOGD("%s: Allocated buffer base:%p size:%d offset:%d fd:%d",
mPmemDev, base, size, offset, fd);
mPmemDev, base, size, offset, fd);
memset((char*)base + offset, 0, size);
//Clean cache before flushing to ensure pmem is properly flushed
err = clean_buffer((void*)((intptr_t) base + offset), size, offset, fd);
@ -230,12 +230,12 @@ int PmemUserspaceAlloc::alloc_buffer(alloc_data& data)
int PmemUserspaceAlloc::free_buffer(void* base, size_t size, int offset, int fd)
{
ALOGD("%s: Freeing buffer base:%p size:%d offset:%d fd:%d",
mPmemDev, base, size, offset, fd);
mPmemDev, base, size, offset, fd);
int err = 0;
if (fd >= 0) {
int err = unmapSubRegion(fd, offset, size);
ALOGE_IF(err<0, "PMEM_UNMAP failed (%s), fd=%d, sub.offset=%u, "
"sub.size=%u", strerror(errno), fd, offset, size);
"sub.size=%u", strerror(errno), fd, offset, size);
if (err == 0) {
// we can't deallocate the memory in case of UNMAP failure
// because it would give that process access to someone else's
@ -252,15 +252,15 @@ int PmemUserspaceAlloc::map_buffer(void **pBase, size_t size, int offset, int fd
int err = 0;
size += offset;
void *base = mmap(0, size, PROT_READ| PROT_WRITE,
MAP_SHARED, fd, 0);
MAP_SHARED, fd, 0);
*pBase = base;
if(base == MAP_FAILED) {
err = -errno;
ALOGE("%s: Failed to map buffer size:%d offset:%d fd:%d Error: %s",
mPmemDev, size, offset, fd, strerror(errno));
mPmemDev, size, offset, fd, strerror(errno));
} else {
ALOGD("%s: Mapped buffer base:%p size:%d offset:%d fd:%d",
mPmemDev, base, size, offset, fd);
mPmemDev, base, size, offset, fd);
}
return err;
@ -273,16 +273,15 @@ int PmemUserspaceAlloc::unmap_buffer(void *base, size_t size, int offset)
base = (void*)(intptr_t(base) - offset);
size += offset;
ALOGD("%s: Unmapping buffer base:%p size:%d offset:%d",
mPmemDev , base, size, offset);
mPmemDev , base, size, offset);
if (munmap(base, size) < 0) {
err = -errno;
ALOGE("%s: Failed to unmap memory at %p :%s",
mPmemDev, base, strerror(errno));
mPmemDev, base, strerror(errno));
}
return err;
return err;
}
int PmemUserspaceAlloc::clean_buffer(void *base, size_t size, int offset, int fd)
@ -327,7 +326,7 @@ int PmemKernelAlloc::alloc_buffer(alloc_data& data)
if (base == MAP_FAILED) {
err = -errno;
ALOGE("%s: failed to map pmem fd: %s", mPmemDev,
strerror(errno));
strerror(errno));
close(fd);
return err;
}
@ -337,7 +336,7 @@ int PmemKernelAlloc::alloc_buffer(alloc_data& data)
data.offset = 0;
data.fd = fd;
ALOGD("%s: Allocated buffer base:%p size:%d fd:%d",
mPmemDev, base, size, fd);
mPmemDev, base, size, fd);
return 0;
}
@ -345,7 +344,7 @@ int PmemKernelAlloc::alloc_buffer(alloc_data& data)
int PmemKernelAlloc::free_buffer(void* base, size_t size, int offset, int fd)
{
ALOGD("%s: Freeing buffer base:%p size:%d fd:%d",
mPmemDev, base, size, fd);
mPmemDev, base, size, fd);
int err = unmap_buffer(base, size, offset);
close(fd);
@ -356,15 +355,15 @@ int PmemKernelAlloc::map_buffer(void **pBase, size_t size, int offset, int fd)
{
int err = 0;
void *base = mmap(0, size, PROT_READ| PROT_WRITE,
MAP_SHARED, fd, 0);
MAP_SHARED, fd, 0);
*pBase = base;
if(base == MAP_FAILED) {
err = -errno;
ALOGE("%s: Failed to map memory in the client: %s",
mPmemDev, strerror(errno));
mPmemDev, strerror(errno));
} else {
ALOGD("%s: Mapped buffer base:%p size:%d, fd:%d",
mPmemDev, base, size, fd);
mPmemDev, base, size, fd);
}
return err;
@ -376,7 +375,7 @@ int PmemKernelAlloc::unmap_buffer(void *base, size_t size, int offset)
if (munmap(base, size)) {
err = -errno;
ALOGW("%s: Error unmapping memory at %p: %s",
mPmemDev, base, strerror(err));
mPmemDev, base, strerror(err));
}
return err;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@ -35,72 +35,72 @@
#include "memalloc.h"
namespace gralloc {
class PmemUserspaceAlloc : public IMemAlloc {
class PmemUserspaceAlloc : public IMemAlloc {
public:
class Allocator: public android::RefBase {
public:
class Allocator: public android::RefBase {
public:
virtual ~Allocator() {};
virtual ssize_t setSize(size_t size) = 0;
virtual size_t size() const = 0;
virtual ssize_t allocate(size_t size, uint32_t flags = 0) = 0;
virtual ssize_t deallocate(size_t offset) = 0;
};
virtual int alloc_buffer(alloc_data& data);
virtual int free_buffer(void *base, size_t size,
int offset, int fd);
virtual int map_buffer(void **pBase, size_t size,
int offset, int fd);
virtual int unmap_buffer(void *base, size_t size,
int offset);
virtual int clean_buffer(void*base, size_t size,
int offset, int fd);
PmemUserspaceAlloc();
~PmemUserspaceAlloc();
private:
int mMasterFd;
void* mMasterBase;
const char* mPmemDev;
android::sp<Allocator> mAllocator;
pthread_mutex_t mLock;
int init_pmem_area();
int init_pmem_area_locked();
virtual ~Allocator() {};
virtual ssize_t setSize(size_t size) = 0;
virtual size_t size() const = 0;
virtual ssize_t allocate(size_t size, uint32_t flags = 0) = 0;
virtual ssize_t deallocate(size_t offset) = 0;
};
class PmemKernelAlloc : public IMemAlloc {
virtual int alloc_buffer(alloc_data& data);
public:
virtual int alloc_buffer(alloc_data& data);
virtual int free_buffer(void *base, size_t size,
int offset, int fd);
virtual int free_buffer(void *base, size_t size,
int offset, int fd);
virtual int map_buffer(void **pBase, size_t size,
int offset, int fd);
virtual int map_buffer(void **pBase, size_t size,
int offset, int fd);
virtual int unmap_buffer(void *base, size_t size,
int offset);
virtual int unmap_buffer(void *base, size_t size,
int offset);
virtual int clean_buffer(void*base, size_t size,
int offset, int fd);
virtual int clean_buffer(void*base, size_t size,
int offset, int fd);
PmemUserspaceAlloc();
PmemKernelAlloc(const char* device);
~PmemUserspaceAlloc();
~PmemKernelAlloc();
private:
const char* mPmemDev;
private:
int mMasterFd;
void* mMasterBase;
const char* mPmemDev;
android::sp<Allocator> mAllocator;
pthread_mutex_t mLock;
int init_pmem_area();
int init_pmem_area_locked();
};
class PmemKernelAlloc : public IMemAlloc {
public:
virtual int alloc_buffer(alloc_data& data);
virtual int free_buffer(void *base, size_t size,
int offset, int fd);
virtual int map_buffer(void **pBase, size_t size,
int offset, int fd);
virtual int unmap_buffer(void *base, size_t size,
int offset);
virtual int clean_buffer(void*base, size_t size,
int offset, int fd);
PmemKernelAlloc(const char* device);
~PmemKernelAlloc();
private:
const char* mPmemDev;
};
};
}
#endif /* GRALLOC_PMEMALLOC_H */

View File

@ -1,39 +1,18 @@
LOCAL_PATH := $(call my-dir)
# HAL module implemenation, not prelinked and stored in
# hw/<OVERLAY_HARDWARE_MODULE_ID>.<ro.product.board>.so
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog libcutils libEGL libhardware libutils liboverlay
LOCAL_SHARED_LIBRARIES += libgenlock libQcomUI libmemalloc
LOCAL_SRC_FILES := \
hwcomposer.cpp \
external_display_only.h
LOCAL_SHARED_LIBRARIES := liblog libcutils libhardware libutils
LOCAL_SHARED_LIBRARIES += libEGL liboverlay libgenlock
LOCAL_SRC_FILES := hwc.cpp \
hwc_overlay.cpp \
hwc_utils.cpp
LOCAL_MODULE := hwcomposer.$(TARGET_BOARD_PLATFORM)
LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).hwcomposer\" -DDEBUG_CALC_FPS
LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc
LOCAL_C_INCLUDES += hardware/qcom/display/liboverlay
LOCAL_C_INCLUDES += hardware/qcom/display/libcopybit
LOCAL_C_INCLUDES := hardware/qcom/display/libgralloc
LOCAL_C_INCLUDES += hardware/qcom/display/libgenlock
LOCAL_C_INCLUDES += hardware/qcom/display/liboverlay
LOCAL_C_INCLUDES += hardware/qcom/display/libqcomui
LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).hwcomposer\"
LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
ifeq ($(TARGET_HAVE_HDMI_OUT),true)
LOCAL_CFLAGS += -DHDMI_DUAL_DISPLAY
endif
ifeq ($(TARGET_USES_OVERLAY),true)
LOCAL_CFLAGS += -DUSE_OVERLAY
endif
ifeq ($(TARGET_HAVE_BYPASS),true)
LOCAL_CFLAGS += -DCOMPOSITION_BYPASS
endif
ifeq ($(TARGET_USE_HDMI_AS_PRIMARY),true)
LOCAL_CFLAGS += -DHDMI_AS_PRIMARY
endif
LOCAL_MODULE_TAGS := optional eng
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)

View File

@ -1,498 +0,0 @@
/*
* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define EXTDEBUG 0
class ExtDispOnly {
enum ExternalOnlyMode {
EXT_ONLY_MODE_OFF = 0,
EXT_ONLY_MODE_ON = 1,
};
enum {
MAX_EXT_ONLY_LAYERS = 2,
};
public:
/* Initialize, allocate data members */
static void init();
/* Deallocate data members */
static void destroy();
/* Closes all the overlay channels */
static void close();
/* Prepare overlay and configures mdp pipes */
static int prepare(hwc_context_t *ctx, hwc_layer_t *layer, int index,
bool waitForVsync);
/* Returns status of external-only mode */
static bool isModeOn();
/* Updates stats and pipe config related to external_only and external_block layers
* If we are staring or stopping this mode, update default mirroring.
*/
static int update(hwc_context_t* ctx, hwc_layer_list_t* list);
/* Stores the locked handle for the buffer that was successfully queued */
static void storeLockedHandles(hwc_layer_list_t* list);
/* Queue buffers to mdp for display */
static int draw(hwc_context_t *ctx, hwc_layer_list_t *list);
private:
/* Locks a buffer and marks it as locked */
static void lockBuffer(native_handle_t *hnd);
/* Unlocks a buffer and clears the locked flag */
static void unlockBuffer(native_handle_t *hnd);
/* Unlocks buffers queued in previous round (and displayed by now)
* Clears the handle cache.
*/
static void unlockPreviousBuffers();
/* Closes the a range of overlay channels */
static void closeRange(int start);
/* Start default external mirroring */
static void startDefaultMirror(hwc_context_t* ctx);
/* Stop default external mirroring */
static void stopDefaultMirror(hwc_context_t* ctx);
/* Checks if external-only mode is starting */
static bool isExtModeStarting(hwc_context_t* ctx, const int&
numExtLayers);
/* Checks if external-only mode is stopping */
static bool isExtModeStopping(hwc_context_t* ctx, const int&
numExtLayers);
//Data members
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
static overlay::OverlayUI* sOvExtUI[MAX_EXT_ONLY_LAYERS];
static native_handle_t* sPreviousExtHandle[MAX_EXT_ONLY_LAYERS];
static ExternalOnlyMode sExtOnlyMode;
static int sNumExtOnlyLayers;
static bool sSkipLayerPresent;
static bool sBlockLayerPresent;
static int sBlockLayerIndex;
#endif
}; //class ExtDispOnly
void ExtDispOnly::lockBuffer(native_handle_t *hnd) {
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
private_handle_t* phnd = (private_handle_t*)hnd;
//Genlock is reference counted and recursive.
//Do not accidently lock a locked buffer.
if(phnd && (phnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK)) {
LOGE_IF(EXTDEBUG, "%s: handle %p already locked", __func__, phnd);
return;
}
if (GENLOCK_FAILURE == genlock_lock_buffer(hnd, GENLOCK_READ_LOCK,
GENLOCK_MAX_TIMEOUT)) {
LOGE("%s: genlock_lock_buffer(READ) failed", __func__);
return;
}
phnd->flags |= private_handle_t::PRIV_FLAGS_HWC_LOCK;
LOGE_IF(EXTDEBUG, "%s: locked handle = %p", __func__, hnd);
#endif
}
void ExtDispOnly::unlockBuffer(native_handle_t *hnd) {
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
//Check if buffer is still around
if(private_handle_t::validate(hnd) != 0) {
LOGE("%s Handle already deallocated", __func__);
return;
}
private_handle_t* phnd = (private_handle_t*)hnd;
//Check if buffer was locked in the first place
if((phnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK) == 0) {
LOGE("%s Handle not locked, cannot unlock", __func__);
return;
}
//Actually try to unlock
if (GENLOCK_FAILURE == genlock_unlock_buffer(hnd)) {
LOGE("%s: genlock_unlock_buffer failed", __func__);
return;
}
//Clear the locked flag
phnd->flags &= ~private_handle_t::PRIV_FLAGS_HWC_LOCK;
LOGE_IF(EXTDEBUG, "%s: unlocked handle = %p", __func__, hnd);
#endif
}
void ExtDispOnly::unlockPreviousBuffers() {
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
for(int i = 0; (i < MAX_EXT_ONLY_LAYERS) && sPreviousExtHandle[i]; i++) {
LOGE_IF(EXTDEBUG, "%s", __func__);
ExtDispOnly::unlockBuffer(sPreviousExtHandle[i]);
sPreviousExtHandle[i] = NULL;
}
#endif
}
void ExtDispOnly::init() {
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
for(int i = 0; i < MAX_EXT_ONLY_LAYERS; i++) {
sOvExtUI[i] = new overlay::OverlayUI();
sPreviousExtHandle[i] = NULL;
}
sExtOnlyMode = EXT_ONLY_MODE_OFF;
sNumExtOnlyLayers = 0;
sSkipLayerPresent = false;
sBlockLayerPresent = false;
sBlockLayerIndex = -1;
LOGE_IF(EXTDEBUG, "%s", __func__);
#endif
}
void ExtDispOnly::destroy() {
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
for(int i = 0; i < MAX_EXT_ONLY_LAYERS; i++) {
delete sOvExtUI[i];
}
#endif
}
void ExtDispOnly::closeRange(int start) {
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
for (int index = start; index < MAX_EXT_ONLY_LAYERS; index++) {
if(sPreviousExtHandle[index]) {
LOGE_IF(EXTDEBUG, "%s", __func__);
ExtDispOnly::unlockBuffer(sPreviousExtHandle[index]);
sPreviousExtHandle[index] = NULL;
}
sOvExtUI[index]->closeChannel();
}
#endif
}
void inline ExtDispOnly::close() {
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
closeRange(0);
#endif
}
int ExtDispOnly::prepare(hwc_context_t *ctx, hwc_layer_t *layer, int index,
bool waitForVsync) {
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
if(ctx->mHDMIEnabled == EXT_DISPLAY_OFF ||
ctx->pendingHDMI == true)
return -1;
if (ctx && sOvExtUI[index]) {
private_hwc_module_t* hwcModule = reinterpret_cast<
private_hwc_module_t*>(ctx->device.common.module);
if (!hwcModule) {
LOGE("%s null module", __func__);
return -1;
}
private_handle_t *hnd = (private_handle_t *)layer->handle;
if(!hnd) {
LOGE("%s handle null", __func__);
return -1;
}
overlay::OverlayUI *ovUI = sOvExtUI[index];
int ret = 0;
//int orientation = layer->transform;
//Assuming layers will always be source landscape
const int orientation = 0;
overlay_buffer_info info;
hwc_rect_t sourceCrop = layer->sourceCrop;
info.width = sourceCrop.right - sourceCrop.left;
info.height = sourceCrop.bottom - sourceCrop.top;
info.format = hnd->format;
info.size = hnd->size;
const int fbnum = ctx->mHDMIEnabled; //HDMI or WFD
const bool isFg = false;
//Just to differentiate zorders for different layers
const int zorder = index;
const bool isVGPipe = true;
ovUI->setSource(info, orientation);
ovUI->setDisplayParams(fbnum, waitForVsync, isFg, zorder, isVGPipe);
const int fbWidth = ovUI->getFBWidth();
const int fbHeight = ovUI->getFBHeight();
ovUI->setPosition(0, 0, fbWidth, fbHeight);
if(ovUI->commit() != overlay::NO_ERROR) {
LOGE("%s: Overlay Commit failed", __func__);
return -1;
}
}
LOGE_IF(EXTDEBUG, "%s", __func__);
#endif
return overlay::NO_ERROR;
}
inline void ExtDispOnly::startDefaultMirror(hwc_context_t* ctx) {
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
hwc_composer_device_t* dev = (hwc_composer_device_t*) ctx;
private_hwc_module_t* hwcModule =
reinterpret_cast<private_hwc_module_t*>(dev->common.module);
framebuffer_device_t *fbDev = hwcModule->fbDevice;
if (fbDev) {
//mHDMIEnabled could be HDMI/WFD/NO EXTERNAL
fbDev->enableHDMIOutput(fbDev, ctx->mHDMIEnabled);
}
#endif
}
inline void ExtDispOnly::stopDefaultMirror(hwc_context_t* ctx) {
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
hwc_composer_device_t* dev = (hwc_composer_device_t*) ctx;
private_hwc_module_t* hwcModule =
reinterpret_cast<private_hwc_module_t*>(dev->common.module);
framebuffer_device_t *fbDev = hwcModule->fbDevice;
if (fbDev) {
fbDev->enableHDMIOutput(fbDev, EXT_DISPLAY_OFF);
}
#endif
}
inline bool ExtDispOnly::isExtModeStarting(hwc_context_t* ctx, const int&
numExtLayers) {
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
return ((sExtOnlyMode == EXT_ONLY_MODE_OFF) && numExtLayers);
#endif
return false;
}
inline bool ExtDispOnly::isExtModeStopping(hwc_context_t* ctx, const int&
numExtLayers) {
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
return ((sExtOnlyMode == EXT_ONLY_MODE_ON) && (numExtLayers == 0));
#endif
return false;
}
inline bool ExtDispOnly::isModeOn() {
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
return (sExtOnlyMode == EXT_ONLY_MODE_ON);
#endif
return false;
}
int ExtDispOnly::update(hwc_context_t* ctx, hwc_layer_list_t* list) {
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
int aNumExtLayers = 0;
bool aSkipLayerPresent = false;
bool aBlockLayerPresent = false;
int aBlockLayerIndex = -1;
//Book-keeping done each cycle
for (size_t i = 0; i < list->numHwLayers; i++) {
private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
// Dont draw in this round
if(list->hwLayers[i].flags & HWC_SKIP_LAYER) {
aSkipLayerPresent = true;
}
if(hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY)) {
aNumExtLayers++;
// No way we can let this be drawn by GPU to fb0
if(list->hwLayers[i].flags & HWC_SKIP_LAYER) {
list->hwLayers[i].flags &= ~ HWC_SKIP_LAYER;
}
list->hwLayers[i].flags |= HWC_USE_EXT_ONLY;
list->hwLayers[i].compositionType = HWC_USE_OVERLAY;
list->hwLayers[i].hints &= ~HWC_HINT_CLEAR_FB;
//EXTERNAL_BLOCK is always an add-on
if(hnd && (hnd->flags &
private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK)) {
aBlockLayerPresent = true;
aBlockLayerIndex = i;
list->hwLayers[i].flags |= HWC_USE_EXT_BLOCK;
}
}
}
//Update Default mirroring state
if (isExtModeStarting(ctx, aNumExtLayers)) {
stopDefaultMirror(ctx);
} else if (isExtModeStopping(ctx, aNumExtLayers)) {
startDefaultMirror(ctx);
}
//Cache our stats
sExtOnlyMode = aNumExtLayers ? EXT_ONLY_MODE_ON : EXT_ONLY_MODE_OFF;
sNumExtOnlyLayers = aNumExtLayers;
sSkipLayerPresent = aSkipLayerPresent;
sBlockLayerPresent = aBlockLayerPresent;
sBlockLayerIndex = aBlockLayerIndex;
LOGE_IF(EXTDEBUG, "%s: numExtLayers = %d skipLayerPresent = %d", __func__,
aNumExtLayers, aSkipLayerPresent);
//If skip layer present return. Buffers to be unlocked in draw phase.
if(aSkipLayerPresent) {
return overlay::NO_ERROR;
}
//If External is not connected, dont setup pipes, just return
if(ctx->mHDMIEnabled == EXT_DISPLAY_OFF ||
ctx->pendingHDMI == true) {
ExtDispOnly::close();
return -1;
}
//Update pipes
bool waitForVsync = true;
bool index = 0;
if (aBlockLayerPresent) {
ExtDispOnly::closeRange(1);
ExtDispOnly::prepare(ctx, &(list->hwLayers[aBlockLayerIndex]),
index, waitForVsync);
} else if (aNumExtLayers) {
ExtDispOnly::closeRange(aNumExtLayers);
for (size_t i = 0; i < list->numHwLayers; i++) {
private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
if(hnd && hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY) {
waitForVsync = (index == (aNumExtLayers - 1));
ExtDispOnly::prepare(ctx, &(list->hwLayers[i]),
index, waitForVsync);
index++;
}
}
} else {
ExtDispOnly::close();
}
#endif
return overlay::NO_ERROR;
}
void ExtDispOnly::storeLockedHandles(hwc_layer_list_t* list) {
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
int index = 0;
if(sBlockLayerPresent) {
private_handle_t *hnd = (private_handle_t *)
list->hwLayers[sBlockLayerIndex].handle;
if(list->hwLayers[sBlockLayerIndex].flags & HWC_USE_EXT_ONLY) {
if(!(hnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK)) {
ExtDispOnly::lockBuffer(hnd);
}
sPreviousExtHandle[index] = hnd;
LOGE_IF(EXTDEBUG, "%s BLOCK: handle = %p", __func__, hnd);
return;
}
}
for(int i = 0; i < list->numHwLayers; i++) {
private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
if(list->hwLayers[i].flags & HWC_USE_EXT_ONLY) {
if(!(hnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK)) {
ExtDispOnly::lockBuffer(hnd);
}
sPreviousExtHandle[index] = hnd;
index++;
LOGE_IF(EXTDEBUG, "%s: handle = %p", __func__, hnd);
}
}
#endif
}
int ExtDispOnly::draw(hwc_context_t *ctx, hwc_layer_list_t *list) {
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
LOGE_IF(EXTDEBUG, "%s", __func__);
if(ctx->mHDMIEnabled == EXT_DISPLAY_OFF ||
ctx->pendingHDMI == true) {
ExtDispOnly::close();
return -1;
}
int ret = overlay::NO_ERROR;
int index = 0;
//If skip layer present or list invalid unlock and return.
if(sSkipLayerPresent || list == NULL) {
ExtDispOnly::unlockPreviousBuffers();
return overlay::NO_ERROR;
}
if(sBlockLayerPresent) {
private_handle_t *hnd = (private_handle_t*)
list->hwLayers[sBlockLayerIndex].handle;
ExtDispOnly::lockBuffer(hnd);
ret = sOvExtUI[index]->queueBuffer(hnd);
if (ret) {
LOGE("%s queueBuffer failed", __func__);
// Unlock the locked buffer
ExtDispOnly::unlockBuffer(hnd);
ExtDispOnly::close();
return -1;
}
ExtDispOnly::unlockPreviousBuffers();
ExtDispOnly::storeLockedHandles(list);
return overlay::NO_ERROR;
}
for(int i = 0; i < list->numHwLayers; i++) {
private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
if(hnd && list->hwLayers[i].flags & HWC_USE_EXT_ONLY) {
overlay::OverlayUI *ovUI = sOvExtUI[index];
ExtDispOnly::lockBuffer(hnd);
ret = ovUI->queueBuffer(hnd);
if (ret) {
LOGE("%s queueBuffer failed", __func__);
// Unlock the all the currently locked buffers
for (int j = 0; j <= i; j++) {
private_handle_t *tmphnd =
(private_handle_t *)list->hwLayers[j].handle;
if(hnd && list->hwLayers[j].flags & HWC_USE_EXT_ONLY)
ExtDispOnly::unlockBuffer(tmphnd);
}
ExtDispOnly::close();
return -1;
}
index++;
}
}
ExtDispOnly::unlockPreviousBuffers();
ExtDispOnly::storeLockedHandles(list);
#endif
return overlay::NO_ERROR;
}
#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
overlay::OverlayUI* ExtDispOnly::sOvExtUI[MAX_EXT_ONLY_LAYERS];
native_handle_t* ExtDispOnly::sPreviousExtHandle[MAX_EXT_ONLY_LAYERS];
ExtDispOnly::ExternalOnlyMode ExtDispOnly::sExtOnlyMode;
int ExtDispOnly::sNumExtOnlyLayers;
bool ExtDispOnly::sSkipLayerPresent;
bool ExtDispOnly::sBlockLayerPresent;
int ExtDispOnly::sBlockLayerIndex;
#endif

145
libhwcomposer/hwc.cpp Normal file
View File

@ -0,0 +1,145 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <EGL/egl.h>
#include "hwc_utils.h"
using namespace qhwc;
static int hwc_device_open(const struct hw_module_t* module,
const char* name,
struct hw_device_t** device);
static struct hw_module_methods_t hwc_module_methods = {
open: hwc_device_open
};
hwc_module_t HAL_MODULE_INFO_SYM = {
common: {
tag: HARDWARE_MODULE_TAG,
version_major: 2,
version_minor: 0,
id: HWC_HARDWARE_MODULE_ID,
name: "Qualcomm Hardware Composer Module",
author: "CodeAurora Forum",
methods: &hwc_module_methods,
dso: 0,
reserved: {0},
}
};
/*
* Save callback functions registered to HWC
*/
static void hwc_registerProcs(struct hwc_composer_device* dev,
hwc_procs_t const* procs)
{
hwc_context_t* ctx = (hwc_context_t*)(dev);
if(!ctx) {
ALOGE("%s: Invalid context", __FUNCTION__);
return;
}
ctx->device.reserved_proc[0] = (void*)procs;
}
static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list)
{
hwc_context_t* ctx = (hwc_context_t*)(dev);
if (LIKELY(list)) {
getLayerStats(ctx, list);
cleanOverlays(ctx);
for (int i=list->numHwLayers-1; i >= 0 ; i--) {
private_handle_t *hnd =
(private_handle_t *)list->hwLayers[i].handle;
if (isSkipLayer(&list->hwLayers[i])) {
break;
} else if(isYuvBuffer(hnd)) {
handleYUV(ctx,&list->hwLayers[i]);
} else {
list->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
}
}
}
return 0;
}
static int hwc_set(hwc_composer_device_t *dev,
hwc_display_t dpy,
hwc_surface_t sur,
hwc_layer_list_t* list)
{
int ret = 0;
hwc_context_t* ctx = (hwc_context_t*)(dev);
if (LIKELY(list)) {
for (size_t i=0; i<list->numHwLayers; i++) {
if (list->hwLayers[i].flags & HWC_SKIP_LAYER) {
continue;
} else if (list->hwLayers[i].compositionType == HWC_USE_OVERLAY) {
drawLayerUsingOverlay(ctx, &(list->hwLayers[i]));
}
}
//XXX: Handle vsync with FBIO_WAITFORVSYNC ioctl
//All other operations (including pan display) should be NOWAIT
EGLBoolean sucess = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur);
} else {
//XXX: put in a wrapper for non overlay targets
setOverlayState(ctx, ovutils::OV_CLOSED);
}
ctx->qbuf->unlockAllPrevious();
return ret;
}
static int hwc_device_close(struct hw_device_t *dev)
{
if(!dev) {
ALOGE("hwc_device_close null device pointer");
return -1;
}
closeContext((hwc_context_t*)dev);
free(dev);
return 0;
}
static int hwc_device_open(const struct hw_module_t* module, const char* name,
struct hw_device_t** device)
{
int status = -EINVAL;
if (!strcmp(name, HWC_HARDWARE_COMPOSER)) {
struct hwc_context_t *dev;
dev = (hwc_context_t*)malloc(sizeof(*dev));
memset(dev, 0, sizeof(*dev));
initContext(dev);
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = const_cast<hw_module_t*>(module);
dev->device.common.close = hwc_device_close;
dev->device.prepare = hwc_prepare;
dev->device.set = hwc_set;
dev->device.registerProcs = hwc_registerProcs;
*device = &dev->device.common;
status = 0;
}
return status;
}

View File

@ -0,0 +1,294 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "hwc_utils.h"
namespace qhwc {
// Determine overlay state based on decoded video info
static ovutils::eOverlayState determineOverlayState(hwc_context_t* ctx,
uint32_t bypassLayer,
uint32_t format)
{
ovutils::eOverlayState state = ovutils::OV_CLOSED;
// Sanity check
if (!ctx) {
ALOGE("%s: NULL ctx", __FUNCTION__);
return state;
}
overlay::Overlay& ov = *(ctx->mOverlay);
state = ov.getState();
// If there are any bypassLayers, state is based on number of layers
if ((bypassLayer > 0) && (ctx->hdmiEnabled == EXT_TYPE_NONE)) {
if (bypassLayer == 1) {
state = ovutils::OV_BYPASS_1_LAYER;
} else if (bypassLayer == 2) {
state = ovutils::OV_BYPASS_2_LAYER;
} else if (bypassLayer == 3) {
state = ovutils::OV_BYPASS_3_LAYER;
}
return state;
}
// RGB is ambiguous for determining overlay state
if (ovutils::isRgb(ovutils::getMdpFormat(format))) {
return state;
}
// Content type is either 2D or 3D
uint32_t fmt3D = 0;//XXX: 3D - ovutils::getS3DFormat(format);
// Determine state based on the external display, content type, and hw type
if (ctx->hdmiEnabled == EXT_TYPE_HDMI) {
// External display is HDMI
if (fmt3D) {
// Content type is 3D
if (ovutils::is3DTV()) {
// TV panel type is 3D
state = ovutils::OV_3D_VIDEO_ON_3D_TV;
} else {
// TV panel type is 2D
state = ovutils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV;
}
} else {
// Content type is 2D
if (ovutils::FrameBufferInfo::getInstance()->supportTrueMirroring()) {
// True UI mirroring is supported
state = ovutils::OV_2D_TRUE_UI_MIRROR;
} else {
// True UI mirroring is not supported
state = ovutils::OV_2D_VIDEO_ON_PANEL_TV;
}
}
} else if (ctx->hdmiEnabled == EXT_TYPE_WIFI) {
// External display is Wifi (currently unsupported)
ALOGE("%s: WIFI external display is unsupported", __FUNCTION__);
return state;
} else {
// No external display (primary panel only)
if (fmt3D) {
// Content type is 3D
if (ovutils::usePanel3D()) {
// Primary panel type is 3D
state = ovutils::OV_3D_VIDEO_ON_3D_PANEL;
} else {
// Primary panel type is 2D
state = ovutils::OV_3D_VIDEO_ON_2D_PANEL;
}
} else {
// Content type is 2D
state = ovutils::OV_2D_VIDEO_ON_PANEL;
}
}
return state;
}
void setOverlayState(hwc_context_t *ctx, ovutils::eOverlayState state)
{
if (!ctx) {
ALOGE("%s: NULL ctx", __FUNCTION__);
return;
}
overlay::Overlay *ov = ctx->mOverlay;
if (!ov) {
ALOGE("%s: NULL OV object", __FUNCTION__);
return;
}
ov->setState(state);
}
bool prepareOverlay(hwc_context_t *ctx, hwc_layer_t *layer)
{
bool ret = false;
if (LIKELY(ctx->mOverlay)) {
private_handle_t *hnd = (private_handle_t *)layer->handle;
overlay::Overlay& ov = *(ctx->mOverlay);
ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
// Set overlay state
ovutils::eOverlayState state = determineOverlayState(ctx, 0, info.format);
setOverlayState(ctx, state);
ovutils::eDest dest = ovutils::OV_PIPE_ALL;
// In the true UI mirroring case, video needs to go to OV_PIPE0 (for
// primary) and OV_PIPE1 (for external)
if (state == ovutils::OV_2D_TRUE_UI_MIRROR) {
dest = static_cast<ovutils::eDest>(
ovutils::OV_PIPE0 | ovutils::OV_PIPE1);
}
// Order order order
// setSource - just setting source
// setParameter - changes src w/h/f accordingly
// setCrop - ROI - that is src_rect
// setPosition - need to do scaling
// commit - commit changes to mdp driver
// queueBuffer - not here, happens when draw is called
ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
if (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
ovutils::setMdpFlags(mdpFlags,
ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
}
// FIXME: Use source orientation for TV when source is portrait
int transform = layer->transform & FINAL_TRANSFORM_MASK;
ovutils::eTransform orient =
static_cast<ovutils::eTransform>(transform);
ovutils::eWait waitFlag = ovutils::NO_WAIT;
if (ctx->skipComposition == true) {
waitFlag = ovutils::WAIT;
}
ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF;
if (ctx->numHwLayers == 1) {
isFgFlag = ovutils::IS_FG_SET;
}
ovutils::PipeArgs parg(mdpFlags,
orient,
info,
waitFlag,
ovutils::ZORDER_0,
isFgFlag,
ovutils::ROT_FLAG_DISABLED);
ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg };
ret = ov.setSource(pargs, dest);
if (!ret) {
ALOGE("%s: setSource failed", __FUNCTION__);
return ret;
}
const ovutils::Params prms (ovutils::OVERLAY_TRANSFORM, orient);
ret = ov.setParameter(prms, dest);
if (!ret) {
ALOGE("%s: setParameter failed transform %x", __FUNCTION__, orient);
return ret;
}
hwc_rect_t sourceCrop = layer->sourceCrop;
// x,y,w,h
ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top, // x, y
sourceCrop.right - sourceCrop.left, // w
sourceCrop.bottom - sourceCrop.top);// h
ret = ov.setCrop(dcrop, dest);
if (!ret) {
ALOGE("%s: setCrop failed", __FUNCTION__);
return ret;
}
int orientation = 0;
ovutils::Dim dim;
hwc_rect_t displayFrame = layer->displayFrame;
dim.x = displayFrame.left;
dim.y = displayFrame.top;
dim.w = (displayFrame.right - displayFrame.left);
dim.h = (displayFrame.bottom - displayFrame.top);
dim.o = orientation;
ret = ov.setPosition(dim, dest);
if (!ret) {
ALOGE("%s: setPosition failed", __FUNCTION__);
return ret;
}
if (!ov.commit(dest)) {
ALOGE("%s: commit fails", __FUNCTION__);
return false;
}
}
return true;
}
bool drawLayerUsingOverlay(hwc_context_t *ctx, hwc_layer_t *layer)
{
private_handle_t *hnd = (private_handle_t *)layer->handle;
// Lock this buffer for read.
ctx->qbuf->lockAndAdd(hnd);
bool ret = true;
overlay::Overlay& ov = *(ctx->mOverlay);
ovutils::eOverlayState state = ov.getState();
// Differentiate between states that need to wait for vsync
switch (state) {
case ovutils::OV_2D_VIDEO_ON_PANEL_TV:
case ovutils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
case ovutils::OV_2D_TRUE_UI_MIRROR:
// If displaying on both primary and external, must play each
// pipe individually since wait for vsync needs to be done at
// the end. Do the following:
// - Play external
// - Play primary
// - Wait for external vsync to be done
// NOTE: In these states
// - primary VG = OV_PIPE0
// - external VG = OV_PIPE1
// - external RGB = OV_PIPE2
// - Only in true UI mirroring case, played by fb
// Same FD for both primary and external VG pipes
ov.setMemoryId(hnd->fd, static_cast<ovutils::eDest>(
ovutils::OV_PIPE0 | ovutils::OV_PIPE1));
// Play external
if (!ov.queueBuffer(hnd->offset, ovutils::OV_PIPE1)) {
ALOGE("%s: queueBuffer failed for external", __FUNCTION__);
ret = false;
}
// Play primary
if (!ov.queueBuffer(hnd->offset, ovutils::OV_PIPE0)) {
ALOGE("%s: queueBuffer failed for primary", __FUNCTION__);
ret = false;
}
// Wait for external vsync to be done
if (!ov.waitForVsync(ovutils::OV_PIPE1)) {
ALOGE("%s: waitForVsync failed for external", __FUNCTION__);
ret = false;
}
break;
default:
// In most cases, displaying only to one (primary or external)
// so use OV_PIPE_ALL since overlay will ignore NullPipes
ov.setMemoryId(hnd->fd, ovutils::OV_PIPE_ALL);
if (!ov.queueBuffer(hnd->offset, ovutils::OV_PIPE_ALL)) {
ALOGE("%s: queueBuffer failed", __FUNCTION__);
ret = false;
}
break;
}
if (!ret) {
ALOGE("%s: failed", __FUNCTION__);
}
return ret;
}
void cleanOverlays(hwc_context_t *ctx )
{
//XXX: handle for HDMI
if(0 == ctx->yuvBufferCount)
setOverlayState(ctx, ovutils::OV_CLOSED);
}
}; //namespace qhwc

114
libhwcomposer/hwc_qbuf.h Normal file
View File

@ -0,0 +1,114 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// -----------------------------------------------------------------------------
// QueuedBufferStore
//This class holds currently and previously queued buffers.
//Provides utilities to store, lock, remove, unlock.
namespace qhwc{
static const int MAX_QUEUED_BUFS = 4;
class QueuedBufferStore {
public:
QueuedBufferStore() {
clearCurrent();
clearPrevious();
}
~QueuedBufferStore() {}
void lockAndAdd(private_handle_t*);
void unlockAllPrevious();
private:
QueuedBufferStore& operator=(const QueuedBufferStore&);
QueuedBufferStore(const QueuedBufferStore&);
bool lockBuffer(private_handle_t *hnd);
void unlockBuffer(private_handle_t *hnd);
void clearCurrent();
void clearPrevious();
void mvCurrToPrev();
//members
private_handle_t *current[MAX_QUEUED_BUFS]; //holds buf being queued
private_handle_t *previous[MAX_QUEUED_BUFS]; //holds bufs queued in prev round
int curCount;
int prevCount;
};
//Store and lock current drawing round buffers
inline void QueuedBufferStore::lockAndAdd(private_handle_t *hnd) {
if(lockBuffer(hnd))
current[curCount++] = hnd;
}
//Unlock all previous drawing round buffers
inline void QueuedBufferStore::unlockAllPrevious() {
//Unlock
for(int i = 0; i < prevCount; i++) {
unlockBuffer(previous[i]);
previous[i] = NULL;
}
//Move current hnd to previous
mvCurrToPrev();
//Clear current
clearCurrent();
}
//Clear currentbuf store
inline void QueuedBufferStore::clearCurrent() {
for(int i = 0; i < MAX_QUEUED_BUFS; i++)
current[i] = NULL;
curCount = 0;
}
//Clear previousbuf store
inline void QueuedBufferStore::clearPrevious() {
for(int i = 0; i < MAX_QUEUED_BUFS; i++)
previous[i] = NULL;
prevCount = 0;
}
//Copy from current to previous
inline void QueuedBufferStore::mvCurrToPrev() {
for(int i = 0; i < curCount; i++)
previous[i] = current[i];
prevCount = curCount;
}
inline bool QueuedBufferStore::lockBuffer(private_handle_t *hnd) {
if (GENLOCK_FAILURE == genlock_lock_buffer(hnd, GENLOCK_READ_LOCK,
GENLOCK_MAX_TIMEOUT)) {
ALOGE("%s: genlock_lock_buffer(READ) failed", __func__);
return false;
}
return true;
}
inline void QueuedBufferStore::unlockBuffer(private_handle_t *hnd) {
//Check if buffer is still around
if(private_handle_t::validate(hnd) != 0) {
ALOGE("%s Invalid Handle", __func__);
return;
}
//Actually try to unlock
if (GENLOCK_FAILURE == genlock_unlock_buffer(hnd)) {
ALOGE("%s: genlock_unlock_buffer failed", __func__);
return;
}
}
// -----------------------------------------------------------------------------
};//namespace

View File

@ -0,0 +1,96 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "hwc_utils.h"
namespace qhwc {
void initContext(hwc_context_t *ctx)
{
//XXX: target specific initializations here
openFramebufferDevice(ctx);
ctx->mOverlay = overlay::Overlay::getInstance();
ctx->qbuf = new QueuedBufferStore();
}
void closeContext(hwc_context_t *ctx)
{
if(ctx->mOverlay) {
delete ctx->mOverlay;
ctx->mOverlay = NULL;
}
if(ctx->fbDev) {
framebuffer_close(ctx->fbDev);
ctx->fbDev = NULL;
}
if(ctx->qbuf) {
delete ctx->qbuf;
ctx->qbuf = NULL;
}
}
// Opens Framebuffer device
void openFramebufferDevice(hwc_context_t *ctx) {
hw_module_t const *module;
if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
framebuffer_open(module, &(ctx->fbDev));
}
}
void dumpLayer(hwc_layer_t const* l)
{
ALOGD("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, {%d,%d,%d,%d}"
", {%d,%d,%d,%d}",
l->compositionType, l->flags, l->handle, l->transform, l->blending,
l->sourceCrop.left,
l->sourceCrop.top,
l->sourceCrop.right,
l->sourceCrop.bottom,
l->displayFrame.left,
l->displayFrame.top,
l->displayFrame.right,
l->displayFrame.bottom);
}
void getLayerStats(hwc_context_t *ctx, const hwc_layer_list_t *list)
{
int yuvBufCount = 0;
int layersNotUpdatingCount = 0;
for (size_t i=0 ; i<list->numHwLayers; i++) {
private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
if (isYuvBuffer(hnd)) {
yuvBufCount++;
}
}
// Number of video/camera layers drawable with overlay
ctx->yuvBufferCount = yuvBufCount;
ctx->numHwLayers = list->numHwLayers;
return;
}
void handleYUV(hwc_context_t *ctx, hwc_layer_t *layer)
{
private_handle_t *hnd =
(private_handle_t *)layer->handle;
//XXX: Handle targets not using overlay
if(prepareOverlay(ctx, layer)) {
layer->compositionType = HWC_USE_OVERLAY;
layer->hints |= HWC_HINT_CLEAR_FB;
}
}
};//namespace

111
libhwcomposer/hwc_utils.h Normal file
View File

@ -0,0 +1,111 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef HWC_UTILS_H
#define HWC_UTILS_H
#include <cutils/log.h>
#include <gralloc_priv.h>
#include <hardware/hwcomposer.h>
#include <hardware/hardware.h>
#include <hardware/gralloc.h>
#include <stdlib.h>
#include <string.h>
#include <fb_priv.h>
#include <overlay.h>
#include <qcom_ui.h>
#include <genlock.h>
#include "hwc_qbuf.h"
#define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1))
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
struct hwc_context_t;
namespace qhwc {
// -----------------------------------------------------------------------------
// Utility functions - implemented in hwc_utils.cpp
void dumpLayer(hwc_layer_t const* l);
void getLayerStats(hwc_context_t *ctx, const hwc_layer_list_t *list);
void handleYUV(hwc_context_t *ctx, hwc_layer_t *layer);
void initContext(hwc_context_t *ctx);
void closeContext(hwc_context_t *ctx);
void openFramebufferDevice(hwc_context_t *ctx);
// Inline utility functions
static inline bool isSkipLayer(const hwc_layer_t* l) {
return (UNLIKELY(l && (l->flags & HWC_SKIP_LAYER)));
}
// Returns true if the buffer is yuv
static inline bool isYuvBuffer(const private_handle_t* hnd) {
return (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO));
}
//Return true if buffer is marked locked
static inline bool isBufferLocked(const private_handle_t* hnd) {
return (hnd && (private_handle_t::PRIV_FLAGS_HWC_LOCK & hnd->flags));
}
// -----------------------------------------------------------------------------
// Overlay specific functions - inline or implemented in hwc_overlay.cpp
bool prepareOverlay(hwc_context_t *ctx, hwc_layer_t *layer);
//XXX: Refine draw functions
bool drawLayerUsingOverlay(hwc_context_t *ctx, hwc_layer_t *layer);
//XXX: Refine
void cleanOverlays(hwc_context_t *ctx );
void setOverlayState(hwc_context_t* ctx, ovutils::eOverlayState state);
// -----------------------------------------------------------------------------
// Copybit specific functions - inline or implemented in hwc_copybit.cpp
// -----------------------------------------------------------------------------
// HDMI specific functions - inline or implemented in hwc_hdmi.cpp
} //qhwc namespace
// -----------------------------------------------------------------------------
// HWC context
// This structure contains overall state
struct hwc_context_t {
hwc_composer_device_t device;
// Layer variables
int yuvBufferCount;
int hdmiEnabled;
int numHwLayers;
bool skipComposition;
//Framebuffer device
framebuffer_device_t *fbDev;
//Overlay object - NULL for non overlay devices
overlay::Overlay *mOverlay;
//QueuedBufferStore to hold buffers for overlay
qhwc::QueuedBufferStore *qbuf;
};
#endif //HWC_UTILS_H

File diff suppressed because it is too large Load Diff

47
liboverlay/Android.mk Executable file → Normal file
View File

@ -1,43 +1,20 @@
# Copyright (C) 2008 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libmemalloc
LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SHARED_LIBRARIES += libcutils
LOCAL_SHARED_LIBRARIES += libutils
LOCAL_SHARED_LIBRARIES += libmemalloc
LOCAL_C_INCLUDES := hardware/qcom/display/libgralloc
LOCAL_SRC_FILES := \
overlayLib.cpp \
overlayLibUI.cpp \
LOCAL_CFLAGS:= -DLOG_TAG=\"OverlayLib\"
overlay.cpp \
overlayCtrl.cpp \
overlayUtils.cpp \
overlayMdp.cpp \
overlayRotator.cpp \
overlayTransitions.cpp
ifeq ($(TARGET_USE_HDMI_AS_PRIMARY),true)
LOCAL_CFLAGS += -DHDMI_AS_PRIMARY
endif
ifeq ($(TARGET_USES_POST_PROCESSING),true)
LOCAL_CFLAGS += -DUSES_POST_PROCESSING
LOCAL_SHARED_LIBRARIES += libmm-abl
LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/pp/inc
LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/lib/
endif
LOCAL_CFLAGS:= -DLOG_TAG=\"overlay2\"
LOCAL_MODULE := liboverlay
#LGE_CHANGE, for userdebug mode
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)

270
liboverlay/mdpWrapper.h Normal file
View File

@ -0,0 +1,270 @@
/*
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MDP_WRAPPER_H
#define MDP_WRAPPER_H
/*
* In order to make overlay::mdp_wrapper shorter, please do something like:
* namespace mdpwrap = overlay::mdp_wrapper;
* */
#include <linux/msm_mdp.h>
#include <linux/msm_rotator.h>
#include <sys/ioctl.h>
#include <utils/Log.h>
#include <errno.h>
#include "overlayUtils.h"
namespace overlay{
namespace mdp_wrapper{
/* FBIOGET_FSCREENINFO */
bool getFScreenInfo(int fd, fb_fix_screeninfo& finfo);
/* FBIOGET_VSCREENINFO */
bool getVScreenInfo(int fd, fb_var_screeninfo& vinfo);
/* FBIOPUT_VSCREENINFO */
bool setVScreenInfo(int fd, fb_var_screeninfo& vinfo);
/* MSM_ROTATOR_IOCTL_START */
bool startRotator(int fd, msm_rotator_img_info& rot);
/* MSM_ROTATOR_IOCTL_ROTATE */
bool rotate(int fd, msm_rotator_data_info& rot);
/* MSMFB_OVERLAY_SET */
bool setOverlay(int fd, mdp_overlay& ov);
/* MSM_ROTATOR_IOCTL_FINISH */
bool endRotator(int fd, int sessionId);
/* MSMFB_OVERLAY_UNSET */
bool unsetOverlay(int fd, int ovId);
/* MSMFB_OVERLAY_GET */
bool getOverlay(int fd, mdp_overlay& ov);
/* MSMFB_OVERLAY_PLAY */
bool play(int fd, msmfb_overlay_data& od);
/* MSMFB_OVERLAY_PLAY_WAIT */
bool playWait(int fd, msmfb_overlay_data& od);
/* MSMFB_OVERLAY_3D */
bool set3D(int fd, msmfb_overlay_3d& ov);
/* the following are helper functions for dumping
* msm_mdp and friends*/
void dump(const char* const s, const msmfb_overlay_data& ov);
void dump(const char* const s, const msmfb_data& ov);
void dump(const char* const s, const mdp_overlay& ov);
void dump(const char* const s, const msmfb_overlay_3d& ov);
void dump(const char* const s, const uint32_t u[], uint32_t cnt);
void dump(const char* const s, const msmfb_img& ov);
void dump(const char* const s, const mdp_rect& ov);
/* and rotator */
void dump(const char* const s, const msm_rotator_img_info& rot);
void dump(const char* const s, const msm_rotator_data_info& rot);
/* info */
void dump(const char* const s, const fb_fix_screeninfo& finfo);
void dump(const char* const s, const fb_var_screeninfo& vinfo);
//---------------Inlines -------------------------------------
inline bool getFScreenInfo(int fd, fb_fix_screeninfo& finfo) {
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) {
ALOGE("Failed to call ioctl FBIOGET_FSCREENINFO err=%d", errno);
return false;
}
return true;
}
inline bool getVScreenInfo(int fd, fb_var_screeninfo& vinfo) {
if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
ALOGE("Failed to call ioctl FBIOGET_VSCREENINFO err=%d", errno);
return false;
}
return true;
}
inline bool setVScreenInfo(int fd, fb_var_screeninfo& vinfo) {
if (ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo) == -1) {
ALOGE("Failed to call ioctl FBIOPUT_VSCREENINFO err=%d", errno);
return false;
}
return true;
}
inline bool startRotator(int fd, msm_rotator_img_info& rot) {
if (ioctl(fd, MSM_ROTATOR_IOCTL_START, &rot) == -1){
ALOGE("Failed to call ioctl MSM_ROTATOR_IOCTL_START err=%d", errno);
return false;
}
return true;
}
inline bool rotate(int fd, msm_rotator_data_info& rot) {
if (ioctl(fd, MSM_ROTATOR_IOCTL_ROTATE, &rot) == -1) {
ALOGE("Failed to call ioctl MSM_ROTATOR_IOCTL_ROTATE err=%d", errno);
return false;
}
return true;
}
inline bool setOverlay(int fd, mdp_overlay& ov) {
if (ioctl(fd, MSMFB_OVERLAY_SET, &ov) == -1) {
ALOGE("Failed to call ioctl MSMFB_OVERLAY_SET err=%d", errno);
return false;
}
return true;
}
inline bool endRotator(int fd, int sessionId) {
if (ioctl(fd, MSM_ROTATOR_IOCTL_FINISH, &sessionId) == -1) {
ALOGE("Failed to call ioctl MSM_ROTATOR_IOCTL_FINISH err=%d", errno);
return false;
}
return true;
}
inline bool unsetOverlay(int fd, int ovId) {
if (ioctl(fd, MSMFB_OVERLAY_UNSET, &ovId) == -1) {
ALOGE("Failed to call ioctl MSMFB_OVERLAY_UNSET err=%d", errno);
return false;
}
return true;
}
inline bool getOverlay(int fd, mdp_overlay& ov) {
if (ioctl(fd, MSMFB_OVERLAY_GET, &ov) == -1) {
ALOGE("Failed to call ioctl MSMFB_OVERLAY_GET err=%d", errno);
return false;
}
return true;
}
inline bool play(int fd, msmfb_overlay_data& od) {
if (ioctl(fd, MSMFB_OVERLAY_PLAY, &od) == -1) {
ALOGE("Failed to call ioctl MSMFB_OVERLAY_PLAY err=%d", errno);
return false;
}
return true;
}
inline bool playWait(int fd, msmfb_overlay_data& od) {
if (ioctl(fd, MSMFB_OVERLAY_PLAY_WAIT, &od) == -1) {
ALOGE("Failed to call ioctl MSMFB_OVERLAY_PLAY_WAIT err=%d", errno);
return false;
}
return true;
}
inline bool set3D(int fd, msmfb_overlay_3d& ov) {
if (ioctl(fd, MSMFB_OVERLAY_3D, &ov) == -1) {
ALOGE("Failed to call ioctl MSMFB_OVERLAY_3D err=%d", errno);
return false;
}
return true;
}
/* dump funcs */
inline void dump(const char* const s, const msmfb_overlay_data& ov) {
ALOGE("%s msmfb_overlay_data id=%d",
s, ov.id);
dump("data", ov.data);
}
inline void dump(const char* const s, const msmfb_data& ov) {
ALOGE("%s msmfb_data offset=%d memid=%d id=%d flags=0x%x priv=%d",
s, ov.offset, ov.memory_id, ov.id, ov.flags, ov.priv);
}
inline void dump(const char* const s, const mdp_overlay& ov) {
ALOGE("%s mdp_overlay z=%d fg=%d alpha=%d mask=%d flags=0x%x id=%d",
s, ov.z_order, ov.is_fg, ov.alpha,
ov.transp_mask, ov.flags, ov.id);
dump("src", ov.src);
dump("src_rect", ov.src_rect);
dump("dst_rect", ov.dst_rect);
dump("user_data", ov.user_data,
sizeof(ov.user_data)/sizeof(ov.user_data[0]));
}
inline void dump(const char* const s, const msmfb_img& ov) {
ALOGE("%s msmfb_img w=%d h=%d format=%d %s",
s, ov.width, ov.height, ov.format,
overlay::utils::getFormatString(ov.format));
}
inline void dump(const char* const s, const mdp_rect& ov) {
ALOGE("%s mdp_rect x=%d y=%d w=%d h=%d",
s, ov.x, ov.y, ov.w, ov.h);
}
inline void dump(const char* const s, const msmfb_overlay_3d& ov) {
ALOGE("%s msmfb_overlay_3d 3d=%d w=%d h=%d",
s, ov.is_3d, ov.width, ov.height);
}
inline void dump(const char* const s, const uint32_t u[], uint32_t cnt) {
ALOGE("%s user_data cnt=%d", s, cnt);
for(uint32_t i=0; i < cnt; ++i) {
ALOGE("i=%d val=%d", i, u[i]);
}
}
inline void dump(const char* const s, const msm_rotator_img_info& rot) {
ALOGE("%s msm_rotator_img_info sessid=%d dstx=%d dsty=%d rot=%d, ena=%d",
s, rot.session_id, rot.dst_x, rot.dst_y,
rot.rotations, rot.enable);
dump("src", rot.src);
dump("dst", rot.dst);
dump("src_rect", rot.src_rect);
}
inline void dump(const char* const s, const msm_rotator_data_info& rot) {
ALOGE("%s msm_rotator_data_info sessid=%d verkey=%d",
s, rot.session_id, rot.version_key);
dump("src", rot.src);
dump("dst", rot.dst);
dump("src_chroma", rot.src_chroma);
dump("dst_chroma", rot.dst_chroma);
}
inline void dump(const char* const s, const fb_fix_screeninfo& finfo) {
ALOGE("%s fb_fix_screeninfo type=%d", s, finfo.type);
}
inline void dump(const char* const s, const fb_var_screeninfo& vinfo) {
ALOGE("%s fb_var_screeninfo xres=%d yres=%d",
s, vinfo.xres, vinfo.yres);
}
} // mdp_wrapper
} // overlay
#endif // MDP_WRAPPER_H

455
liboverlay/overlay.cpp Normal file
View File

@ -0,0 +1,455 @@
/*
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "overlayUtils.h"
#include "overlayImpl.h"
#include "overlay.h"
// MDP related FIXME move to state
#include "overlayMdp.h"
#include "overlayCtrlData.h"
#include "overlayRotator.h"
namespace overlay {
Overlay::Overlay(): mOv(0) {
}
Overlay::~Overlay() {
if(mState.state() == utils::OV_CLOSED) return;
close();
delete mOv;
mOv = 0;
}
bool Overlay::open() {
// We need an empty open to just open the bare minimum for business
return true;
}
void Overlay::reset(){
if(mOv && !mOv->close()) {
ALOGE("%s Overlay failed", __FUNCTION__);
}
delete mOv;
mOv = 0;
}
bool Overlay::close()
{
OVASSERT(mOv,
"%s Overlay and Rotator should be init at this point",
__FUNCTION__);
// FIXME that one needs to move to the state machine class
utils::eOverlayState st = mState.state();
switch (st) {
case utils::OV_CLOSED:
// try to close any partially opened items
break;
case utils::OV_2D_VIDEO_ON_PANEL:
case utils::OV_2D_VIDEO_ON_PANEL_TV:
case utils::OV_3D_VIDEO_ON_2D_PANEL:
case utils::OV_3D_VIDEO_ON_3D_PANEL:
case utils::OV_3D_VIDEO_ON_3D_TV:
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
case utils::OV_UI_MIRROR:
case utils::OV_2D_TRUE_UI_MIRROR:
case utils::OV_BYPASS_1_LAYER:
case utils::OV_BYPASS_2_LAYER:
case utils::OV_BYPASS_3_LAYER:
mOv = mState.handleEvent(utils::OV_CLOSED, mOv);
this->reset();
break;
default:
OVASSERT(false, "close Unknown state %d", st);
return false;
}
return true;
}
bool Overlay::commit(utils::eDest dest)
{
OVASSERT(mOv,
"%s Overlay and Rotator should be init at this point",
__FUNCTION__);
// FIXME that one needs to move to the state machine class
utils::eOverlayState st = mState.state();
switch (st) {
case utils::OV_2D_VIDEO_ON_PANEL:
case utils::OV_2D_VIDEO_ON_PANEL_TV:
case utils::OV_3D_VIDEO_ON_2D_PANEL:
case utils::OV_3D_VIDEO_ON_3D_PANEL:
case utils::OV_3D_VIDEO_ON_3D_TV:
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
case utils::OV_UI_MIRROR:
case utils::OV_2D_TRUE_UI_MIRROR:
case utils::OV_BYPASS_1_LAYER:
case utils::OV_BYPASS_2_LAYER:
case utils::OV_BYPASS_3_LAYER:
if(!mOv->commit(dest)) {
ALOGE("Overlay %s failed", __FUNCTION__);
return false;
}
break;
default:
OVASSERT(false, "%s Unknown state %d", __FUNCTION__, st);
return false;
}
return true;
}
bool Overlay::queueBuffer(uint32_t offset,
utils::eDest dest)
{
OVASSERT(mOv,
"%s Overlay and Rotator should be init at this point",
__FUNCTION__);
// FIXME that one needs to move to the state machine class
utils::eOverlayState st = mState.state();
switch (st) {
case utils::OV_2D_VIDEO_ON_PANEL:
case utils::OV_2D_VIDEO_ON_PANEL_TV:
case utils::OV_3D_VIDEO_ON_2D_PANEL:
case utils::OV_3D_VIDEO_ON_3D_PANEL:
case utils::OV_3D_VIDEO_ON_3D_TV:
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
case utils::OV_UI_MIRROR:
case utils::OV_2D_TRUE_UI_MIRROR:
case utils::OV_BYPASS_1_LAYER:
case utils::OV_BYPASS_2_LAYER:
case utils::OV_BYPASS_3_LAYER:
if(!mOv->queueBuffer(offset, dest)) {
ALOGE("Overlay %s failed", __FUNCTION__);
return false;
}
break;
default:
OVASSERT(false, "%s Unknown state %d", __FUNCTION__, st);
return false;
}
return true;
}
bool Overlay::dequeueBuffer(void*& buf,
utils::eDest dest)
{
OVASSERT(mOv,
"%s Overlay and Rotator should be init at this point",
__FUNCTION__);
// FIXME that one needs to move to the state machine class
utils::eOverlayState st = mState.state();
switch (st) {
case utils::OV_2D_VIDEO_ON_PANEL:
case utils::OV_2D_VIDEO_ON_PANEL_TV:
case utils::OV_3D_VIDEO_ON_2D_PANEL:
case utils::OV_3D_VIDEO_ON_3D_PANEL:
case utils::OV_3D_VIDEO_ON_3D_TV:
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
case utils::OV_UI_MIRROR:
case utils::OV_2D_TRUE_UI_MIRROR:
case utils::OV_BYPASS_1_LAYER:
case utils::OV_BYPASS_2_LAYER:
case utils::OV_BYPASS_3_LAYER:
if(!mOv->dequeueBuffer(buf, dest)) {
ALOGE("Overlay %s failed", __FUNCTION__);
return false;
}
break;
default:
OVASSERT(false, "%s Unknown state %d", __FUNCTION__, st);
return false;
}
return true;
}
bool Overlay::waitForVsync(utils::eDest dest)
{
OVASSERT(mOv,
"%s Overlay and Rotator should be init at this point",
__FUNCTION__);
// FIXME that one needs to move to the state machine class
utils::eOverlayState st = mState.state();
switch (st) {
case utils::OV_2D_VIDEO_ON_PANEL:
case utils::OV_2D_VIDEO_ON_PANEL_TV:
case utils::OV_3D_VIDEO_ON_2D_PANEL:
case utils::OV_3D_VIDEO_ON_3D_PANEL:
case utils::OV_3D_VIDEO_ON_3D_TV:
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
case utils::OV_UI_MIRROR:
case utils::OV_2D_TRUE_UI_MIRROR:
case utils::OV_BYPASS_1_LAYER:
case utils::OV_BYPASS_2_LAYER:
case utils::OV_BYPASS_3_LAYER:
if(!mOv->waitForVsync(dest)) {
ALOGE("Overlay %s failed", __FUNCTION__);
return false;
}
break;
default:
OVASSERT(false, "%s Unknown state %d", __FUNCTION__, st);
return false;
}
return true;
}
bool Overlay::setCrop(const utils::Dim& d,
utils::eDest dest)
{
OVASSERT(mOv,
"%s Overlay and Rotator should be init at this point",
__FUNCTION__);
// FIXME that one needs to move to the state machine class
utils::eOverlayState st = mState.state();
switch (st) {
case utils::OV_2D_VIDEO_ON_PANEL:
case utils::OV_2D_VIDEO_ON_PANEL_TV:
case utils::OV_3D_VIDEO_ON_2D_PANEL:
case utils::OV_3D_VIDEO_ON_3D_PANEL:
case utils::OV_3D_VIDEO_ON_3D_TV:
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
case utils::OV_UI_MIRROR:
case utils::OV_2D_TRUE_UI_MIRROR:
case utils::OV_BYPASS_1_LAYER:
case utils::OV_BYPASS_2_LAYER:
case utils::OV_BYPASS_3_LAYER:
if(!mOv->setCrop(d, dest)) {
ALOGE("Overlay %s failed", __FUNCTION__);
return false;
}
break;
default:
OVASSERT(false, "%s Unknown state %d", __FUNCTION__, st);
return false;
}
return true;
}
bool Overlay::setPosition(const utils::Dim& d,
utils::eDest dest)
{
OVASSERT(mOv,
"%s Overlay and Rotator should be init at this point",
__FUNCTION__);
// FIXME that one needs to move to the state machine class
utils::eOverlayState st = mState.state();
switch (st) {
case utils::OV_2D_VIDEO_ON_PANEL:
case utils::OV_2D_VIDEO_ON_PANEL_TV:
case utils::OV_3D_VIDEO_ON_2D_PANEL:
case utils::OV_3D_VIDEO_ON_3D_PANEL:
case utils::OV_3D_VIDEO_ON_3D_TV:
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
case utils::OV_UI_MIRROR:
case utils::OV_2D_TRUE_UI_MIRROR:
case utils::OV_BYPASS_1_LAYER:
case utils::OV_BYPASS_2_LAYER:
case utils::OV_BYPASS_3_LAYER:
if(!mOv->setPosition(d, dest)) {
ALOGE("Overlay %s failed", __FUNCTION__);
return false;
}
break;
default:
OVASSERT(false, "setPos Unknown state %d", st);
return false;
}
return true;
}
bool Overlay::setParameter(const utils::Params& param,
utils::eDest dest)
{
OVASSERT(mOv,
"%s Overlay and Rotator should be init at this point",
__FUNCTION__);
// FIXME that one needs to move to the state machine class
utils::eOverlayState st = mState.state();
switch (st) {
case utils::OV_2D_VIDEO_ON_PANEL:
case utils::OV_2D_VIDEO_ON_PANEL_TV:
case utils::OV_3D_VIDEO_ON_2D_PANEL:
case utils::OV_3D_VIDEO_ON_3D_PANEL:
case utils::OV_3D_VIDEO_ON_3D_TV:
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
case utils::OV_UI_MIRROR:
case utils::OV_2D_TRUE_UI_MIRROR:
case utils::OV_BYPASS_1_LAYER:
case utils::OV_BYPASS_2_LAYER:
case utils::OV_BYPASS_3_LAYER:
if(!mOv->setParameter(param, dest)) {
ALOGE("Overlay %s failed", __FUNCTION__);
return false;
}
break;
default:
OVASSERT(false, "%s Unknown state %d", __FUNCTION__ , st);
return false;
}
return true;
}
bool Overlay::setSource(const utils::PipeArgs args[utils::MAX_PIPES],
utils::eDest dest)
{
// FIXME that one needs to move to the state machine class
utils::PipeArgs margs[utils::MAX_PIPES] = {
args[0], args[1], args[2] };
utils::eOverlayState st = mState.state();
switch (st) {
case utils::OV_CLOSED:
// if we get setSource when we are closed, then
// we will assume tranistion to OV_2D_VIDEO_ON_PANEL
// returns overlay
mOv = mState.handle_closed(utils::OV_2D_VIDEO_ON_PANEL);
if (!mOv) {
ALOGE("Overlay %s failed", __FUNCTION__);
this->reset(); // cleanup
return false;
}
break;
case utils::OV_2D_VIDEO_ON_PANEL:
case utils::OV_3D_VIDEO_ON_2D_PANEL:
case utils::OV_UI_MIRROR:
case utils::OV_BYPASS_1_LAYER:
case utils::OV_BYPASS_2_LAYER:
case utils::OV_BYPASS_3_LAYER:
// no tweaking
break;
case utils::OV_3D_VIDEO_ON_3D_PANEL:
case utils::OV_3D_VIDEO_ON_3D_TV:
margs[utils::CHANNEL_1].zorder = utils::ZORDER_1;
break;
case utils::OV_2D_VIDEO_ON_PANEL_TV:
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
// If displaying on both, external VG pipe set to be no wait
margs[utils::CHANNEL_1].wait = utils::NO_WAIT;
break;
case utils::OV_2D_TRUE_UI_MIRROR:
// Set zorder -- external VG pipe (video) gets 0, RGB pipe (UI) gets 1
margs[utils::CHANNEL_1].zorder = utils::ZORDER_0;
margs[utils::CHANNEL_2].zorder = utils::ZORDER_1;
// External VG (video) and RGB (UI) pipe set to be no wait
margs[utils::CHANNEL_0].wait = utils::WAIT;
margs[utils::CHANNEL_1].wait = utils::NO_WAIT;
margs[utils::CHANNEL_2].wait = utils::NO_WAIT;
break;
default:
OVASSERT(false, "%s Unknown state %d", __FUNCTION__, st);
return false;
}
if (!mOv->setSource(margs, dest)) {
ALOGE("Overlay %s failed", __FUNCTION__);
return false;
}
return true;
}
void Overlay::setMemoryId(int id, utils::eDest dest)
{
OVASSERT(mOv,
"%s Overlay and Rotator should be init at this point",
__FUNCTION__);
// FIXME that one needs to move to the state machine class
utils::eOverlayState st = mState.state();
switch (st) {
case utils::OV_2D_VIDEO_ON_PANEL:
case utils::OV_2D_VIDEO_ON_PANEL_TV:
case utils::OV_3D_VIDEO_ON_2D_PANEL:
case utils::OV_3D_VIDEO_ON_3D_PANEL:
case utils::OV_3D_VIDEO_ON_3D_TV:
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
case utils::OV_UI_MIRROR:
case utils::OV_2D_TRUE_UI_MIRROR:
case utils::OV_BYPASS_1_LAYER:
case utils::OV_BYPASS_2_LAYER:
case utils::OV_BYPASS_3_LAYER:
mOv->setMemoryId(id, dest);
break;
default:
OVASSERT(false, "setMemId Unknown state %d", st);
}
}
void Overlay::dump() const
{
OVASSERT(mOv,
"%s Overlay and Rotator should be init at this point",
__FUNCTION__);
// FIXME dump tate object, factory
ALOGE("== Dump Overlay start ==");
mState.dump();
mOv->dump();
ALOGE("== Dump Overlay end ==");
}
void Overlay::setState(utils::eOverlayState s) {
mOv = mState.handleEvent(s, mOv);
}
utils::eOverlayState Overlay::getState() const {
return mState.state();
}
Overlay *Overlay::sInstance = 0;
Overlay* Overlay::getInstance() {
if(sInstance == NULL)
sInstance = new Overlay();
return sInstance;
}
/**** NullPipe ****/
bool NullPipe::open(RotatorBase*) {
ALOGE_IF(DEBUG_OVERLAY, "NullPipe open");
return true;
}
bool NullPipe::close() { return true; }
bool NullPipe::commit() { return true; }
bool NullPipe::start(const utils::PipeArgs&) { return true; }
bool NullPipe::setCrop(const utils::Dim&) { return true; }
bool NullPipe::setPosition(const utils::Dim&) { return true; }
bool NullPipe::setParameter(const utils::Params&) { return true; }
bool NullPipe::setSource(const utils::PipeArgs&) { return true; }
bool NullPipe::queueBuffer(uint32_t offset) { return true; }
bool NullPipe::dequeueBuffer(void*&) { return true; }
bool NullPipe::waitForVsync() { return true; }
void NullPipe::setMemoryId(int) {}
// NullPipe will return by val here as opposed to other Pipes.
utils::PipeArgs NullPipe::getArgs() const { return utils::PipeArgs(); }
utils::eOverlayPipeType NullPipe::getOvPipeType() const {
return utils::OV_PIPE_TYPE_NULL;
}
void NullPipe::dump() const {
ALOGE("== NullPipe (null) start/end ==");
}
} // overlay

103
liboverlay/overlay.h Normal file
View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OVERLAY_H
#define OVERLAY_H
#include "overlayUtils.h"
#include "overlayState.h"
#include "overlayImpl.h"
namespace overlay {
/**/
class Overlay : utils::NoCopy {
public:
/* dtor close */
~Overlay();
/* Overlay related func */
/* We need an empty open to just open the bare minimum for
* business. */
bool open();
/* close rotator, state, overlayimpl*/
bool close();
/* Following is the same as the pure virt interface in ov impl */
bool commit(utils::eDest dest = utils::OV_PIPE_ALL);
bool queueBuffer(uint32_t offset,
utils::eDest dest = utils::OV_PIPE_ALL);
bool dequeueBuffer(void*& buf,
utils::eDest dest = utils::OV_PIPE_ALL);
bool waitForVsync(utils::eDest dest = utils::OV_PIPE1);
bool setCrop(const utils::Dim& d,
utils::eDest dest = utils::OV_PIPE_ALL);
bool setPosition(const utils::Dim& dim,
utils::eDest dest = utils::OV_PIPE_ALL);
bool setParameter(const utils::Params& param,
utils::eDest dest = utils::OV_PIPE_ALL);
bool setSource(const utils::PipeArgs args[utils::MAX_PIPES],
utils::eDest dest = utils::OV_PIPE_ALL);
void setMemoryId(int id, utils::eDest dest = utils::OV_PIPE_ALL);
void dump() const;
/* state related functions */
void setState(utils::eOverlayState s);
/* expose state */
utils::eOverlayState getState() const;
/* Returns the singleton instance of overlay */
static Overlay* getInstance();
private:
/* Ctor setup */
Overlay();
/* reset all pointers */
void reset();
/* Holds the state, state transition logic
* In the meantime, using simple enum rather than
* a class */
OverlayState mState;
/* Holds the actual overlay impl, set when changing state*/
OverlayImplBase *mOv;
/* Singleton Instance*/
static Overlay *sInstance;
};
} // overlay
#endif // OVERLAY_H

349
liboverlay/overlayCtrl.cpp Normal file
View File

@ -0,0 +1,349 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <cutils/properties.h>
#include "overlayCtrlData.h"
#include "fb_priv.h"
namespace overlay{
bool Ctrl::open(uint32_t fbnum,
RotatorBase* rot) {
// MDP/FD open
if(!mMdp.open(fbnum)) {
ALOGE("Ctrl failed to open fbnum=%d", fbnum);
return false;
}
if(!getScreenInfo(mInfo)) {
ALOGE("Ctrl failed to getScreenInfo");
return false;
}
OVASSERT(rot, "rot is null");
mRot = rot;
// rot should be already opened
return true;
}
bool Ctrl::start(const utils::PipeArgs& args)
{
int colorFormat = utils::getColorFormat(args.whf.format);
utils::eMdpFlags flags = args.mdpFlags;
//XXX: Support for interlaced content
if (0) {
setMdpFlags(flags, utils::OV_MDP_DEINTERLACE);
// Get the actual format
colorFormat = args.whf.format ^ HAL_PIXEL_FORMAT_INTERLACE;
}
utils::Whf hwwhf(args.whf);
int fmt = utils::getMdpFormat(colorFormat);
// FIXME format should probably be int and not uint
if (fmt < 0) {
ALOGE("Ctrl failed getMdpFormat unsopported "
"colorFormat=%d format=%d flags=%d",
colorFormat, fmt, flags);
return false;
}
hwwhf.format = fmt;
// devices should be already opened
// (by calling open earlier in the flow)
const utils::PipeArgs newargs(flags, // mdp flags
args.orientation, // trans
hwwhf,
args.wait,
args.zorder,
args.isFg,
args.rotFlags);
if (!setInfo(newargs)) {
ALOGE("Ctrl failed to setInfo mdpflags=%d wait=%d zorder=%d",
newargs.mdpFlags, newargs.wait, newargs.zorder);
hwwhf.dump();
return false;
}
// FIXME, can we remove that and have it in
// setSource only when source changed?
if(!mRot->start(newargs)) {
ALOGE("Ctrl failed to start Rotation session");
return false;
}
// if geom is different, we need to prepare a new rot buffers.
// remap on demand when the current orientation is 90,180, etc.
// and the prev orientation was 0. It means we go from orient
if(!mRot->remap(utils::ROT_NUM_BUFS, newargs)) {
ALOGE("%s Error in remapping", __FUNCTION__);
}
if(!mMdp.set()) {
ALOGE("Ctrl start failed set overlay");
return false;
}
// cache the src to be the current mCrop vals
mCrop.w = hwwhf.w;
mCrop.h = hwwhf.h;
return true;
}
inline void Ctrl::updateSource(RotatorBase* r,
const utils::PipeArgs& args,
utils::ScreenInfo& info)
{
mMdp.updateSource(r, args, info);
}
bool Ctrl::setSource(const utils::PipeArgs& args)
{
mMdp.setWait(args.wait);
utils::PipeArgs newargs(args);
utils::Whf whf(args.whf);
// check geom change
if(mOvBufInfo != whf) {
// whf.format is given as HAL, that is why it is
// needed to be MDP fmt.
whf.format = utils::getColorFormat(whf.format);
int fmt = utils::getMdpFormat(whf.format);
OVASSERT(-1 != fmt, "Ctrl setSource format is -1");
whf.format = fmt;
newargs.whf = whf;
updateSource(mRot, newargs, mInfo);
mMdp.setUserData(0);
if(!mRot->start(newargs)) {
ALOGE("%s failed start rot", __FUNCTION__);
return false;
}
// if geom is different, we need to prepare a new rot buffers.
// remap on demand when the current orientation is 90,180, etc.
// and the prev orientation was 0. It means we go from orient
if(!mRot->remap(utils::ROT_NUM_BUFS, newargs)) {
ALOGE("%s Error in remapping", __FUNCTION__);
}
}
// needed for setSource
mOrient = args.orientation;
// cache last whf from gralloc hnd
mOvBufInfo = args.whf;
// orign impl is returning false here
// because they will close the overlay and reopen it.
// New design would not do that.
return true;
}
bool Ctrl::setPosition(const utils::Dim& dim)
{
if(!dim.check(mInfo.mFBWidth, mInfo.mFBHeight)) {
ALOGE("Ctrl setPosition error in dim");
dim.dump();
return false;
}
if(!mMdp.setPosition(dim, mInfo.mFBWidth, mInfo.mFBHeight)) {
ALOGE("Ctrl failed MDP setPosition");
return false;
}
return true;
}
bool Ctrl::setParameter(const utils::Params& p)
{
if (utils::OVERLAY_TRANSFORM == p.param &&
p.value == mMdp.getUserData()) {
// nothing to do here
return true;
}
utils::eTransform trns = static_cast<utils::eTransform>(p.value);
switch (p.param) {
case utils::OVERLAY_DITHER:
// nothing here today
ALOGE("Ctrl setParameter OVERLAY_DITHER not impl");
return true;
case utils::OVERLAY_TRANSFORM:
if(!mRot->overlayTransform(mMdp, trns)) {
ALOGE("Ctrl setParameter failed Rot overlayTransform");
return false;
}
break;
default:
ALOGE("Ctrl setParameter unknown param %d", p.param);
return false;
}
return true;
}
bool Ctrl::setCrop(const utils::Dim& d)
{
// FIXME check channel validity
if(!mMdp.setCrop(d)) {
ALOGE("Data setCrop failed in MDP setCrop");
return false;
}
mCrop = d;
return true;
}
utils::Dim Ctrl::getAspectRatio(const utils::Whf& whf) const
{
utils::Whf inWhf(whf.w, whf.h, mMdp.getSrcWhf().format);
utils::Whf tmpwhf(inWhf);
uint32_t fbWidth = mInfo.mFBWidth;
uint32_t fbHeight = mInfo.mFBHeight;
/* Calculate the width and height if it is YUV TILE format*/
if (inWhf.format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED) {
tmpwhf.w = whf.w - (utils::alignup(whf.w, 64) - whf.w);
tmpwhf.h = whf.h - (utils::alignup(whf.h, 32) - whf.h);
}
if (inWhf.w * fbHeight > fbWidth * inWhf.h) {
inWhf.h = fbWidth * inWhf.h / inWhf.w;
utils::even_out(inWhf.h);
inWhf.w = fbWidth;
} else if (inWhf.w * fbHeight < fbWidth * inWhf.h) {
inWhf.w = fbHeight * inWhf.w / inWhf.h;
utils::even_out(inWhf.w);
inWhf.h = fbHeight;
} else {
inWhf.w = fbWidth;
inWhf.h = fbHeight;
}
/* Scaling of upto a max of 8 times supported */
if (inWhf.w > (tmpwhf.w * utils::HW_OV_MAGNIFICATION_LIMIT)){
inWhf.w = utils::HW_OV_MAGNIFICATION_LIMIT * tmpwhf.w;
}
if(inWhf.h > (tmpwhf.h * utils::HW_OV_MAGNIFICATION_LIMIT)) {
inWhf.h = utils::HW_OV_MAGNIFICATION_LIMIT * tmpwhf.h;
}
if (inWhf.w > fbWidth) inWhf.w = fbWidth;
if (inWhf.h > fbHeight) inWhf.h = fbHeight;
char value[PROPERTY_VALUE_MAX];
property_get("hw.actionsafe.width", value, "0");
float asWidth = atof(value);
property_get("hw.actionsafe.height", value, "0");
float asHeight = atof(value);
inWhf.w = inWhf.w * (1.0f - asWidth / 100.0f);
inWhf.h = inWhf.h * (1.0f - asHeight / 100.0f);
uint32_t x = (fbWidth - inWhf.w) / 2.0;
uint32_t y = (fbHeight - inWhf.h) / 2.0;
return utils::Dim(x, y, inWhf.w, inWhf.h);
}
utils::FrameBufferInfo* utils::FrameBufferInfo::sFBInfoInstance = 0;
// This function gets the destination position for external display
// based on the position and aspect ratio of the primary
utils::Dim Ctrl::getAspectRatio(const utils::Dim& dim) const {
float priWidth = utils::FrameBufferInfo::getInstance()->getWidth();
float priHeight = utils::FrameBufferInfo::getInstance()->getHeight();
float fbWidth = mInfo.mFBWidth;
float fbHeight = mInfo.mFBHeight;
float wRatio = 1.0;
float hRatio = 1.0;
float xRatio = 1.0;
float yRatio = 1.0;
utils::Dim inDim(dim);
int xPos = 0;
int yPos = 0;
int tmp = 0;
utils::Dim tmpDim;
switch(inDim.o) {
case MDP_ROT_NOP:
case MDP_ROT_180:
{
utils::Whf whf((uint32_t) priWidth, (uint32_t) priHeight, 0);
tmpDim = getAspectRatio(whf);
xPos = tmpDim.x;
yPos = tmpDim.y;
fbWidth = tmpDim.w;
fbHeight = tmpDim.h;
if (inDim.o == MDP_ROT_180) {
inDim.x = priWidth - (inDim.x + inDim.w);
inDim.y = priHeight - (inDim.y + inDim.h);
}
break;
}
case MDP_ROT_90:
case MDP_ROT_270:
{
if(inDim.o == MDP_ROT_90) {
tmp = inDim.y;
inDim.y = priWidth - (inDim.x + inDim.w);
inDim.x = tmp;
}
else if (inDim.o == MDP_ROT_270) {
tmp = inDim.x;
inDim.x = priHeight - (inDim.y + inDim.h);
inDim.y = tmp;
}
// Swap the destination width/height
utils::swapWidthHeight(inDim.w, inDim.h);
// Swap width/height for primary
utils::swapWidthHeight(priWidth, priHeight);
utils::Whf whf((uint32_t) priWidth, (uint32_t) priHeight, 0);
tmpDim = getAspectRatio(whf);
xPos = tmpDim.x;
yPos = tmpDim.y;
fbWidth = tmpDim.w;
fbHeight = tmpDim.h;
break;
}
default:
ALOGE("%s: Unknown Orientation", __FUNCTION__);
break;
}
// Calculate the position
xRatio = inDim.x/priWidth;
yRatio = inDim.y/priHeight;
wRatio = inDim.w/priWidth;
hRatio = inDim.h/priHeight;
return utils::Dim((xRatio * fbWidth) + xPos, // x
(yRatio * fbHeight) + yPos, // y
(wRatio * fbWidth), // width
(hRatio * fbHeight), // height
inDim.o); // orientation
}
void Ctrl::dump() const {
ALOGE("== Dump Ctrl start ==");
ALOGE("orient=%d", mOrient);
mInfo.dump("mInfo");
mMdp.dump();
mRot->dump();
ALOGE("== Dump Ctrl end ==");
}
} // overlay

View File

@ -0,0 +1,365 @@
/*
* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OVERLAY_CTRLDATA_H
#define OVERLAY_CTRLDATA_H
#include "overlayUtils.h"
#include "overlayMdp.h"
#include "gralloc_priv.h" // INTERLACE_MASK
namespace ovutils = overlay::utils;
namespace overlay {
// FIXME make int to be uint32 whenever possible
class RotatorBase;
/*
* FIXME do we want rot to be template parameter?
* It's already using inheritance...
*
* Sequence to use:
* open
* start
* setXXX
* close
*
* Can call setRot anytime to replace rotator on-the-fly
* */
class Ctrl : utils::NoCopy {
public:
/* ctor */
explicit Ctrl();
/* dtor close */
~Ctrl();
/* should open devices? or start()? */
bool open(uint32_t fbnum, RotatorBase* rot);
/* close underlying mdp */
bool close();
/* Invoke methods for opening underlying devices
* flags - PIPE SHARED
* wait - WAIT, NO_WAIT */
bool start(const utils::PipeArgs& args);
/* Dynamically set rotator*/
void setRot(RotatorBase* rot);
/* set mdp posision using dim */
bool setPosition(const utils::Dim& dim);
/* set param using Params (param,value pair) */
bool setParameter(const utils::Params& p);
/* set source using whf, orient and wait flag */
bool setSource(const utils::PipeArgs& args);
/* set crop info and pass it down to mdp */
bool setCrop(const utils::Dim& d);
/* mdp set overlay/commit changes */
bool commit();
/* ctrl id */
int getId() const;
/* ctrl fd */
int getFd() const;
bool getRotSessId(int& id) const;
utils::Dim getAspectRatio(const utils::Whf& whf) const;
utils::Dim getAspectRatio(const utils::Dim& dim) const;
/* access for screen info */
utils::ScreenInfo getScreenInfo() const;
/* retrieve cached crop data */
utils::Dim getCrop() const;
/* dump the state of the object */
void dump() const;
private:
/* Retrieve screen info from underlying mdp */
bool getScreenInfo(utils::ScreenInfo& info);
/* calls underlying mdp set info */
bool setInfo(const utils::PipeArgs& args);
/* given whf, update src */
void updateSource(RotatorBase* r,
const utils::PipeArgs& args,
utils::ScreenInfo& info);
// mdp ctrl struct(info e.g.)
MdpCtrl mMdp;
// Rotator
RotatorBase* mRot;
/* Cache cropped value */
utils::Dim mCrop;
/* Screen info */
utils::ScreenInfo mInfo;
/* orientation cache FIXME */
utils::eTransform mOrient;
/* Cache last known whfz.
* That would help us compare to a previous
* source that was submitted */
utils::Whf mOvBufInfo;
};
/*
* MDP = DataMdp, ROT = CtrlMdp usually since Rotator<>
* is instansiated with Ctrl data structure.
* */
class Data : utils::NoCopy {
public:
/* init, reset */
explicit Data();
/* calls close */
~Data();
/* should open devices? or start()? */
bool open(uint32_t fbnum, RotatorBase* rot);
/* calls underlying mdp close */
bool close();
/* set the rotator */
void setRot(RotatorBase* rot);
/* set memory id in the mdp struct */
void setMemoryId(int id);
/* set overlay id in the mdp struct */
void setId(int id);
/* get overlay id in the mdp struct */
int getId() const;
/* queue buffer to the overlay */
bool queueBuffer(uint32_t offset);
/* wait for vsync to be done */
bool waitForVsync();
/* sump the state of the obj */
void dump() const;
private:
/* play wrapper */
bool play();
/* playWait wrapper */
bool playWait();
// mdp data struct
MdpData mMdp;
// Rotator
RotatorBase* mRot;
};
/* This class just creates a Ctrl Data pair to be used by a pipe.
* Although this was legacy design, this separation still makes sense, since we
* need to use the Ctrl channel in hwc_prepare (i.e config stage) and Data
* channel in hwc_set (i.e draw stage)
*/
struct CtrlData {
Ctrl ctrl;
Data data;
};
//-------------Inlines-------------------------------
inline Ctrl::Ctrl() : mRot(0), mOrient(utils::OVERLAY_TRANSFORM_0) {
mMdp.reset();
}
inline Ctrl::~Ctrl() {
close();
}
inline bool Ctrl::close() {
// do not close the rotator
if(!mMdp.close())
return false;
return true;
}
inline bool Ctrl::commit() {
if(!mMdp.set()) {
ALOGE("Ctrl commit failed set overlay");
return false;
}
return true;
}
inline bool Ctrl::getScreenInfo(utils::ScreenInfo& info) {
if(!mMdp.getScreenInfo(info)){
ALOGE("Ctrl failed to get screen info");
return false;
}
return true;
}
inline bool Ctrl::setInfo(const utils::PipeArgs& args)
{
// FIXME set flags, zorder and wait separtly
if(!mMdp.setInfo(mRot, args, mInfo)){
ALOGE("Ctrl failed to setInfo wait=%d mdpflags=%d "
"zorder=%d", args.wait, args.mdpFlags, args.zorder);
return false;
}
return true;
}
inline int Ctrl::getId() const {
// FIXME check channel up?
return mMdp.getId();
}
inline int Ctrl::getFd() const {
// FIXME check channel up?
return mMdp.getFd();
}
inline bool Ctrl::getRotSessId(int& id) const {
// FIXME check channel up?
// should be -1 in case of no rot session active
id = mRot->getSessId();
return true;
}
inline utils::ScreenInfo Ctrl::getScreenInfo() const {
return mInfo;
}
inline utils::Dim Ctrl::getCrop() const {
return mCrop;
}
inline Data::Data() : mRot(0) {
mMdp.reset();
}
inline Data::~Data() { close(); }
inline void Data::setRot(RotatorBase* rot) { mRot = rot; }
inline void Data::setMemoryId(int id) { mMdp.setMemoryId(id); }
// really a reqid
inline void Data::setId(int id) { mMdp.setId(id); }
inline int Data::getId() const { return mMdp.getId(); }
inline bool Data::open(uint32_t fbnum,
RotatorBase* rot) {
if(!mMdp.open(fbnum)) {
ALOGE("Data cannot open mdp");
return false;
}
OVASSERT(rot, "rot is null");
mRot = rot;
// rotator should be already opened here
return true;
}
inline bool Data::close() {
if(!mMdp.close()) {
ALOGE("Data close failed");
return false;
}
return true;
}
inline bool Data::queueBuffer(uint32_t offset) {
// FIXME asserts on state validity
mMdp.setOffset(offset);
mRot->setRotDataSrcMemId(mMdp.getMemoryId());
// will play if succeeded
if(!mRot->prepareQueueBuf(offset)) {
ALOGE("Data failed to prepareQueueBuf");
return false;
}
// Play can go either from mdp or rot
if(!this->play()){
ALOGE("Data error in MDP/ROT play");
return false;
}
return true;
}
inline bool Data::waitForVsync() {
// Call mdp playWait
if(!this->playWait()){
ALOGE("Error in MDP playWait");
return false;
}
return true;
}
inline bool Data::play() {
int fd = mMdp.getFd();
return mRot->enabled() ? mRot->play(fd) : mMdp.play();
}
inline bool Data::playWait() {
return mMdp.playWait();
}
inline void Data::dump() const {
ALOGE("== Dump Data MDP start ==");
mMdp.dump();
mRot->dump();
ALOGE("== Dump Data MDP end ==");
}
} // overlay
#endif

742
liboverlay/overlayImpl.h Normal file
View File

@ -0,0 +1,742 @@
/*
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OVERLAY_IMPL_H
#define OVERLAY_IMPL_H
#include "overlayUtils.h"
#include "overlayRotator.h"
// FIXME make int to be uint32 whenever possible
namespace overlay {
// Interface only. No member, no definiton (except ~ which can
// also be =0 with impl in cpp)
class OverlayImplBase {
public:
/* empty dtor. can be =0 with cpp impl*/
virtual ~OverlayImplBase() {}
/* Open pipe/rot for one dest */
virtual bool openPipe(RotatorBase* rot, utils::eDest dest) = 0;
/* Close pipe/rot for all specified dest */
virtual bool closePipe(utils::eDest dest) = 0;
/* Copy specified pipe/rot from ov passed in (used by state machine only) */
virtual bool copyOvPipe(OverlayImplBase* ov, utils::eDest dest) = 0;
/* TODO open func customized for RGBx pipes */
/* Open all pipes
* To open just one pipe, use openPipe()
* */
virtual bool open(RotatorBase* rot0,
RotatorBase* rot1,
RotatorBase* rot2) = 0;
/* Close all pipes
* To close just one pipe, use closePipe()
* */
virtual bool close() = 0;
/*
* Commit changes to the overlay
* */
virtual bool commit(utils::eDest dest = utils::OV_PIPE_ALL) = 0;
/* Queue buffer with offset*/
virtual bool queueBuffer(uint32_t offset,
utils::eDest dest = utils::OV_PIPE_ALL) = 0;
/* For RGBx pipes, dequeue buffer (that is fb chunk)*/
virtual bool dequeueBuffer(void*& buf,
utils::eDest dest = utils::OV_PIPE_ALL) = 0;
/* Wait for vsync to be done on dest */
virtual bool waitForVsync(utils::eDest dest = utils::OV_PIPE1) = 0;
/* Crop existing destination using Dim coordinates */
virtual bool setCrop(const utils::Dim& d,
utils::eDest dest = utils::OV_PIPE_ALL) = 0;
/* Set new position using Dim */
virtual bool setPosition(const utils::Dim& dim,
utils::eDest dest = utils::OV_PIPE_ALL) = 0;
/* Set parameters - usually needed for Rotator, but would
* be passed down the stack as well */
virtual bool setParameter(const utils::Params& param,
utils::eDest dest = utils::OV_PIPE_ALL) = 0;
/* Set new source including orientation */
virtual bool setSource(const utils::PipeArgs[utils::MAX_PIPES],
utils::eDest dest = utils::OV_PIPE_ALL) = 0;
/* set memory id to the underlying pipes */
virtual void setMemoryId(int id, utils::eDest dest = utils::OV_PIPE_ALL) = 0;
/* Get the overlay pipe type */
virtual utils::eOverlayPipeType getOvPipeType(utils::eDest dest) const = 0;
/* Dump underlying state */
virtual void dump() const = 0;
};
class NullPipe {
public:
/* TODO open func customized for RGBx pipes */
bool open(RotatorBase* rot);
bool close();
bool start(const utils::PipeArgs& args);
bool commit();
bool setCrop(const utils::Dim& d);
bool setPosition(const utils::Dim& dim);
bool setParameter(const utils::Params& param);
bool setSource(const utils::PipeArgs& args);
bool queueBuffer(uint32_t offset);
bool dequeueBuffer(void*& buf);
bool waitForVsync();
void setMemoryId(int id);
utils::PipeArgs getArgs() const;
utils::eOverlayPipeType getOvPipeType() const;
void dump() const;
};
/*
* Each pipe is not specific to a display (primary/external). The order in the
* template params, will setup the priorities of the pipes.
* */
template <class P0, class P1=NullPipe, class P2=NullPipe>
class OverlayImpl : public OverlayImplBase {
public:
typedef P0 pipe0;
typedef P1 pipe1;
typedef P2 pipe2;
/* ctor */
OverlayImpl();
OverlayImpl(P0* p0, P1* p1, P2* p2);
/*
* Comments of the below functions are the same as the one
* in OverlayImplBase.
* */
virtual ~OverlayImpl();
virtual bool openPipe(RotatorBase* rot, utils::eDest dest);
virtual bool closePipe(utils::eDest dest);
virtual bool copyOvPipe(OverlayImplBase* ov, utils::eDest dest);
/* TODO open func customized for RGBx pipes */
virtual bool open(RotatorBase* rot0,
RotatorBase* rot1,
RotatorBase* rot2);
virtual bool close();
virtual bool commit(utils::eDest dest = utils::OV_PIPE_ALL);
virtual bool setCrop(const utils::Dim& d,
utils::eDest dest = utils::OV_PIPE_ALL);
virtual bool setPosition(const utils::Dim& dim,
utils::eDest dest = utils::OV_PIPE_ALL);
virtual bool setParameter(const utils::Params& param,
utils::eDest dest = utils::OV_PIPE_ALL);
virtual bool setSource(const utils::PipeArgs[utils::MAX_PIPES],
utils::eDest dest = utils::OV_PIPE_ALL);
virtual bool queueBuffer(uint32_t offset,
utils::eDest dest = utils::OV_PIPE_ALL);
virtual bool dequeueBuffer(void*& buf,
utils::eDest dest = utils::OV_PIPE_ALL);
virtual bool waitForVsync(utils::eDest dest = utils::OV_PIPE1);
virtual void setMemoryId(int id, utils::eDest dest = utils::OV_PIPE_ALL);
virtual utils::eOverlayPipeType getOvPipeType(utils::eDest dest) const;
virtual void dump() const;
private:
P0* mPipe0;
P1* mPipe1;
P2* mPipe2;
// More Px here in the future as needed
/* */
/* Each Px has it's own Rotator here.
* will pass rotator to the lower layer in stack
* but only overlay is allowed to control the lifetime
* of the rotator instace */
RotatorBase* mRotP0;
RotatorBase* mRotP1;
RotatorBase* mRotP2;
};
//-----------Inlines and Template defn---------------------------------
template <class P0, class P1, class P2>
OverlayImpl<P0, P1, P2>::OverlayImpl() :
mPipe0(new P0), mPipe1(new P1), mPipe2(new P2),
mRotP0(0), mRotP1(0), mRotP2(0)
{}
template <class P0, class P1, class P2>
OverlayImpl<P0, P1, P2>::OverlayImpl(P0* p0, P1* p1, P2* p2) :
mPipe0(p0), mPipe1(p1), mPipe2(p2),
mRotP0(0), mRotP1(0), mRotP2(0)
{}
template <class P0, class P1, class P2>
OverlayImpl<P0, P1, P2>::~OverlayImpl()
{
// no op in the meantime. needed to be clean
// since state machine will do delete. so we
// do not want to close/delete pipes here
}
/* Open only one pipe/rot pair per call */
template <class P0, class P1, class P2>
bool OverlayImpl<P0, P1, P2>::openPipe(RotatorBase* rot, utils::eDest dest)
{
OVASSERT(rot, "%s: OverlayImpl rot is null", __FUNCTION__);
OVASSERT(utils::isValidDest(dest), "%s: OverlayImpl invalid dest=%d",
__FUNCTION__, dest);
// Need to down case rotator to mdp one.
// we assume p0/p1/p2/px all use the _same_ underlying mdp structure.
// FIXME STATIC_ASSERT here
bool ret = true;
if (utils::OV_PIPE0 & dest) {
OVASSERT(mPipe0, "%s: OverlayImpl pipe0 is null", __FUNCTION__);
ALOGE_IF(DEBUG_OVERLAY, "Open pipe0");
ret = mPipe0->open(rot);
mRotP0 = rot;
if(!ret) {
ALOGE("%s: OverlayImpl pipe0 failed to open", __FUNCTION__);
}
return ret;
}
if (utils::OV_PIPE1 & dest) {
OVASSERT(mPipe1, "%s: OverlayImpl pipe1 is null", __FUNCTION__);
ALOGE_IF(DEBUG_OVERLAY, "Open pipe1");
ret = mPipe1->open(rot);
mRotP1 = rot;
if(!ret) {
ALOGE("%s: OverlayImpl pipe1 failed to open", __FUNCTION__);
}
return ret;
}
if (utils::OV_PIPE2 & dest) {
OVASSERT(mPipe2, "%s: OverlayImpl pipe2 is null", __FUNCTION__);
ALOGE_IF(DEBUG_OVERLAY, "Open pipe2");
ret = mPipe2->open(rot);
mRotP2 = rot;
if(!ret) {
ALOGE("%s: OverlayImpl pipe2 failed to open", __FUNCTION__);
}
return ret;
}
// Should have returned by here
return false;
}
/* Close pipe/rot for all specified dest */
template <class P0, class P1, class P2>
bool OverlayImpl<P0, P1, P2>::closePipe(utils::eDest dest)
{
OVASSERT(utils::isValidDest(dest), "%s: OverlayImpl invalid dest=%d",
__FUNCTION__, dest);
if (utils::OV_PIPE0 & dest) {
// Close pipe0
OVASSERT(mPipe0, "%s: OverlayImpl pipe0 is null", __FUNCTION__);
ALOGE_IF(DEBUG_OVERLAY, "Close pipe0");
if (!mPipe0->close()) {
ALOGE("%s: OverlayImpl failed to close pipe0", __FUNCTION__);
return false;
}
delete mPipe0;
mPipe0 = 0;
// Close the rotator for pipe0
OVASSERT(mRotP0, "%s: OverlayImpl rot0 is null", __FUNCTION__);
if (!mRotP0->close()) {
ALOGE("%s: OverlayImpl failed to close rot for pipe0", __FUNCTION__);
}
delete mRotP0;
mRotP0 = 0;
}
if (utils::OV_PIPE1 & dest) {
// Close pipe1
OVASSERT(mPipe1, "%s: OverlayImpl pipe1 is null", __FUNCTION__);
ALOGE_IF(DEBUG_OVERLAY, "Close pipe1");
if (!mPipe1->close()) {
ALOGE("%s: OverlayImpl failed to close pipe1", __FUNCTION__);
return false;
}
delete mPipe1;
mPipe1 = 0;
// Close the rotator for pipe1
OVASSERT(mRotP1, "%s: OverlayImpl rot1 is null", __FUNCTION__);
if (!mRotP1->close()) {
ALOGE("%s: OverlayImpl failed to close rot for pipe1", __FUNCTION__);
}
delete mRotP1;
mRotP1 = 0;
}
if (utils::OV_PIPE2 & dest) {
// Close pipe2
OVASSERT(mPipe2, "%s: OverlayImpl pipe2 is null", __FUNCTION__);
ALOGE_IF(DEBUG_OVERLAY, "Close pipe2");
if (!mPipe2->close()) {
ALOGE("%s: OverlayImpl failed to close pipe2", __FUNCTION__);
return false;
}
delete mPipe2;
mPipe2 = 0;
// Close the rotator for pipe2
OVASSERT(mRotP2, "%s: OverlayImpl rot2 is null", __FUNCTION__);
if (!mRotP2->close()) {
ALOGE("%s: OverlayImpl failed to close rot for pipe2", __FUNCTION__);
}
delete mRotP2;
mRotP2 = 0;
}
return true;
}
/* Copy pipe/rot from ov for all specified dest */
template <class P0, class P1, class P2>
bool OverlayImpl<P0, P1, P2>::copyOvPipe(OverlayImplBase* ov,
utils::eDest dest)
{
OVASSERT(ov, "%s: OverlayImpl ov is null", __FUNCTION__);
OVASSERT(utils::isValidDest(dest), "%s: OverlayImpl invalid dest=%d",
__FUNCTION__, dest);
OverlayImpl<P0, P1, P2>* ovimpl = static_cast<OverlayImpl<P0, P1, P2>*>(ov);
if (utils::OV_PIPE0 & dest) {
mPipe0 = ovimpl->mPipe0;
mRotP0 = ovimpl->mRotP0;
}
if (utils::OV_PIPE1 & dest) {
mPipe1 = ovimpl->mPipe1;
mRotP1 = ovimpl->mRotP1;
}
if (utils::OV_PIPE2 & dest) {
mPipe2 = ovimpl->mPipe2;
mRotP2 = ovimpl->mRotP2;
}
return true;
}
/* TODO open func customized for RGBx pipes */
/* Open all pipes/rot */
template <class P0, class P1, class P2>
bool OverlayImpl<P0, P1, P2>::open(RotatorBase* rot0,
RotatorBase* rot1,
RotatorBase* rot2)
{
if (!this->openPipe(rot0, utils::OV_PIPE0)) {
if (!this->close()) {
ALOGE("%s: failed to close at least one pipe", __FUNCTION__);
}
return false;
}
if (!this->openPipe(rot1, utils::OV_PIPE1)) {
if (!this->close()) {
ALOGE("%s: failed to close at least one pipe", __FUNCTION__);
}
return false;
}
if (!this->openPipe(rot2, utils::OV_PIPE2)) {
if (!this->close()) {
ALOGE("%s: failed to close at least one pipe", __FUNCTION__);
}
return false;
}
return true;
}
/* Close all pipes/rot */
template <class P0, class P1, class P2>
bool OverlayImpl<P0, P1, P2>::close()
{
if (!this->closePipe(utils::OV_PIPE_ALL)) {
return false;
}
return true;
}
template <class P0, class P1, class P2>
bool OverlayImpl<P0, P1, P2>::commit(utils::eDest dest)
{
OVASSERT(mPipe0 && mPipe1 && mPipe2,
"%s: Pipes are null p0=%p p1=%p p2=%p",
__FUNCTION__, mPipe0, mPipe1, mPipe2);
if (utils::OV_PIPE0 & dest) {
if(!mPipe0->commit()) {
ALOGE("OverlayImpl p0 failed to commit");
return false;
}
}
if (utils::OV_PIPE1 & dest) {
if(!mPipe1->commit()) {
ALOGE("OverlayImpl p1 failed to commit");
return false;
}
}
if (utils::OV_PIPE2 & dest) {
if(!mPipe2->commit()) {
ALOGE("OverlayImpl p2 failed to commit");
return false;
}
}
return true;
}
template <class P0, class P1, class P2>
bool OverlayImpl<P0, P1, P2>::setCrop(const utils::Dim& d, utils::eDest dest)
{
OVASSERT(mPipe0 && mPipe1 && mPipe2,
"%s: Pipes are null p0=%p p1=%p p2=%p",
__FUNCTION__, mPipe0, mPipe1, mPipe2);
if (utils::OV_PIPE0 & dest) {
if(!mPipe0->setCrop(d)) {
ALOGE("OverlayImpl p0 failed to crop");
return false;
}
}
if (utils::OV_PIPE1 & dest) {
if(!mPipe1->setCrop(d)) {
ALOGE("OverlayImpl p1 failed to crop");
return false;
}
}
if (utils::OV_PIPE2 & dest) {
if(!mPipe2->setCrop(d)) {
ALOGE("OverlayImpl p2 failed to crop");
return false;
}
}
return true;
}
template <class P0, class P1, class P2>
bool OverlayImpl<P0, P1, P2>::setPosition(const utils::Dim& d,
utils::eDest dest)
{
OVASSERT(mPipe0 && mPipe1 && mPipe2,
"%s: Pipes are null p0=%p p1=%p p2=%p",
__FUNCTION__, mPipe0, mPipe1, mPipe2);
if (utils::OV_PIPE0 & dest) {
if(!mPipe0->setPosition(d)) {
ALOGE("OverlayImpl p0 failed to setpos");
return false;
}
}
if (utils::OV_PIPE1 & dest) {
if(!mPipe1->setPosition(d)) {
ALOGE("OverlayImpl p1 failed to setpos");
return false;
}
}
if (utils::OV_PIPE2 & dest) {
if(!mPipe2->setPosition(d)) {
ALOGE("OverlayImpl p2 failed to setpos");
return false;
}
}
return true;
}
template <class P0, class P1, class P2>
bool OverlayImpl<P0, P1, P2>::setParameter(const utils::Params& param,
utils::eDest dest)
{
OVASSERT(mPipe0 && mPipe1 && mPipe2,
"%s: Pipes are null p0=%p p1=%p p2=%p",
__FUNCTION__, mPipe0, mPipe1, mPipe2);
if (utils::OV_PIPE0 & dest) {
if(!mPipe0->setParameter(param)) {
ALOGE("OverlayImpl p0 failed to setparam");
return false;
}
}
if (utils::OV_PIPE1 & dest) {
if(!mPipe1->setParameter(param)) {
ALOGE("OverlayImpl p1 failed to setparam");
return false;
}
}
if (utils::OV_PIPE2 & dest) {
if(!mPipe2->setParameter(param)) {
ALOGE("OverlayImpl p2 failed to setparam");
return false;
}
}
return true;
}
template <class P0, class P1, class P2>
bool OverlayImpl<P0, P1, P2>::setSource(const utils::PipeArgs args[utils::MAX_PIPES],
utils::eDest dest)
{
OVASSERT(mPipe0 && mPipe1 && mPipe2,
"%s: Pipes are null p0=%p p1=%p p2=%p",
__FUNCTION__, mPipe0, mPipe1, mPipe2);
if (utils::OV_PIPE0 & dest) {
if(!mPipe0->setSource(args[0])) {
ALOGE("OverlayImpl p0 failed to setsrc");
return false;
}
}
if (utils::OV_PIPE1 & dest) {
if(!mPipe1->setSource(args[1])) {
ALOGE("OverlayImpl p1 failed to setsrc");
return false;
}
}
if (utils::OV_PIPE2 & dest) {
if(!mPipe2->setSource(args[2])) {
ALOGE("OverlayImpl p2 failed to setsrc");
return false;
}
}
return true;
}
template <class P0, class P1, class P2>
bool OverlayImpl<P0, P1, P2>::queueBuffer(uint32_t offset, utils::eDest dest)
{
OVASSERT(mPipe0 && mPipe1 && mPipe2,
"%s: Pipes are null p0=%p p1=%p p2=%p",
__FUNCTION__, mPipe0, mPipe1, mPipe2);
if (utils::OV_PIPE0 & dest) {
if(!mPipe0->queueBuffer(offset)) {
ALOGE("OverlayImpl p0 failed to queueBuffer");
return false;
}
}
if (utils::OV_PIPE1 & dest) {
if(!mPipe1->queueBuffer(offset)) {
ALOGE("OverlayImpl p1 failed to queueBuffer");
return false;
}
}
if (utils::OV_PIPE2 & dest) {
if(!mPipe2->queueBuffer(offset)) {
ALOGE("OverlayImpl p2 failed to queueBuffer");
return false;
}
}
return true;
}
template <class P0, class P1, class P2>
bool OverlayImpl<P0, P1, P2>::dequeueBuffer(void*& buf, utils::eDest dest)
{
OVASSERT(mPipe0 && mPipe1 && mPipe2,
"%s: Pipes are null p0=%p p1=%p p2=%p",
__FUNCTION__, mPipe0, mPipe1, mPipe2);
if (utils::OV_PIPE0 & dest) {
if(!mPipe0->dequeueBuffer(buf)) {
ALOGE("OverlayImpl p0 failed to dequeueBuffer");
return false;
}
}
if (utils::OV_PIPE1 & dest) {
if(!mPipe1->dequeueBuffer(buf)) {
ALOGE("OverlayImpl p1 failed to dequeueBuffer");
return false;
}
}
if (utils::OV_PIPE2 & dest) {
if(!mPipe2->dequeueBuffer(buf)) {
ALOGE("OverlayImpl p2 failed to dequeueBuffer");
return false;
}
}
return true;
}
template <class P0, class P1, class P2>
bool OverlayImpl<P0, P1, P2>::waitForVsync(utils::eDest dest)
{
OVASSERT(mPipe0 && mPipe1 && mPipe2,
"%s: Pipes are null p0=%p p1=%p p2=%p",
__FUNCTION__, mPipe0, mPipe1, mPipe2);
if (utils::OV_PIPE0 & dest) {
if(!mPipe0->waitForVsync()) {
ALOGE("OverlayImpl p0 failed to waitForVsync");
return false;
}
}
if (utils::OV_PIPE1 & dest) {
if(!mPipe1->waitForVsync()) {
ALOGE("OverlayImpl p1 failed to waitForVsync");
return false;
}
}
if (utils::OV_PIPE2 & dest) {
if(!mPipe2->waitForVsync()) {
ALOGE("OverlayImpl p2 failed to waitForVsync");
return false;
}
}
return true;
}
template <class P0, class P1, class P2>
void OverlayImpl<P0, P1, P2>::setMemoryId(int id, utils::eDest dest)
{
OVASSERT(mPipe0 && mPipe1 && mPipe2,
"%s: Pipes are null p0=%p p1=%p p2=%p",
__FUNCTION__, mPipe0, mPipe1, mPipe2);
if (utils::OV_PIPE0 & dest) {
mPipe0->setMemoryId(id);
}
if (utils::OV_PIPE1 & dest) {
mPipe1->setMemoryId(id);
}
if (utils::OV_PIPE2 & dest) {
mPipe2->setMemoryId(id);
}
}
template <class P0, class P1, class P2>
utils::eOverlayPipeType OverlayImpl<P0, P1, P2>::getOvPipeType(utils::eDest dest) const
{
OVASSERT(utils::isValidDest(dest), "%s: OverlayImpl invalid dest=%d",
__FUNCTION__, dest);
if (utils::OV_PIPE0 & dest) {
OVASSERT(mPipe0, "%s: OverlayImpl pipe0 is null", __FUNCTION__);
return mPipe0->getOvPipeType();
}
if (utils::OV_PIPE1 & dest) {
OVASSERT(mPipe1, "%s: OverlayImpl pipe1 is null", __FUNCTION__);
return mPipe1->getOvPipeType();
}
if (utils::OV_PIPE2 & dest) {
OVASSERT(mPipe2, "%s: OverlayImpl pipe2 is null", __FUNCTION__);
return mPipe2->getOvPipeType();
}
// Should never get here
return utils::OV_PIPE_TYPE_NULL;
}
template <class P0, class P1, class P2>
void OverlayImpl<P0, P1, P2>::dump() const
{
OVASSERT(mPipe0 && mPipe1 && mPipe2,
"%s: Pipes are null p0=%p p1=%p p2=%p",
__FUNCTION__, mPipe0, mPipe1, mPipe2);
ALOGE("== Dump OverlayImpl dump start ROT p0 ==");
mRotP0->dump();
ALOGE("== Dump OverlayImpl dump end ROT p0 ==");
ALOGE("== Dump OverlayImpl dump start ROT p1 ==");
mRotP1->dump();
ALOGE("== Dump OverlayImpl dump end ROT p1 ==");
ALOGE("== Dump OverlayImpl dump start ROT p2 ==");
mRotP2->dump();
ALOGE("== Dump OverlayImpl dump end ROT p2 ==");
ALOGE("== Dump OverlayImpl dump start p0 ==");
mPipe0->dump();
ALOGE("== Dump OverlayImpl dump end p0 ==");
ALOGE("== Dump OverlayImpl dump start p1 ==");
mPipe1->dump();
ALOGE("== Dump OverlayImpl dump end p1 ==");
ALOGE("== Dump OverlayImpl dump start p2 ==");
mPipe2->dump();
ALOGE("== Dump OverlayImpl dump end p2 ==");
}
} // overlay
#endif // OVERLAY_IMPL_H

File diff suppressed because it is too large Load Diff

View File

@ -1,451 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef INCLUDE_OVERLAY_LIB
#define INCLUDE_OVERLAY_LIB
#include <cutils/log.h>
#include <cutils/properties.h>
#include <cutils/atomic.h>
#include <hardware/hardware.h>
#include <hardware/gralloc.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <linux/fb.h>
#include <linux/msm_mdp.h>
#include <linux/msm_rotator.h>
#include <linux/android_pmem.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <utils/threads.h>
#include <utils/RefBase.h>
#include <alloc_controller.h>
#include <memalloc.h>
#ifdef USES_POST_PROCESSING
#include "lib-postproc.h"
#endif
#define HW_OVERLAY_MAGNIFICATION_LIMIT 8
#define HW_OVERLAY_MINIFICATION_LIMIT HW_OVERLAY_MAGNIFICATION_LIMIT
#define EVEN_OUT(x) if (x & 0x0001) {x--;}
#define NO_PIPE -1
#define VG0_PIPE 0
#define VG1_PIPE 1
#define NUM_CHANNELS 2
#define NUM_FB_DEVICES 3
#define FRAMEBUFFER_0 0
#define FRAMEBUFFER_1 1
#define FRAMEBUFFER_2 2
#define NUM_SHARPNESS_VALS 256
#define SHARPNESS_RANGE 1.0f
#define HUE_RANGE 180
#define BRIGHTNESS_RANGE 255
#define CON_SAT_RANGE 1.0f
#define CAP_RANGE(value,max,min) do { if (value - min < -0.0001)\
{value = min;}\
else if(value - max > 0.0001)\
{value = max;}\
} while(0);
enum {
HDMI_OFF,
HDMI_ON
};
enum {
OVERLAY_CHANNEL_DOWN,
OVERLAY_CHANNEL_UP
};
enum {
NEW_REQUEST,
UPDATE_REQUEST
};
enum {
WAIT_FOR_VSYNC = 1<<0,
DISABLE_FRAMEBUFFER_FETCH = 1<<1,
INTERLACED_CONTENT = 1<<2,
OVERLAY_PIPE_SHARE = 1<<3,
SECURE_OVERLAY_SESSION = 1<<4,
};
/* ------------------------------- 3D defines ---------------------------------------*/
// The compound format passed to the overlay is
// ABCCC where A is the input 3D format,
// B is the output 3D format
// CCC is the color format e.g YCbCr420SP YCrCb420SP etc.
#define FORMAT_3D(x) (x & 0xFF000)
#define COLOR_FORMAT(x) (x & 0xFFF)
// in the final 3D format, the MSB 2Bytes are the input format and the
// LSB 2bytes are the output format. Shift the output byte 12 bits.
#define SHIFT_OUTPUT_3D 12
#define FORMAT_3D_OUTPUT(x) ((x & 0xF000) >> SHIFT_OUTPUT_3D)
#define FORMAT_3D_INPUT(x) (x & 0xF0000)
#define INPUT_MASK_3D 0xFFFF0000
#define OUTPUT_MASK_3D 0x0000FFFF
#define SHIFT_3D 16
// The output format is the 2MSB bytes. Shift the format by 12 to reflect this
#define HAL_3D_OUT_SIDE_BY_SIDE_MASK (HAL_3D_OUT_SIDE_BY_SIDE >> SHIFT_OUTPUT_3D)
#define HAL_3D_OUT_TOP_BOTTOM_MASK (HAL_3D_OUT_TOP_BOTTOM >> SHIFT_OUTPUT_3D)
#define HAL_3D_OUT_INTERLEAVE_MASK (HAL_3D_OUT_INTERLEAVE >> SHIFT_OUTPUT_3D)
#define HAL_3D_OUT_MONOSCOPIC_MASK (HAL_3D_OUT_MONOSCOPIC >> SHIFT_OUTPUT_3D)
// 3D panel barrier orientation
#define BARRIER_LANDSCAPE 1
#define BARRIER_PORTRAIT 2
#ifdef HDMI_AS_PRIMARY
#define FORMAT_3D_FILE "/sys/class/graphics/fb0/format_3d"
#define EDID_3D_INFO_FILE "/sys/class/graphics/fb0/3d_present"
#else
#define FORMAT_3D_FILE "/sys/class/graphics/fb1/format_3d"
#define EDID_3D_INFO_FILE "/sys/class/graphics/fb1/3d_present"
#endif
#define BARRIER_FILE "/sys/devices/platform/mipi_novatek.0/enable_3d_barrier"
/* -------------------------- end 3D defines ----------------------------------------*/
// Struct to hold the buffer info: geometry and size
struct overlay_buffer_info {
int width;
int height;
int format;
int size;
};
using android::Mutex;
namespace overlay {
#define FB_DEVICE_TEMPLATE "/dev/graphics/fb%u"
//Utility Class to query the framebuffer info
class FrameBufferInfo {
int mFBWidth;
int mFBHeight;
bool mBorderFillSupported;
static FrameBufferInfo *sFBInfoInstance;
FrameBufferInfo():mFBWidth(0),mFBHeight(0), mBorderFillSupported(false) {
char const * const device_name =
"/dev/graphics/fb0";
int fd = open(device_name, O_RDWR, 0);
mdp_overlay ov;
memset(&ov, 0, sizeof(ov));
if (fd < 0) {
LOGE("FrameBufferInfo: Cant open framebuffer ");
return;
}
fb_var_screeninfo vinfo;
if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
LOGE("FrameBufferInfo: FBIOGET_VSCREENINFO on fb0 failed");
close(fd);
fd = -1;
return;
}
ov.id = 1;
if(ioctl(fd, MSMFB_OVERLAY_GET, &ov)) {
LOGE("FrameBufferInfo: MSMFB_OVERLAY_GET on fb0 failed");
close(fd);
fd = -1;
return;
}
close(fd);
fd = -1;
mFBWidth = vinfo.xres;
mFBHeight = vinfo.yres;
mBorderFillSupported = (ov.flags & MDP_BORDERFILL_SUPPORTED) ?
true : false;
}
public:
static FrameBufferInfo* getInstance(){
if (!sFBInfoInstance){
sFBInfoInstance = new FrameBufferInfo;
}
return sFBInfoInstance;
}
int getWidth() const { return mFBWidth; }
int getHeight() const { return mFBHeight; }
bool canSupportTrueMirroring() const {
return mBorderFillSupported; }
};
enum {
OV_UI_MIRROR_TV = 0,
OV_2D_VIDEO_ON_PANEL,
OV_2D_VIDEO_ON_TV,
OV_3D_VIDEO_2D_PANEL,
OV_3D_VIDEO_2D_TV,
OV_3D_VIDEO_3D_PANEL,
OV_3D_VIDEO_3D_TV
};
bool isHDMIConnected();
bool is3DTV();
bool isPanel3D();
bool usePanel3D();
bool send3DInfoPacket(unsigned int format3D);
bool enableBarrier(unsigned int orientation);
unsigned int getOverlayConfig (unsigned int format3D, bool poll = true,
bool isHDMI = false);
int getColorFormat(int format);
bool isInterlacedContent(int format);
int get_mdp_format(int format);
int get_size(int format, int w, int h);
int get_rot_output_format(int format);
int get_mdp_orientation(int value);
void normalize_crop(uint32_t& xy, uint32_t& wh);
//Initializes the overlay - cleans up any existing overlay pipes
int initOverlay();
/* Print values being sent to driver in case of ioctl failures
These logs are enabled only if DEBUG_OVERLAY is true */
void dump(msm_rotator_img_info& mRotInfo);
void dump(mdp_overlay& mOvInfo);
const char* getFormatString(int format);
//singleton class to decide the z order of new overlay surfaces
class ZOrderManager {
bool mFB0Pipes[NUM_CHANNELS];
bool mFB1Pipes[NUM_CHANNELS+1]; //FB1 can have 3 pipes
int mPipesInuse; // Holds the number of pipes in use
int mMaxPipes; // Max number of pipes
static ZOrderManager *sInstance;
Mutex *mObjMutex;
ZOrderManager(){
mPipesInuse = 0;
// for true mirroring support there can be 3 pipes on secondary
mMaxPipes = FrameBufferInfo::getInstance()->canSupportTrueMirroring()?
NUM_CHANNELS+1 : NUM_CHANNELS;
for (int i = 0; i < NUM_CHANNELS; i++)
mFB0Pipes[i] = false;
for (int j = 0; j < mMaxPipes; j++)
mFB1Pipes[j] = false;
mObjMutex = new Mutex();
}
~ZOrderManager() {
delete sInstance;
delete mObjMutex;
}
public:
static ZOrderManager* getInstance(){
if (!sInstance){
sInstance = new ZOrderManager;
}
return sInstance;
}
int getZ(int fbnum);
void decZ(int fbnum, int zorder);
};
const int max_num_buffers = 3;
typedef struct mdp_rect overlay_rect;
class OverlayControlChannel {
enum {
SET_NONE = 0,
SET_SHARPNESS,
#ifdef USES_POST_PROCESSING
SET_HUE,
SET_BRIGHTNESS,
SET_SATURATION,
SET_CONTRAST,
#endif
RESET_ALL,
};
bool mNoRot;
int mFBNum;
int mFBWidth;
int mFBHeight;
int mFBbpp;
int mFBystride;
int mFormat;
int mFD;
int mRotFD;
int mSize;
int mOrientation;
unsigned int mFormat3D;
bool mUIChannel;
#ifdef USES_POST_PROCESSING
struct display_pp_conv_cfg hsic_cfg;
#endif
mdp_overlay mOVInfo;
msm_rotator_img_info mRotInfo;
msmfb_overlay_3d m3DOVInfo;
bool mIsChannelUpdated;
bool openDevices(int fbnum = -1);
bool setOverlayInformation(const overlay_buffer_info& info,
int zorder = 0, int flags = 0,
int requestType = NEW_REQUEST);
bool startOVRotatorSessions(const overlay_buffer_info& info, int requestType);
void swapOVRotWidthHeight();
int commitVisualParam(int8_t paramType, float paramValue);
void setInformationFromFlags(int flags, mdp_overlay& ov);
public:
OverlayControlChannel();
~OverlayControlChannel();
bool startControlChannel(const overlay_buffer_info& info,
int fbnum, bool norot = false,
bool uichannel = false,
unsigned int format3D = 0, int zorder = 0,
int flags = 0);
bool closeControlChannel();
bool setPosition(int x, int y, uint32_t w, uint32_t h);
bool setTransform(int value, bool fetch = true);
void setSize (int size) { mSize = size; }
bool getPosition(int& x, int& y, uint32_t& w, uint32_t& h);
bool getOvSessionID(int& sessionID) const;
bool getRotSessionID(int& sessionID) const;
bool getSize(int& size) const;
bool isChannelUP() const { return (mFD > 0); }
int getFBWidth() const { return mFBWidth; }
int getFBHeight() const { return mFBHeight; }
int getFormat3D() const { return mFormat3D; }
bool getOrientation(int& orientation) const;
bool updateOverlayFlags(int flags);
bool getAspectRatioPosition(int w, int h, overlay_rect *rect);
// Calculates the aspect ratio for video on HDMI based on primary
// aspect ratio used in case of true mirroring
bool getAspectRatioPosition(int w, int h, int orientation,
overlay_rect *inRect, overlay_rect *outRect);
bool getPositionS3D(int channel, int format, overlay_rect *rect);
bool updateOverlaySource(const overlay_buffer_info& info, int orientation, int flags);
bool getFormat() const { return mFormat; }
bool setVisualParam(int8_t paramType, float paramValue);
bool useVirtualFB ();
bool doFlagsNeedUpdate(int flags);
};
class OverlayDataChannel {
bool mNoRot;
bool mSecure;
int mFD;
int mRotFD;
int mPmemFD;
void* mPmemAddr;
uint32_t mPmemOffset;
uint32_t mNewPmemOffset;
msmfb_overlay_data mOvData;
msmfb_overlay_data mOvDataRot;
msm_rotator_data_info mRotData;
int mRotOffset[max_num_buffers];
int mCurrentItem;
int mNumBuffers;
bool mUpdateDataChannel;
android::sp<gralloc::IAllocController> mAlloc;
int mBufferType;
bool openDevices(int fbnum = -1, bool uichannel = false, int num_buffers = 2);
bool mapRotatorMemory(int num_buffers, bool uiChannel, int requestType);
bool queue(uint32_t offset);
public:
OverlayDataChannel();
~OverlayDataChannel();
bool startDataChannel(const OverlayControlChannel& objOvCtrlChannel,
int fbnum, bool norot = false, bool secure = false,
bool uichannel = false, int num_buffers = 2);
bool startDataChannel(int ovid, int rotid, int size,
int fbnum, bool norot = false, bool uichannel = false,
int num_buffers = 2);
bool closeDataChannel();
bool setFd(int fd);
bool queueBuffer(uint32_t offset);
bool waitForHdmiVsync();
bool setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h);
bool getCropS3D(overlay_rect *inRect, int channel, int format, overlay_rect *rect);
bool isChannelUP() const { return (mFD > 0); }
bool updateDataChannel(int size);
};
/*
* Overlay class for single thread application
* A multiple thread/process application need to use Overlay HAL
*/
class Overlay {
bool mChannelUP;
//stores the connected external display Ex: HDMI(1) WFD(2)
int mExternalDisplay;
unsigned int mS3DFormat;
//Actual cropped source width and height of overlay
int mCroppedSrcWidth;
int mCroppedSrcHeight;
overlay_buffer_info mOVBufferInfo;
int mState;
// Stores the current device orientation
int mDevOrientation;
OverlayControlChannel objOvCtrlChannel[2];
OverlayDataChannel objOvDataChannel[2];
public:
Overlay();
~Overlay();
static bool sHDMIAsPrimary;
bool startChannel(const overlay_buffer_info& info, int fbnum, bool norot = false,
bool uichannel = false, unsigned int format3D = 0,
int channel = 0, int flags = 0,
int num_buffers = 2);
bool closeChannel();
bool setDeviceOrientation(int orientation);
bool setPosition(int x, int y, uint32_t w, uint32_t h);
bool setTransform(int value);
bool setOrientation(int value, int channel = 0);
bool setFd(int fd, int channel = 0);
bool queueBuffer(uint32_t offset, int channel = 0);
bool getPosition(int& x, int& y, uint32_t& w, uint32_t& h, int channel = 0);
bool isChannelUP() const { return mChannelUP; }
int getFBWidth(int channel = 0) const;
int getFBHeight(int channel = 0) const;
bool getOrientation(int& orientation, int channel = 0) const;
bool queueBuffer(buffer_handle_t buffer);
bool setSource(const overlay_buffer_info& info, int orientation, int hdmiConnected,
int flags, int numBuffers = 2);
bool getAspectRatioPosition(int w, int h, overlay_rect *rect, int channel = 0);
bool setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h);
bool updateOverlayFlags(int flags);
void setVisualParam(int8_t paramType, float paramValue);
bool waitForHdmiVsync(int channel);
int getChannelStatus() const { return (mChannelUP ? OVERLAY_CHANNEL_UP: OVERLAY_CHANNEL_DOWN); }
void closeExternalChannel();
private:
bool setChannelPosition(int x, int y, uint32_t w, uint32_t h, int channel = 0);
bool setChannelCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h, int channel);
bool queueBuffer(int fd, uint32_t offset, int channel);
bool updateOverlaySource(const overlay_buffer_info& info, int orientation, int flags);
int getS3DFormat(int format);
};
struct overlay_shared_data {
volatile bool isControlSetup;
unsigned int state;
int rotid[2];
int ovid[2];
};
};
#endif

View File

@ -1,482 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "overlayLibUI.h"
#include "gralloc_priv.h"
#define LOG_TAG "OverlayUI"
using android::sp;
using gralloc::IMemAlloc;
using gralloc::alloc_data;
namespace {
/* helper functions */
void swapOVRotWidthHeight(msm_rotator_img_info& rotInfo,
mdp_overlay& ovInfo) {
int srcWidth = ovInfo.src.width;
ovInfo.src.width = ovInfo.src.height;
ovInfo.src.height = srcWidth;
int srcRectWidth = ovInfo.src_rect.w;
ovInfo.src_rect.w = ovInfo.src_rect.h;
ovInfo.src_rect.h = srcRectWidth;
int dstWidth = rotInfo.dst.width;
rotInfo.dst.width = rotInfo.dst.height;
rotInfo.dst.height = dstWidth;
}
bool isRGBType(int format) {
bool ret = false;
switch(format) {
case MDP_RGBA_8888:
case MDP_BGRA_8888:
case MDP_RGBX_8888:
case MDP_RGB_565:
ret = true;
break;
default:
ret = false;
break;
}
return ret;
}
int getRGBBpp(int format) {
int ret = -1;
switch(format) {
case MDP_RGBA_8888:
case MDP_BGRA_8888:
case MDP_RGBX_8888:
ret = 4;
break;
case MDP_RGB_565:
ret = 2;
break;
default:
ret = -1;
break;
}
return ret;
}
bool turnOFFVSync() {
static int swapIntervalPropVal = -1;
if (swapIntervalPropVal == -1) {
char pval[PROPERTY_VALUE_MAX];
property_get("debug.gr.swapinterval", pval, "1");
swapIntervalPropVal = atoi(pval);
}
return (swapIntervalPropVal == 0);
}
};
namespace overlay {
status_t Display::openDisplay(int fbnum) {
if (mFD != NO_INIT)
return NO_ERROR;
status_t ret = NO_INIT;
char dev_name[64];
snprintf(dev_name, 64, FB_DEVICE_TEMPLATE, fbnum);
mFD = open(dev_name, O_RDWR, 0);
if (mFD < 0) {
LOGE("Failed to open FB %d", fbnum);
return ret;
}
fb_var_screeninfo vinfo;
if (ioctl(mFD, FBIOGET_VSCREENINFO, &vinfo)) {
LOGE("FBIOGET_VSCREENINFO on failed on FB %d", fbnum);
close(mFD);
mFD = NO_INIT;
return ret;
}
mFBWidth = vinfo.xres;
mFBHeight = vinfo.yres;
mFBBpp = vinfo.bits_per_pixel;
ret = NO_ERROR;
return ret;
}
void Display::closeDisplay() {
close(mFD);
mFD = NO_INIT;
}
Rotator::Rotator() : mFD(NO_INIT), mSessionID(NO_INIT), mPmemFD(NO_INIT)
{
mAlloc = gralloc::IAllocController::getInstance(false);
}
Rotator::~Rotator()
{
closeRotSession();
}
status_t Rotator::startRotSession(msm_rotator_img_info& rotInfo,
int size, int numBuffers) {
status_t ret = NO_ERROR;
if (mSessionID == NO_INIT && mFD == NO_INIT) {
mNumBuffers = numBuffers;
mFD = open("/dev/msm_rotator", O_RDWR, 0);
if (mFD < 0) {
LOGE("Couldnt open rotator device");
return NO_INIT;
}
if (ioctl(mFD, MSM_ROTATOR_IOCTL_START, &rotInfo)) {
close(mFD);
mFD = NO_INIT;
return NO_INIT;
}
mSessionID = rotInfo.session_id;
alloc_data data;
data.base = 0;
data.fd = -1;
data.offset = 0;
data.size = mSize * mNumBuffers;
data.align = getpagesize();
data.uncached = true;
int allocFlags = GRALLOC_USAGE_PRIVATE_MM_HEAP |
GRALLOC_USAGE_PRIVATE_WRITEBACK_HEAP |
GRALLOC_USAGE_PRIVATE_ADSP_HEAP |
GRALLOC_USAGE_PRIVATE_IOMMU_HEAP |
GRALLOC_USAGE_PRIVATE_SMI_HEAP |
GRALLOC_USAGE_PRIVATE_DO_NOT_MAP;
int err = mAlloc->allocate(data, allocFlags, 0);
if(err) {
LOGE("%s: Can't allocate rotator memory", __func__);
closeRotSession();
return NO_INIT;
}
mPmemFD = data.fd;
mPmemAddr = data.base;
mBufferType = data.allocType;
mCurrentItem = 0;
for (int i = 0; i < mNumBuffers; i++)
mRotOffset[i] = i * mSize;
ret = NO_ERROR;
}
return ret;
}
status_t Rotator::closeRotSession() {
if (mSessionID != NO_INIT && mFD != NO_INIT) {
ioctl(mFD, MSM_ROTATOR_IOCTL_FINISH, &mSessionID);
close(mFD);
if (NO_INIT != mPmemFD) {
sp<IMemAlloc> memalloc = mAlloc->getAllocator(mBufferType);
memalloc->free_buffer(mPmemAddr, mSize * mNumBuffers, 0, mPmemFD);
close(mPmemFD);
}
}
mFD = NO_INIT;
mSessionID = NO_INIT;
mPmemFD = NO_INIT;
mPmemAddr = MAP_FAILED;
return NO_ERROR;
}
status_t Rotator::rotateBuffer(msm_rotator_data_info& rotData) {
status_t ret = NO_INIT;
if (mSessionID != NO_INIT) {
rotData.dst.memory_id = mPmemFD;
rotData.dst.offset = mRotOffset[mCurrentItem];
rotData.session_id = mSessionID;
mCurrentItem = (mCurrentItem + 1) % mNumBuffers;
if (ioctl(mFD, MSM_ROTATOR_IOCTL_ROTATE, &rotData)) {
LOGE("Rotator failed to rotate");
return BAD_VALUE;
}
return NO_ERROR;
}
return ret;
}
//===================== OverlayUI =================//
OverlayUI::OverlayUI() : mChannelState(CLOSED), mOrientation(NO_INIT),
mFBNum(NO_INIT), mZorder(NO_INIT), mWaitForVsync(false), mIsFg(false),
mSessionID(NO_INIT), mParamsChanged(false) {
memset(&mOvInfo, 0, sizeof(mOvInfo));
memset(&mRotInfo, 0, sizeof(mRotInfo));
}
OverlayUI::~OverlayUI() {
closeChannel();
}
void OverlayUI::setSource(const overlay_buffer_info& info, int orientation) {
status_t ret = NO_INIT;
int format3D = FORMAT_3D(info.format);
int colorFormat = COLOR_FORMAT(info.format);
int format = get_mdp_format(colorFormat);
if (format3D || !isRGBType(format)) {
LOGE("%s: Unsupported format", __func__);
return;
}
mParamsChanged |= (mSource.width ^ info.width) ||
(mSource.height ^ info.height) ||
(mSource.format ^ format) ||
(mSource.size ^ info.size) ||
(mOrientation ^ orientation);
mSource.width = info.width;
mSource.height = info.height;
mSource.format = format;
mSource.size = info.size;
mOrientation = orientation;
setupOvRotInfo();
}
void OverlayUI::setDisplayParams(int fbNum, bool waitForVsync, bool isFg, int
zorder, bool isVGPipe) {
int flags = 0;
if(false == waitForVsync)
flags |= MDP_OV_PLAY_NOWAIT;
else
flags &= ~MDP_OV_PLAY_NOWAIT;
if(isVGPipe)
flags |= MDP_OV_PIPE_SHARE;
else
flags &= ~MDP_OV_PIPE_SHARE;
if (turnOFFVSync())
flags |= MDP_OV_PLAY_NOWAIT;
mParamsChanged |= (mFBNum ^ fbNum) ||
(mOvInfo.is_fg ^ isFg) ||
(mOvInfo.flags ^ flags) ||
(mOvInfo.z_order ^ zorder);
mFBNum = fbNum;
mOvInfo.is_fg = isFg;
mOvInfo.flags = flags;
mOvInfo.z_order = zorder;
mobjDisplay.openDisplay(mFBNum);
}
void OverlayUI::setPosition(int x, int y, int w, int h) {
mParamsChanged |= (mOvInfo.dst_rect.x ^ x) ||
(mOvInfo.dst_rect.y ^ y) ||
(mOvInfo.dst_rect.w ^ w) ||
(mOvInfo.dst_rect.h ^ h);
mOvInfo.dst_rect.x = x;
mOvInfo.dst_rect.y = y;
mOvInfo.dst_rect.w = w;
mOvInfo.dst_rect.h = h;
}
void OverlayUI::setCrop(int x, int y, int w, int h) {
mParamsChanged |= (mOvInfo.src_rect.x ^ x) ||
(mOvInfo.src_rect.y ^ y) ||
(mOvInfo.src_rect.w ^ w) ||
(mOvInfo.src_rect.h ^ h);
mOvInfo.src_rect.x = x;
mOvInfo.src_rect.y = y;
mOvInfo.src_rect.w = w;
mOvInfo.src_rect.h = h;
}
void OverlayUI::setupOvRotInfo() {
int w = mSource.width;
int h = mSource.height;
int format = mSource.format;
int srcw = (w + 31) & ~31;
int srch = (h + 31) & ~31;
mOvInfo.src.width = srcw;
mOvInfo.src.height = srch;
mOvInfo.src.format = format;
mOvInfo.src_rect.w = w;
mOvInfo.src_rect.h = h;
mOvInfo.alpha = 0xff;
mOvInfo.transp_mask = 0xffffffff;
mRotInfo.src.format = format;
mRotInfo.dst.format = format;
mRotInfo.src.width = srcw;
mRotInfo.src.height = srch;
mRotInfo.src_rect.w = srcw;
mRotInfo.src_rect.h = srch;
mRotInfo.dst.width = srcw;
mRotInfo.dst.height = srch;
int rot = mOrientation;
switch(rot) {
case 0:
case HAL_TRANSFORM_FLIP_H:
case HAL_TRANSFORM_FLIP_V:
rot = 0;
break;
case HAL_TRANSFORM_ROT_90:
case (HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_H):
case (HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_V): {
int tmp = mOvInfo.src_rect.x;
mOvInfo.src_rect.x = mOvInfo.src.height -
(mOvInfo.src_rect.y + mOvInfo.src_rect.h);
mOvInfo.src_rect.y = tmp;
swapOVRotWidthHeight(mRotInfo, mOvInfo);
rot = HAL_TRANSFORM_ROT_90;
break;
}
case HAL_TRANSFORM_ROT_180:
break;
case HAL_TRANSFORM_ROT_270: {
int tmp = mOvInfo.src_rect.y;
mOvInfo.src_rect.y = mOvInfo.src.width -
(mOvInfo.src_rect.x + mOvInfo.src_rect.w);
mOvInfo.src_rect.x = tmp;
swapOVRotWidthHeight(mRotInfo, mOvInfo);
break;
}
default:
break;
}
int mdp_rotation = overlay::get_mdp_orientation(rot);
if (mdp_rotation < 0)
mdp_rotation = 0;
mOvInfo.user_data[0] = mdp_rotation;
mRotInfo.rotations = mOvInfo.user_data[0];
if (mdp_rotation)
mRotInfo.enable = 1;
}
status_t OverlayUI::commit() {
status_t ret = BAD_VALUE;
if(mChannelState != UP)
mOvInfo.id = MSMFB_NEW_REQUEST;
ret = startOVSession();
if (ret == NO_ERROR && mOrientation) {
ret = mobjRotator.startRotSession(mRotInfo, mSource.size);
}
if (ret == NO_ERROR) {
mChannelState = UP;
} else {
LOGE("start channel failed.");
}
return ret;
}
status_t OverlayUI::closeChannel() {
if( mChannelState != UP ) {
return NO_ERROR;
}
if(NO_ERROR != closeOVSession()) {
LOGE("%s: closeOVSession() failed.", __FUNCTION__);
return BAD_VALUE;
}
if(NO_ERROR != mobjRotator.closeRotSession()) {
LOGE("%s: closeRotSession() failed.", __FUNCTION__);
return BAD_VALUE;
}
mChannelState = CLOSED;
mParamsChanged = false;
memset(&mOvInfo, 0, sizeof(mOvInfo));
memset(&mRotInfo, 0, sizeof(mRotInfo));
return NO_ERROR;
}
status_t OverlayUI::startOVSession() {
status_t ret = NO_INIT;
ret = mobjDisplay.openDisplay(mFBNum);
if (ret != NO_ERROR)
return ret;
if(mParamsChanged) {
mParamsChanged = false;
mdp_overlay ovInfo = mOvInfo;
if (ioctl(mobjDisplay.getFD(), MSMFB_OVERLAY_SET, &ovInfo)) {
LOGE("Overlay set failed..");
ret = BAD_VALUE;
} else {
mSessionID = ovInfo.id;
mOvInfo = ovInfo;
ret = NO_ERROR;
}
}
return ret;
}
status_t OverlayUI::closeOVSession() {
status_t ret = NO_ERROR;
int err = 0;
if(err = ioctl(mobjDisplay.getFD(), MSMFB_OVERLAY_UNSET, &mSessionID)) {
LOGE("%s: MSMFB_OVERLAY_UNSET failed. (%d)", __FUNCTION__, err);
ret = BAD_VALUE;
} else {
mobjDisplay.closeDisplay();
mSessionID = NO_INIT;
}
return ret;
}
status_t OverlayUI::queueBuffer(buffer_handle_t buffer) {
status_t ret = NO_INIT;
if (mChannelState != UP)
return ret;
msmfb_overlay_data ovData;
memset(&ovData, 0, sizeof(ovData));
private_handle_t const* hnd = reinterpret_cast
<private_handle_t const*>(buffer);
ovData.data.memory_id = hnd->fd;
ovData.data.offset = hnd->offset;
if (mOrientation) {
msm_rotator_data_info rotData;
memset(&rotData, 0, sizeof(rotData));
rotData.src.memory_id = hnd->fd;
rotData.src.offset = hnd->offset;
if (mobjRotator.rotateBuffer(rotData) != NO_ERROR) {
LOGE("Rotator failed.. ");
return BAD_VALUE;
}
ovData.data.memory_id = rotData.dst.memory_id;
ovData.data.offset = rotData.dst.offset;
}
ovData.id = mSessionID;
if (ioctl(mobjDisplay.getFD(), MSMFB_OVERLAY_PLAY, &ovData)) {
LOGE("Queuebuffer failed ");
return BAD_VALUE;
}
return NO_ERROR;
}
};

View File

@ -1,140 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef INCLUDE_OVERLAY_LIB_UI
#define INCLUDE_OVERLAY_LIB_UI
#include <errno.h>
#include "overlayLib.h"
namespace overlay {
enum channel_state_t { UP, CLOSED, PENDING_CLOSE };
enum status_t {
NO_ERROR,
INVALID_OPERATION = -ENOSYS,
BAD_VALUE = -EINVAL,
NO_INIT = -ENODEV,
ALREADY_EXISTS = -EEXIST
};
/*
* Display class provides following services
* Open FB
* FB information (Width, Height and Bpp)
*/
class Display {
int mFD;
int mFBWidth;
int mFBHeight;
int mFBBpp;
Display(const Display& objDisplay);
Display& operator=(const Display& objDisplay);
public:
explicit Display() : mFD(NO_INIT) { };
~Display() { close(mFD); };
int getFD() const { return mFD; };
int getFBWidth() const { return mFBWidth; };
int getFBHeight() const { return mFBHeight; };
int getFBBpp() const { return mFBBpp; };
status_t openDisplay(int fbnum);
void closeDisplay();
};
/*
* Rotator class, manages rotation of the buffers
* It communicates with Rotator driver, provides following services
* Start rotator session
* Rotate buffer
*/
class Rotator {
int mFD;
int mSessionID;
int mPmemFD;
void* mPmemAddr;
int mRotOffset[max_num_buffers];
int mCurrentItem;
int mNumBuffers;
int mSize;
android::sp<gralloc::IAllocController> mAlloc;
int mBufferType;
Rotator(const Rotator& objROtator);
Rotator& operator=(const Rotator& objRotator);
public:
explicit Rotator();
~Rotator();
status_t startRotSession(msm_rotator_img_info& rotInfo, int size,
int numBuffers = max_num_buffers);
status_t closeRotSession();
status_t rotateBuffer(msm_rotator_data_info& rotData);
};
/*
* Overlay class for Comp. Bypass
* We merge control and data channel classes.
*/
class OverlayUI {
channel_state_t mChannelState;
overlay_buffer_info mSource;
int mZorder;
int mOrientation;
int mFBNum;
bool mWaitForVsync;
bool mIsFg;
int mSessionID;
Display mobjDisplay;
Rotator mobjRotator;
mdp_overlay mOvInfo;
msm_rotator_img_info mRotInfo;
bool mParamsChanged;
OverlayUI(const OverlayUI& objOverlay);
OverlayUI& operator=(const OverlayUI& objOverlay);
status_t startOVSession();
status_t closeOVSession();
void setupOvRotInfo();
public:
enum fbnum_t { FB0, FB1 };
OverlayUI();
~OverlayUI();
void setSource(const overlay_buffer_info& info, int orientation);
void setPosition(int x, int y, int w, int h);
void setCrop(int x, int y, int w, int h);
void setDisplayParams(int fbNum, bool waitForVsync, bool isFg, int zorder,
bool isVGPipe);
status_t commit();
status_t closeChannel();
channel_state_t isChannelUP() const { return mChannelState; };
int getFBWidth() const { return mobjDisplay.getFBWidth(); };
int getFBHeight() const { return mobjDisplay.getFBHeight(); };
status_t queueBuffer(buffer_handle_t buffer);
};
};
#endif

289
liboverlay/overlayMdp.cpp Normal file
View File

@ -0,0 +1,289 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "overlayUtils.h"
#include "overlayMdp.h"
#undef ALOG_TAG
#define ALOG_TAG "overlay"
namespace ovutils = overlay::utils;
namespace overlay {
bool MdpCtrl::open(uint32_t fbnum) {
// FD open
if(!utils::openDev(mFd, fbnum,
Res::devTemplate, O_RDWR)){
ALOGE("Ctrl failed to open fbnum=%d", fbnum);
return false;
}
return true;
}
void MdpCtrl::reset() {
utils::memset0(mOVInfo);
utils::memset0(mLkgo);
mOVInfo.id = -1;
mLkgo.id = -1;
}
bool MdpCtrl::close() {
if(-1 == static_cast<int>(mOVInfo.id)) return true;
if(!mdp_wrapper::unsetOverlay(mFd.getFD(), mOVInfo.id)) {
ALOGE("MdpCtrl close error in unset");
return false;
}
reset();
if(!mFd.close()) {
return false;
}
return true;
}
bool MdpCtrl::getScreenInfo(overlay::utils::ScreenInfo& info) {
fb_fix_screeninfo finfo;
if (!mdp_wrapper::getFScreenInfo(mFd.getFD(), finfo)) {
return false;
}
fb_var_screeninfo vinfo;
if (!mdp_wrapper::getVScreenInfo(mFd.getFD(), vinfo)) {
return false;
}
info.mFBWidth = vinfo.xres;
info.mFBHeight = vinfo.yres;
info.mFBbpp = vinfo.bits_per_pixel;
info.mFBystride = finfo.line_length;
return true;
}
bool MdpCtrl::get() {
mdp_overlay ov;
ov.id = mOVInfo.id;
if (!mdp_wrapper::getOverlay(mFd.getFD(), ov)) {
ALOGE("MdpCtrl get failed");
return false;
}
mOVInfo = ov;
return true;
}
// that is the second part of original setParameter function
void MdpCtrl::setSrcFormat(const utils::Whf& whf) {
//By default mdp src format is the same as buffer's
mOVInfo.src.format = whf.format;
//If rotation is used and input formats are tiled then output of rotator is
//non-tiled.
// FIXME mRotInfo.enable = 1; for enable
if (getUserData()) { // if rotations enabled in MdpCtrl
if (whf.format == MDP_Y_CRCB_H2V2_TILE)
mOVInfo.src.format = MDP_Y_CRCB_H2V2;
else if (whf.format == MDP_Y_CBCR_H2V2_TILE)
mOVInfo.src.format = MDP_Y_CBCR_H2V2;
return;
}
}
bool MdpCtrl::set() {
if(!this->ovChanged()) {
return true; // nothing todo here.
}
if(!mdp_wrapper::setOverlay(mFd.getFD(), mOVInfo)) {
ALOGE("MdpCtrl failed to setOverlay, restoring last known "
"good ov info");
mdp_wrapper::dump("== Bad OVInfo is: ", mOVInfo);
mdp_wrapper::dump("== Last good known OVInfo is: ", mLkgo);
this->restore();
// FIXME, do we need to set the old one?
return false;
}
this->save();
return true;
}
bool MdpCtrl::setPosition(const overlay::utils::Dim& d,
int fbw, int fbh)
{
// Validatee against FB size
if(!d.check(fbw, fbh)) {
ALOGE("MdpCtrl setPosition failed dest dim violate screen limits");
return false;
}
ovutils::Dim dim(d);
ovutils::Dim ovsrcdim = getSrcRectDim();
// Scaling of upto a max of 8 times supported
if(dim.w >(ovsrcdim.w * ovutils::HW_OV_MAGNIFICATION_LIMIT)){
dim.w = ovutils::HW_OV_MAGNIFICATION_LIMIT * ovsrcdim.w;
dim.x = (fbw - dim.w) / 2;
}
if(dim.h >(ovsrcdim.h * ovutils::HW_OV_MAGNIFICATION_LIMIT)) {
dim.h = ovutils::HW_OV_MAGNIFICATION_LIMIT * ovsrcdim.h;
dim.y = (fbh - dim.h) / 2;
}
//dim.even_out();
setDstRectDim(dim);
return true;
}
void MdpCtrl::updateSource(RotatorBase* r,
const utils::PipeArgs& args,
const utils::ScreenInfo& info) {
utils::Whf whf(args.whf);
mOVInfo.src.width = whf.w;
mOVInfo.src.height = whf.h;
mOVInfo.src_rect.x = 0;
mOVInfo.src_rect.y = 0;
mOVInfo.dst_rect.x = 0;
mOVInfo.dst_rect.y = 0;
mOVInfo.dst_rect.w = whf.w;
mOVInfo.dst_rect.h = whf.h;
mOVInfo.src.format = whf.format;
if(whf.format == MDP_Y_CRCB_H2V2_TILE ||
(whf.format == MDP_Y_CBCR_H2V2_TILE)) {
// passing by value, setInfo fills it and return by val
mOVInfo = r->setInfo(args, mOVInfo);
} else {
mOVInfo.src_rect.w = whf.w;
mOVInfo.src_rect.h = whf.h;
}
if (whf.w > info.mFBWidth)
mOVInfo.dst_rect.w = info.mFBWidth;
if (whf.h > info.mFBHeight)
mOVInfo.dst_rect.h = info.mFBHeight;
mSize = whf.size;
}
bool MdpCtrl::setInfo(RotatorBase* r,
const utils::PipeArgs& args,
const utils::ScreenInfo& info)
{
// new request
utils::Whf whf(args.whf);
mOVInfo.id = MSMFB_NEW_REQUEST;
updateSource(r, args, info);
setUserData(0);
mOVInfo.alpha = 0xff;
mOVInfo.transp_mask = 0xffffffff;
setZ(args.zorder);
setFlags(args.mdpFlags);
setWait(args.wait);
setIsFg(args.isFg);
mSize = whf.size;
return true;
}
bool MdpCtrl::setCrop(const utils::Dim& cdim) {
utils::Dim d(cdim);
const utils::Whf ovwhf = getSrcWhf();
int udata = getUserData();
switch(udata) {
case MDP_ROT_NOP:
break; // nothing to do here
case MDP_ROT_90:
case MDP_ROT_90 | MDP_FLIP_UD:
case MDP_ROT_90 | MDP_FLIP_LR:
{
if (ovwhf.w < (d.y + d.h)) {
ALOGE("MdpCtrl setCrop failed ROT 90 udata=%d",
udata);
d.dump();
this->dump();
return false;
}
uint32_t tmp = d.x;
d.x = ovwhf.w - (d.y + d.h);
d.y = tmp;
utils::swap(d.w, d.h);
}break;
case MDP_ROT_270:
{
if (ovwhf.h < (d.x + d.w)) {
ALOGE("MdpCtrl setCrop failed ROT 270 udata=%d",
udata);
d.dump();
this->dump();
return false;
}
uint32_t tmp = d.y;
d.y = ovwhf.h - (d.x + d.w);
d.x = tmp;
utils::swap(d.w, d.h);
}break;
case MDP_ROT_180:
{
if ((ovwhf.h < (d.y + d.h)) ||
(ovwhf.w < ( d.x + d.w))) {
ALOGE("MdpCtrl setCrop failed ROT 180 udata=%d",
udata);
d.dump();
this->dump();
return false;
}
d.x = ovwhf.w - (d.x + d.w);
d.y = ovwhf.h - (d.y + d.h);
}break;
default:
if(!(udata & (MDP_FLIP_UD | MDP_FLIP_LR))) {
ALOGE("MdpCtrl setCrop unknown rot %d", udata);
return false;
}
}
if(getSrcRectDim() == d) {
return true; // Nothing to do here
}
utils::normalizeCrop(d.x, d.w);
utils::normalizeCrop(d.y, d.h);
setSrcRectDim(d);
return true;
}
void MdpCtrl::dump() const {
ALOGE("== Dump MdpCtrl start ==");
ALOGE("size=%d", mSize);
mFd.dump();
mdp_wrapper::dump("mOVInfo", mOVInfo);
ALOGE("== Dump MdpCtrl end ==");
}
void MdpData::dump() const {
ALOGE("== Dump MdpData start ==");
mFd.dump();
mdp_wrapper::dump("mOvData", mOvData);
ALOGE("== Dump MdpData end ==");
}
void MdpCtrl3D::dump() const {
ALOGE("== Dump MdpCtrl start ==");
mFd.dump();
ALOGE("== Dump MdpCtrl end ==");
}
} // overlay

489
liboverlay/overlayMdp.h Normal file
View File

@ -0,0 +1,489 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef OVERLAY_MDP_H
#define OVERLAY_MDP_H
#include <linux/msm_mdp.h>
#include "overlayUtils.h"
#include "mdpWrapper.h"
#include "overlayRotator.h"
namespace overlay{
class RotatorBase;
/*
* Mdp Ctrl holds corresponding fd and MDP related struct.
* It is simple wrapper to MDP services
* */
class MdpCtrl {
public:
/* ctor reset */
explicit MdpCtrl();
/* dtor close */
~MdpCtrl();
/* Open underlying device using fbnum */
bool open(uint32_t fbnum);
/* unset overlay, reset and close fd */
bool close();
/* reset and set ov id to -1*/
void reset();
/* get orient / user_data[0] */
int getOrient() const;
/* returns session id */
int getId() const;
/* returns the fd associated to ctrl*/
int getFd() const;
/* Get screen info. out: info*/
bool getScreenInfo(utils::ScreenInfo& info);
/* overlay get */
bool get();
/* returns flags from mdp structure.
* Flags are WAIT/NOWAIT/PIPE SHARED*/
int getFlags() const;
/* set flags to mdp structure */
void setFlags(int f);
/* code taken from OverlayControlChannel::setOverlayInformation */
bool setInfo(RotatorBase* r,
const utils::PipeArgs& args,
const utils::ScreenInfo& info);
/* given whf, update src */
void updateSource(RotatorBase* r,
const utils::PipeArgs& args,
const utils::ScreenInfo& info);
/* set z order */
void setZ(utils::eZorder z);
/* set Wait/nowait */
void setWait(utils::eWait wait);
/* set isFg flag */
void setIsFg(utils::eIsFg isFg);
/* calls overlay set
* Set would always consult last good known ov instance.
* Only if it is different, set would actually exectue ioctl.
* On a sucess ioctl. last good known ov instance is updated */
bool set();
/* return a copy of src whf*/
utils::Whf getSrcWhf() const;
/* set src whf */
void setSrcWhf(const utils::Whf& whf);
/* set source format based on rot info */
void setSrcFormat(const utils::Whf& whf);
/* swap src w/h*/
void swapSrcWH();
/* swap src rect w/h */
void swapSrcRectWH();
/* returns a copy to src rect dim */
utils::Dim getSrcRectDim() const;
/* set src/dst rect dim */
void setSrcRectDim(const utils::Dim d);
void setDstRectDim(const utils::Dim d);
/* returns a copy ro dst rect dim */
utils::Dim getDstRectDim() const;
/* returns user_data[0]*/
int getUserData() const;
/* sets user_data[0] */
void setUserData(int v);
/* return true if current overlay is different
* than lask known good overlay */
bool ovChanged() const;
/* save mOVInfo to be last known good ov*/
void save();
/* restore last known good ov to be the current */
void restore();
/*
* Sets ROI, the unpadded region, for source buffer.
* Should be called before a setPosition, for small clips.
* Dim - ROI dimensions.
*/
bool setCrop(const utils::Dim& d);
/* given a dim and w/h, set overlay dim */
bool setPosition(const utils::Dim& dim, int w, int h);
/* using user_data, sets/unsets roationvalue in mdp flags */
void setRotationFlags();
/* dump state of the object */
void dump() const;
private:
/* last good known ov info */
mdp_overlay mLkgo;
/* Actual overlay mdp structure */
mdp_overlay mOVInfo;
/* FD for the mdp fbnum */
OvFD mFd;
/* cached size FIXME do we need it? */
uint32_t mSize;
};
/* MDP 3D related ctrl */
class MdpCtrl3D {
public:
/* ctor reset data */
MdpCtrl3D();
/* calls MSMFB_OVERLAY_3D */
bool close();
/* set w/h. format is ignored*/
void setWh(const utils::Whf& whf);
/* set is_3d calls MSMFB_OVERLAY_3D */
bool useVirtualFB();
/* set fd to be used in ioctl */
void setFd(int fd);
/* dump */
void dump() const;
private:
/* reset */
void reset();
/* actual MSM 3D info */
msmfb_overlay_3d m3DOVInfo;
/* FD for the mdp 3D */
OvFD mFd;
};
/* MDP data */
class MdpData {
public:
/* ctor reset data */
explicit MdpData();
/* dtor close*/
~MdpData();
/* open FD */
bool open(uint32_t fbnum);
/* memset0 the underlying mdp object */
void reset();
/* close fd, and reset */
bool close();
/* Set FD / memid */
void setMemoryId(int id);
/* set id of mdp data */
void setId(int id);
/* return ses id of data */
int getId() const;
/* get underlying fd*/
int getFd() const;
/* get memory_id */
int getMemoryId() const;
/* set offset in underlying mdp obj */
void setOffset(uint32_t o);
/* calls wrapper play */
bool play();
/* calls wrapper playWait */
bool playWait();
/* dump state of the object */
void dump() const;
private:
/* actual overlay mdp data */
msmfb_overlay_data mOvData;
/* fd to mdp fbnum */
OvFD mFd;
};
//--------------Inlines---------------------------------
namespace utils {
inline bool openDev(OvFD& fd, int fb,
const char* const s,
int flags) {
return overlay::open(fd, fb, Res::devTemplate, O_RDWR);
}
}
template <class T>
inline void init(T& t) {
memset(&t, 0, sizeof(T));
}
///// MdpCtrl //////
inline MdpCtrl::MdpCtrl() : mSize(0) {
reset();
}
inline MdpCtrl::~MdpCtrl() {
close();
}
inline int MdpCtrl::getOrient() const {
return getUserData();
}
inline int MdpCtrl::getId() const {
return mOVInfo.id;
}
inline int MdpCtrl::getFd() const {
return mFd.getFD();
}
inline int MdpCtrl::getFlags() const {
return mOVInfo.flags;
}
inline void MdpCtrl::setFlags(int f) {
mOVInfo.flags = f;
}
inline void MdpCtrl::setZ(overlay::utils::eZorder z) {
mOVInfo.z_order = z;
}
inline void MdpCtrl::setWait(overlay::utils::eWait wait) {
mOVInfo.flags = utils::setWait(wait, mOVInfo.flags);
}
inline void MdpCtrl::setIsFg(overlay::utils::eIsFg isFg) {
mOVInfo.is_fg = isFg;
}
inline bool MdpCtrl::ovChanged() const {
// 0 means same
if(0 == ::memcmp(&mOVInfo, &mLkgo, sizeof (mdp_overlay))) {
return false;
}
return true;
}
inline void MdpCtrl::save() {
if(static_cast<ssize_t>(mOVInfo.id) == -1) {
ALOGE("MdpCtrl current ov has id -1, will not save");
// FIXME dump both?
return;
}
mLkgo = mOVInfo;
}
inline void MdpCtrl::restore() {
if(static_cast<ssize_t>(mLkgo.id) == -1) {
ALOGE("MdpCtrl Lkgo ov has id -1, will not restore");
// FIXME dump both?
return;
}
mOVInfo = mLkgo;
}
inline overlay::utils::Whf MdpCtrl::getSrcWhf() const {
return utils::Whf(mOVInfo.src.width,
mOVInfo.src.height,
mOVInfo.src.format);
}
inline void MdpCtrl::setSrcWhf(const overlay::utils::Whf& whf) {
mOVInfo.src.width = whf.w;
mOVInfo.src.height = whf.h;
mOVInfo.src.format = whf.format;
}
inline overlay::utils::Dim MdpCtrl::getSrcRectDim() const {
return utils::Dim(mOVInfo.src_rect.x,
mOVInfo.src_rect.y,
mOVInfo.src_rect.w,
mOVInfo.src_rect.h);
}
inline void MdpCtrl::setSrcRectDim(const overlay::utils::Dim d) {
mOVInfo.src_rect.x = d.x;
mOVInfo.src_rect.y = d.y;
mOVInfo.src_rect.w = d.w;
mOVInfo.src_rect.h = d.h;
}
inline overlay::utils::Dim MdpCtrl::getDstRectDim() const {
return utils::Dim(mOVInfo.dst_rect.x,
mOVInfo.dst_rect.y,
mOVInfo.dst_rect.w,
mOVInfo.dst_rect.h);
}
inline void MdpCtrl::setDstRectDim(const overlay::utils::Dim d) {
mOVInfo.dst_rect.x = d.x;
mOVInfo.dst_rect.y = d.y;
mOVInfo.dst_rect.w = d.w;
mOVInfo.dst_rect.h = d.h;
}
inline int MdpCtrl::getUserData() const { return mOVInfo.user_data[0]; }
inline void MdpCtrl::setUserData(int v) { mOVInfo.user_data[0] = v; }
inline void MdpCtrl::setRotationFlags() {
const int u = getUserData();
if (u == MDP_ROT_90 || u == MDP_ROT_270)
mOVInfo.flags |= MDP_SOURCE_ROTATED_90;
else
mOVInfo.flags &= ~MDP_SOURCE_ROTATED_90;
}
inline void MdpCtrl::swapSrcWH() {
utils::swap(mOVInfo.src.width,
mOVInfo.src.height); }
inline void MdpCtrl::swapSrcRectWH() {
utils::swap(mOVInfo.src_rect.h,
mOVInfo.src_rect.w); }
/////// MdpCtrl3D //////
inline MdpCtrl3D::MdpCtrl3D() { reset(); }
inline bool MdpCtrl3D::close() {
if (m3DOVInfo.is_3d) {
m3DOVInfo.is_3d = 0;
if(!mdp_wrapper::set3D(mFd.getFD(), m3DOVInfo)) {
ALOGE("MdpCtrl3D close failed set3D with 0");
return false;
}
}
reset();
return true;
}
inline void MdpCtrl3D::reset() {
utils::memset0(m3DOVInfo);
}
inline void MdpCtrl3D::setFd(int fd) {
mFd.copy(fd);
OVASSERT(mFd.valid(), "MdpCtrl3D setFd, FD should be valid");
}
inline void MdpCtrl3D::setWh(const utils::Whf& whf) {
// ignore fmt. Needed for useVirtualFB callflow
m3DOVInfo.width = whf.w;
m3DOVInfo.height = whf.h;
}
inline bool MdpCtrl3D::useVirtualFB() {
if(!m3DOVInfo.is_3d) {
m3DOVInfo.is_3d = 1;
if(!mdp_wrapper::set3D(mFd.getFD(), m3DOVInfo)) {
ALOGE("MdpCtrl3D close failed set3D with 0");
return false;
}
}
return true;
}
/////// MdpData //////
inline MdpData::MdpData() { reset(); }
inline MdpData::~MdpData() { close(); }
inline bool MdpData::open(uint32_t fbnum) {
// FD open
if(!utils::openDev(mFd, fbnum, Res::devTemplate, O_RDWR)){
ALOGE("Ctrl failed to open fbnum=%d", fbnum);
return false;
}
return true;
}
inline void MdpData::reset() {
overlay::utils::memset0(mOvData);
mOvData.data.memory_id = -1;
}
inline bool MdpData::close() {
if(-1 == mOvData.data.memory_id) return true;
reset();
if(!mFd.close()) {
return false;
}
return true;
}
inline void MdpData::setMemoryId(int id) { mOvData.data.memory_id = id; }
inline int MdpData::getMemoryId() const { return mOvData.data.memory_id; }
inline void MdpData::setId(int id) { mOvData.id = id; }
inline int MdpData::getId() const { return mOvData.id; }
inline int MdpData::getFd() const { return mFd.getFD(); }
inline void MdpData::setOffset(uint32_t o) { mOvData.data.offset = o; }
inline bool MdpData::play() {
if(!mdp_wrapper::play(mFd.getFD(), mOvData)){
ALOGE("MdpData failed to play");
return false;
}
return true;
}
inline bool MdpData::playWait() {
if(!mdp_wrapper::playWait(mFd.getFD(), mOvData)){
ALOGE("MdpData failed to playWait");
return false;
}
return true;
}
} // overlay
#endif // OVERLAY_MDP_H

205
liboverlay/overlayMem.h Normal file
View File

@ -0,0 +1,205 @@
/*
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OVERLAY_MEM_H
#define OVERLAY_MEM_H
#include <sys/mman.h>
#include <fcntl.h>
#include <alloc_controller.h>
#include <memalloc.h>
#include "gralloc_priv.h"
#include "overlayUtils.h"
namespace overlay {
/*
* Holds base address, offset and the fd
* */
class OvMem {
public:
/* ctor init*/
explicit OvMem();
/* dtor DO NOT call close so it can be copied */
~OvMem();
/* Use libgralloc to retrieve fd, base addr, alloc type */
bool open(uint32_t numbufs,
uint32_t bufSz, int flags = O_RDWR);
/* close fd. assign base address to invalid*/
bool close();
/* return underlying fd */
int getFD() const;
/* return true if fd is valid and base address is valid */
bool valid() const;
/* dump the state of the object */
void dump() const;
/* return underlying address */
void* addr() const;
/* return underlying offset */
uint32_t bufSz() const;
/* return number of bufs */
uint32_t numBufs() const ;
private:
/* actual os fd */
int mFd;
/* points to base addr (mmap)*/
void* mBaseAddr;
/* allocated buffer type determined by gralloc (ashmem, ion, etc) */
int mAllocType;
/* holds buf size */
uint32_t mBufSz;
/* num of bufs */
uint32_t mNumBuffers;
/* gralloc alloc controller */
android::sp<gralloc::IAllocController> mAlloc;
};
//-------------------Inlines-----------------------------------
using android::sp;
using gralloc::IMemAlloc;
using gralloc::alloc_data;
inline OvMem::OvMem() {
mFd = -1;
mBaseAddr = MAP_FAILED;
mAllocType = 0;
mBufSz = 0;
mNumBuffers = 0;
mAlloc = gralloc::IAllocController::getInstance(false);
}
inline OvMem::~OvMem() { }
inline bool OvMem::open(uint32_t numbufs,
uint32_t bufSz, int flags)
{
alloc_data data;
//XXX: secure buffers and IOMMU heap
int allocFlags = GRALLOC_USAGE_PRIVATE_MM_HEAP |
GRALLOC_USAGE_PRIVATE_DO_NOT_MAP;
int err = 0;
OVASSERT(numbufs && bufSz, "numbufs=%d bufSz=%d", numbufs, bufSz);
mBufSz = bufSz;
mNumBuffers = numbufs;
data.base = 0;
data.fd = -1;
data.offset = 0;
data.size = mBufSz * mNumBuffers;
data.align = getpagesize();
data.uncached = true;
err = mAlloc->allocate(data, allocFlags, 0);
if (err != 0) {
ALOGE("OvMem: error allocating memory");
}
mFd = data.fd;
mBaseAddr = data.base;
mAllocType = data.allocType;
return true;
}
inline bool OvMem::close()
{
int ret = 0;
if(!valid()) {
return true;
}
sp<IMemAlloc> memalloc = mAlloc->getAllocator(mAllocType);
ret = memalloc->free_buffer(mBaseAddr, mBufSz * mNumBuffers, 0, mFd);
if (ret != 0) {
ALOGE("OvMem: error freeing buffer");
}
mFd = -1;
mBaseAddr = MAP_FAILED;
mAllocType = 0;
mBufSz = 0;
mNumBuffers = 0;
return ret;
}
inline bool OvMem::valid() const
{
return (mFd != -1) && (mBaseAddr != MAP_FAILED);
}
inline int OvMem::getFD() const
{
return mFd;
}
inline void* OvMem::addr() const
{
return mBaseAddr;
}
inline uint32_t OvMem::bufSz() const
{
return mBufSz;
}
inline uint32_t OvMem::numBufs() const
{
return mNumBuffers;
}
inline void OvMem::dump() const
{
ALOGE("%s: fd=%d addr=%p type=%d bufsz=%u",
__FUNCTION__, mFd, mBaseAddr, mAllocType, mBufSz);
}
} // overlay
#endif // OVERLAY_MEM_H

View File

@ -0,0 +1,430 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "overlayRotator.h"
#include "overlayUtils.h"
#include "overlayMdp.h"
namespace ovutils = overlay::utils;
namespace overlay {
namespace utils {
inline mdp_overlay setInfoNullRot(const utils::PipeArgs& args,
const mdp_overlay& o)
{
mdp_overlay ov = o;
utils::Whf whf(args.whf);
utils::Dim d(utils::getSrcRectDim(ov));
d.w = whf.w - (utils::alignup(whf.w, 64) - whf.w);
d.h = whf.h - (utils::alignup(whf.h, 32) - whf.h);
utils::setSrcRectDim(ov, d);
return ov;
}
inline mdp_overlay setInfoRot(const utils::PipeArgs& args,
const mdp_overlay& o)
{
/* If there are no orientation, then we use setInfoRot
* That is even if we are a real rotator object (not null)
* Note, that if args.rotFlags are ENABLED
* it means we would still like to have rot
* even though it is ROT_0 */
if(OVERLAY_TRANSFORM_0 == args.orientation &&
utils::ROT_FLAG_ENABLED != args.rotFlags) {
return setInfoNullRot(args, o);
}
mdp_overlay ov = o;
utils::Whf whf(args.whf);
utils::Dim d(utils::getSrcRectDim(ov));
d.w = whf.w;
d.h = whf.h;
utils::Whf localwhf (utils::getSrcWhf(ov));
localwhf.w = utils::alignup(whf.w, 64);
localwhf.h = utils::alignup(whf.h, 32);
d.x = localwhf.w - whf.w;
d.y = localwhf.h - whf.h;
utils::setSrcRectDim(ov, d);
utils::setSrcWhf(ov, localwhf);
return ov;
}
} // utils
bool MdpRot::open()
{
if(!mFd.open(Res::rotPath, O_RDWR)){
ALOGE("MdpRot failed to open %s", Res::rotPath);
return false;
}
return true;
}
bool MdpRot::open_i(uint32_t numbufs, uint32_t bufsz)
{
OvMem mem;
OVASSERT(MAP_FAILED == mem.addr(), "MAP failed in open_i");
if(!mem.open(numbufs, bufsz)){
ALOGE("%s: Failed to open", __func__);
mem.close();
return false;
}
OVASSERT(MAP_FAILED != mem.addr(), "MAP failed");
OVASSERT(mem.getFD() != -1, "getFd is -1");
mData.data.memory_id = mem.getFD();
mRotDataInfo.dst.memory_id = mem.getFD();
mRotDataInfo.dst.offset = 0;
mMem.curr().m = mem;
return true;
}
bool MdpRot::RotMem::close() {
bool ret = true;
for(uint32_t i=0; i < RotMem::MAX_ROT_MEM; ++i) {
// skip current, and if valid, close
if(m[i].valid() && (m[i].close() != 0)) {
ALOGE("%s error in closing prev rot mem %d", __FUNCTION__, i);
ret = false;
}
}
return ret;
}
bool MdpRot::close() {
bool success = true;
if(mFd.valid() && (getSessId() > 0)) {
if(!mdp_wrapper::endRotator(mFd.getFD(), getSessId())) {
ALOGE("Mdp Rot error endRotator, fd=%d sessId=%d",
mFd.getFD(), getSessId());
success = false;
}
}
if (!mFd.close()) {
ALOGE("Mdp Rot error closing fd");
success = false;
}
if (!mMem.close()) {
ALOGE("Mdp Rot error closing mem");
success = false;
}
reset();
return success;
}
bool MdpRot::unmapNonCurrent() {
bool ret = true;
for(uint32_t i=0; i < RotMem::MAX_ROT_MEM; ++i) {
// skip current, and if valid, close
if(i != mMem._curr % RotMem::MAX_ROT_MEM &&
mMem.m[i].valid() &&
!mMem.m[i].close()) {
ALOGE("%s error in closing prev rot mem %d", __FUNCTION__, i);
ret = false;
}
}
return ret;
}
bool MdpRot::remap(uint32_t numbufs,
const utils::PipeArgs& args) {
// if current size changed, remap
if(args.whf.size == mMem.curr().size()) {
ALOGE_IF(DEBUG_OVERLAY, "%s: same size %d", __FUNCTION__, args.whf.size);
return true;
}
// remap only if we have orientation.
// If rotFlags are ENABLED, it means we need rotation bufs
// even when orientation is 0
if(utils::OVERLAY_TRANSFORM_0 == args.orientation &&
utils::ROT_FLAG_ENABLED != args.rotFlags) {
ALOGE_IF(DEBUG_OVERLAY, "%s: orientation=%d, rotFlags=%d",
__FUNCTION__, args.orientation, args.rotFlags);
return true;
}
ALOGE_IF(DEBUG_OVERLAY, "%s: size changed - remapping", __FUNCTION__);
OVASSERT(!mMem.prev().valid(), "Prev should not be valid");
// remap and have the current to be the new one.
// ++mMem will make curr to be prev, and prev will be curr
++mMem;
if(!open_i(numbufs, args.whf.size)) {
ALOGE("%s Error could not open", __FUNCTION__);
return false;
}
OVASSERT(numbufs <= ROT_MAX_BUF_OFFSET,
"Numbufs %d > ROT_MAX_BUF_OFFSET", numbufs);
for (uint32_t i = 0; i < numbufs; ++i) {
mMem.curr().mRotOffset[i] = i * args.whf.size;
}
return true;
}
bool MdpRot::start() {
if(!overlay::mdp_wrapper::startRotator(mFd.getFD(), mRotImgInfo)) {
ALOGE("MdpRot start failed");
this->dump();
return false;
}
mRotDataInfo.session_id = mRotImgInfo.session_id;
return true;
}
void MdpRot::reset() {
ovutils::memset0(mRotImgInfo);
ovutils::memset0(mRotDataInfo);
ovutils::memset0(mData);
ovutils::memset0(mMem.curr().mRotOffset);
ovutils::memset0(mMem.prev().mRotOffset);
mMem.curr().mCurrOffset = 0;
mMem.prev().mCurrOffset = 0;
isSrcFB = false;
}
bool MdpRot::prepareQueueBuf(uint32_t offset) {
// FIXME if it fails, what happens to the above current item?
if(enabled()) {
OVASSERT(mMem.curr().m.numBufs(),
"prepareQueueBuf numbufs is 0");
// If the rotator source is FB
if(isSrcFB) {
mRotDataInfo.src.flags |= MDP_MEMORY_ID_TYPE_FB;
}
mRotDataInfo.src.offset = offset;
mRotDataInfo.dst.offset =
mMem.curr().mRotOffset[mMem.curr().mCurrOffset];
mMem.curr().mCurrOffset =
(mMem.curr().mCurrOffset + 1) % mMem.curr().m.numBufs();
if(!overlay::mdp_wrapper::rotate(mFd.getFD(), mRotDataInfo)) {
ALOGE("MdpRot failed rotate");
return false;
}
mData.data.offset = mRotDataInfo.dst.offset;
}
return true;
}
bool MdpRot::play(int fd) {
if(!overlay::mdp_wrapper::play(fd, mData)) {
ALOGE("MdpRot failed to play with fd=%d", fd);
return false;
}
// if the prev mem is valid, we need to close
if(mMem.prev().valid()) {
// FIXME FIXME FIXME if no wait for vsync the above
// play will return immediatly and might cause
// tearing when prev.close is called.
if(!mMem.prev().close()) {
ALOGE("%s error in closing prev rot mem", __FUNCTION__);
}
}
return true;
}
///// Null Rot ////
mdp_overlay NullRotator::setInfo(
const utils::PipeArgs& args,
const mdp_overlay& o) {
return utils::setInfoNullRot(args, o);
}
///// Rotator ////
mdp_overlay Rotator::setInfo(
const utils::PipeArgs& args,
const mdp_overlay& o)
{
return utils::setInfoRot(args, o);
}
bool Rotator::overlayTransform(MdpCtrl& mdp,
utils::eTransform& rot)
{
ALOGE_IF(DEBUG_OVERLAY, "%s: rot=%d", __FUNCTION__, rot);
switch(int(rot)) {
case 0:
case HAL_TRANSFORM_FLIP_H:
case HAL_TRANSFORM_FLIP_V:
overlayTransFlipHV(mdp, rot);
break;
case HAL_TRANSFORM_ROT_90:
case (HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_H):
case (HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_V):
overlayTransFlipRot90(mdp, rot);
break;
case HAL_TRANSFORM_ROT_180:
overlayTransFlipRot180(mdp);
break;
case HAL_TRANSFORM_ROT_270:
overlayTransFlipRot270(mdp);
break;
default:
ALOGE("%s: Error due to unknown rot value %d", __FUNCTION__, rot);
return false;
}
/* everything below is rotation related */
int r = utils::getMdpOrient(rot);
ALOGE_IF(DEBUG_OVERLAY, "%s: r=%d", __FUNCTION__, r);
if (r == -1) {
ALOGE("Ctrl setParameter rot it -1");
return false;
}
// Need to have both in sync
mdp.setUserData(r);
this->setRotations(r);
this->setDisable();
if(r) {
this->setEnable();
}
/* set src format using rotation info
* e.g. (12-->5 in case of rotation) */
mdp.setSrcFormat(this->getSrcWhf());
// based on 90/270 set flags
mdp.setRotationFlags();
return true;
}
void Rotator::overlayTransFlipHV(MdpCtrl& mdp,
utils::eTransform& rot)
{
int val = mdp.getUserData();
ALOGE_IF(DEBUG_OVERLAY, "%s: prev=%d", __FUNCTION__, val);
utils::Dim d = mdp.getSrcRectDim();
utils::Whf whf = mdp.getSrcWhf();
if (val == MDP_ROT_90) {
int tmp = d.y;
d.y = compute(whf.w,
d.x,
d.w);
d.x = tmp;
mdp.setSrcRectDim(d);
utils::swapOVRotWidthHeight(mRot, mdp);
}
else if (val == MDP_ROT_270) {
int tmp = d.x;
d.x = compute(whf.h,
d.y,
d.h);
d.y = tmp;
mdp.setSrcRectDim(d);
utils::swapOVRotWidthHeight(mRot, mdp);
}
}
void Rotator::overlayTransFlipRot90(MdpCtrl& mdp,
utils::eTransform& rot)
{
int val = mdp.getUserData();
ALOGE_IF(DEBUG_OVERLAY, "%s: prev=%d", __FUNCTION__, val);
utils::Dim d = mdp.getSrcRectDim();
utils::Whf whf = mdp.getSrcWhf();
if (val == MDP_ROT_270) {
d.x = compute(whf.w,
d.x,
d.w);
d.y = compute(whf.h,
d.y,
d.h);
}
else if (val == MDP_ROT_NOP || val == MDP_ROT_180) {
int tmp = d.x;
d.x = compute(whf.h,
d.y,
d.h);
d.y = tmp;
mdp.setSrcRectDim(d);
utils::swapOVRotWidthHeight(mRot, mdp);
}
}
void Rotator::overlayTransFlipRot180(MdpCtrl& mdp)
{
int val = mdp.getUserData();
ALOGE_IF(DEBUG_OVERLAY, "%s: prev=%d", __FUNCTION__, val);
utils::Dim d = mdp.getSrcRectDim();
utils::Whf whf = mdp.getSrcWhf();
if (val == MDP_ROT_270) {
int tmp = d.y;
d.y = compute(whf.w,
d.x,
d.w);
d.x = tmp;
mdp.setSrcRectDim(d);
utils::swapOVRotWidthHeight(mRot, mdp);
}
else if (val == MDP_ROT_90) {
int tmp = d.x;
d.x = compute(whf.h,
d.y,
d.h);
d.y = tmp;
mdp.setSrcRectDim(d);
utils::swapOVRotWidthHeight(mRot, mdp);
}
}
void Rotator::overlayTransFlipRot270(MdpCtrl& mdp)
{
int val = mdp.getUserData();
ALOGE_IF(DEBUG_OVERLAY, "%s: prev=%d", __FUNCTION__, val);
utils::Dim d = mdp.getSrcRectDim();
utils::Whf whf = mdp.getSrcWhf();
if (val == MDP_ROT_90) {
d.y = compute(whf.h,
d.y,
d.h);
d.x = compute(whf.w,
d.x,
d.w);
}
else if (val == MDP_ROT_NOP || val == MDP_ROT_180) {
int tmp = d.y;
d.y = compute(whf.w,
d.x,
d.w);
d.x = tmp;
mdp.setSrcRectDim(d);
utils::swapOVRotWidthHeight(mRot, mdp);
}
}
void MdpRot::dump() const {
ALOGE("== Dump MdpRot start ==");
mFd.dump();
mMem.curr().m.dump();
mdp_wrapper::dump("mRotImgInfo", mRotImgInfo);
mdp_wrapper::dump("mRotDataInfo", mRotDataInfo);
mdp_wrapper::dump("mData", mData);
ALOGE("== Dump MdpRot end ==");
}
}

554
liboverlay/overlayRotator.h Normal file
View File

@ -0,0 +1,554 @@
/*
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OVERLAY_ROTATOR_H
#define OVERLAY_ROTATOR_H
#include <stdlib.h>
#include "mdpWrapper.h"
#include "overlayUtils.h"
#include "overlayMem.h"
namespace overlay {
class MdpCtrl;
/*
* MDP rot holds MDP's rotation related structures.
*
* */
class MdpRot {
public:
/* ctor */
explicit MdpRot();
/* open fd for rotator. map bufs is defered */
bool open();
/* remap rot buffers */
bool remap(uint32_t numbufs, const utils::PipeArgs& args);
/* Unmap everything that is not current */
bool unmapNonCurrent();
/* close fd, mem */
bool close();
/* reset underlying data, basically memset 0 */
void reset();
/* calls underlying wrappers to start rotator */
bool start();
/* start underlying but use given whf and flags */
bool start(const utils::PipeArgs& args);
/* start underlying but use given whf and flags.
* Has the ability to parameterize the dst fmt */
template <int ROT_OUT_FMT>
bool start(const utils::PipeArgs& args);
/* assign memory id to mdp structure */
void setDataMemId(int fd);
void setRotDataSrcMemId(int fd);
/* Mark src as FB (non-ION) */
void setSrcFB(bool);
/* get dst (for offset and memory id) non-virt */
int getDstMemId() const;
uint32_t getDstOffset() const;
/* set enable/disable flag */
void setEnable();
void setDisable();
bool enabled() const;
/* set rotator flag*/
void setRotations(uint32_t r);
/* set the req data id in mData */
void setDataReqId(int id);
/* swap rot info dst w/h */
void swapDstWH();
/* returns a copy of src whf */
utils::Whf getSrcWhf() const;
/* setup rotator data before queue buf calls
* call play if rotate call succeed. return false if failed */
bool prepareQueueBuf(uint32_t offset);
/* call play on mdp*/
bool play(int fd);
/* set src whf */
void setSrcWhf(const utils::Whf& whf);
/* returns rotator session id */
int getSessId() const;
/* dump the state of the object */
void dump() const;
private:
bool open_i(uint32_t numbufs, uint32_t bufsz);
/* max buf no for offset */
enum { ROT_MAX_BUF_OFFSET = 2 };
/* rot info*/
msm_rotator_img_info mRotImgInfo;
/* rot data */
msm_rotator_data_info mRotDataInfo;
/* data needed for rotator */
msmfb_overlay_data mData;
/* rotator fd */
OvFD mFd;
/* Array of memory map for rotator
* The array enable us to change rot buffers/mapping
* on the fly*/
struct RotMem {
enum {MAX_ROT_MEM = 2};
struct Mem {
Mem() : mCurrOffset(0) {utils::memset0(mRotOffset); }
bool valid() { return m.valid(); }
bool close() { return m.close(); }
uint32_t size() const { return m.bufSz(); }
/* rotator data info dst offset */
uint32_t mRotOffset[ROT_MAX_BUF_OFFSET];
/* current offset slot from mRotOffset */
uint32_t mCurrOffset;
OvMem m;
};
RotMem() : _curr(0) {}
Mem& curr() { return m[_curr % MAX_ROT_MEM]; }
const Mem& curr() const { return m[_curr % MAX_ROT_MEM]; }
Mem& prev() { return m[(_curr+1) % MAX_ROT_MEM]; }
RotMem& operator++() { ++_curr; return *this; }
bool close();
uint32_t _curr;
Mem m[MAX_ROT_MEM];
} mMem;
bool isSrcFB;
};
/*
* RotatorBase. No memebers, just interface.
* ~ can also be =0 with empty impl in cpp.
* */
class RotatorBase {
public:
/* Most of the below are No op funcs for RotatorBase */
virtual ~RotatorBase() {}
virtual bool open() = 0;
virtual bool remap(uint32_t numbufs, const utils::PipeArgs& args) = 0;
virtual bool close() = 0;
virtual bool start(const utils::PipeArgs& args) = 0;
virtual bool start() = 0;
virtual mdp_overlay setInfo(const utils::PipeArgs& args,
const mdp_overlay& o) = 0;
virtual bool overlayTransform(MdpCtrl& mdp,
utils::eTransform& rot) = 0;
virtual void setSrcWhf(const utils::Whf& wfh) = 0;
virtual utils::Whf getSrcWhf() const = 0;
virtual void setRotations(uint32_t r) = 0;
virtual void setDataReqId(int id) = 0;
virtual bool prepareQueueBuf(uint32_t offset) = 0;
virtual bool play(int fd) = 0;
virtual void setEnable() = 0;
virtual void setDisable() = 0;
virtual bool enabled() const = 0;
virtual void setDataMemId(int fd) = 0;
virtual void setRotDataSrcMemId(int fd) = 0;
virtual void setSrcFB(bool) = 0;
virtual int getSessId() const = 0;
virtual void dump() const = 0;
};
/*
* Null/Empty impl of RotatorBase
* */
class NullRotator : public RotatorBase {
public:
/* Most of the below are No op funcs for RotatorBase */
virtual ~NullRotator();
virtual bool open();
virtual bool remap(uint32_t numbufs, const utils::PipeArgs& args);
virtual bool close();
virtual bool start(const utils::PipeArgs& args);
virtual bool start();
/* null rotator behavior should set info in a specific way */
virtual mdp_overlay setInfo(const utils::PipeArgs& args,
const mdp_overlay& o);
virtual bool overlayTransform(MdpCtrl& o,
utils::eTransform& rot);
virtual void setSrcWhf(const utils::Whf& wfh);
virtual utils::Whf getSrcWhf() const;
virtual void setRotations(uint32_t r);
virtual void setDataReqId(int id);
virtual bool prepareQueueBuf(uint32_t offset);
virtual bool play(int fd);
virtual void setEnable();
virtual void setDisable();
virtual bool enabled () const;
virtual void setDataMemId(int fd);
virtual void setRotDataSrcMemId(int fd);
virtual void setSrcFB(bool);
virtual int getSessId() const;
virtual void dump() const;
};
/*
* Rotator impl.
* */
class Rotator : public RotatorBase
{
public:
/* construct underlying object */
explicit Rotator();
/* close underlying rot */
virtual ~Rotator();
/* calls underlying open */
virtual bool open();
/* remap rot buffers */
virtual bool remap(uint32_t numbufs, const utils::PipeArgs& args);
/* calls underlying close */
virtual bool close();
/* calls underlying start */
virtual bool start();
/* calls underlying start with whf and flags */
virtual bool start(const utils::PipeArgs& args);
/* non virtual - calls underlying start with whf and flags.
* Has the ability to parameterize the dst */
template <int ROT_OUT_FMT>
bool start(const utils::PipeArgs& args);
/* Unmap everything that is not current */
bool unmapNonCurrent();
/* set info using whf and given mdp */
virtual mdp_overlay setInfo(const utils::PipeArgs& args,
const mdp_overlay& o);
/* transform function for the MDP */
virtual bool overlayTransform(MdpCtrl& mdp,
utils::eTransform& rot);
/* set src whf */
virtual void setSrcWhf(const utils::Whf& wfh);
/* set Rotations */
virtual void setRotations(uint32_t r);
/* set the req data id in mData */
virtual void setDataReqId(int id);
/* set memory_id */
virtual void setDataMemId(int fd);
virtual void setRotDataSrcMemId(int fd);
/* Mark the src for rotator as FB. usually set by UI mirroing cases */
virtual void setSrcFB(bool);
/* get dst (for offset and memory id) non-virt */
int getDstMemId() const;
uint32_t getDstOffset() const;
/* set enable/disable flag */
virtual void setEnable();
virtual void setDisable();
virtual bool enabled () const;
/* return rotator sess id */
virtual int getSessId() const;
/* return a copy of src whf*/
virtual utils::Whf getSrcWhf() const;
/* prepare rot for queue buf*/
virtual bool prepareQueueBuf(uint32_t offset);
/* call play on mdp*/
virtual bool play(int fd);
/* dump the state of the object */
virtual void dump() const;
private:
/* helper functions for overlayTransform */
void overlayTransFlipHV(MdpCtrl& mdp,
utils::eTransform& rot);
void overlayTransFlipRot90(MdpCtrl& mdp,
utils::eTransform& rot);
void overlayTransFlipRot180(MdpCtrl& mdp);
void overlayTransFlipRot270(MdpCtrl& mdp);
/* underlying rotator MDP object */
MdpRot mRot;
};
//--------------inlines------------------------------------
//// MdpRot ////
inline MdpRot::MdpRot() { reset(); }
inline bool MdpRot::start(const utils::PipeArgs& args) {
return this->start<utils::ROT_OUT_FMT_DEFAULT>(args);
}
inline void MdpRot::setDataMemId(int fd) { mData.data.memory_id = fd; }
inline void MdpRot::setRotDataSrcMemId(int fd) {
mRotDataInfo.src.memory_id = fd; }
inline void MdpRot::setEnable() { mRotImgInfo.enable = 1; }
inline void MdpRot::setDisable() { mRotImgInfo.enable = 0; }
inline bool MdpRot::enabled() const { return mRotImgInfo.enable; }
inline void MdpRot::setRotations(uint32_t r) { mRotImgInfo.rotations = r; }
inline void MdpRot::setDataReqId(int id) { mData.id = id; }
inline void MdpRot::swapDstWH() {
overlay::utils::swap(mRotImgInfo.dst.width,
mRotImgInfo.dst.height); }
inline overlay::utils::Whf MdpRot::getSrcWhf() const {
return overlay::utils::Whf(mRotImgInfo.src.width,
mRotImgInfo.src.height,
mRotImgInfo.src.format);
}
inline int MdpRot::getDstMemId() const {
return mRotDataInfo.dst.memory_id;
}
inline uint32_t MdpRot::getDstOffset() const {
return mRotDataInfo.dst.offset;
}
inline void MdpRot::setSrcWhf(const overlay::utils::Whf& whf) {
mRotImgInfo.src.width = whf.w;
mRotImgInfo.src.height = whf.h;
mRotImgInfo.src.format = whf.format;
}
inline int MdpRot::getSessId() const { return mRotImgInfo.session_id; }
inline void MdpRot::setSrcFB(bool mark) { isSrcFB = mark; }
///// Null Rotator /////
inline NullRotator::~NullRotator() {}
inline bool NullRotator::open() {
return true; }
inline bool NullRotator::remap(uint32_t numbufs,
const utils::PipeArgs& args){
return true; }
inline bool NullRotator::close() { return true; }
inline bool NullRotator::start(const utils::PipeArgs& args)
{ return true; }
inline bool NullRotator::start() { return true; }
inline bool NullRotator::overlayTransform(MdpCtrl& o,
utils::eTransform& rot)
{ return true; }
inline void NullRotator::setSrcWhf(const overlay::utils::Whf& wfh) {}
inline void NullRotator::setRotations(uint32_t) {}
inline void NullRotator::setDataReqId(int id) {}
inline void NullRotator::setEnable() {}
inline void NullRotator::setDisable() {}
inline bool NullRotator::enabled() const { return false; }
inline int NullRotator::getSessId() const { return -1; }
inline overlay::utils::Whf NullRotator::getSrcWhf() const {
return overlay::utils::Whf(); }
inline bool NullRotator::prepareQueueBuf(uint32_t offset)
{ return true; }
inline bool NullRotator::play(int fd)
{ return true; }
inline void NullRotator::setDataMemId(int fd) {}
inline void NullRotator::setRotDataSrcMemId(int fd) {}
inline void NullRotator::setSrcFB(bool) {}
inline void NullRotator::dump() const {
ALOGE("== Dump NullRotator dump (null) start/end ==");
}
///// Rotator /////
inline Rotator::Rotator() { }
inline Rotator::~Rotator() {
mRot.close(); // also will do reset
}
inline bool Rotator::open() {
if(!mRot.open()) {
ALOGE("Rotator::open failed");
return false;
}
return true;
}
template <int ROT_OUT_FMT>
inline bool Rotator::start(const utils::PipeArgs& args) {
return mRot.start<ROT_OUT_FMT>(args);
}
inline bool Rotator::remap(uint32_t numbufs,
const utils::PipeArgs& args){
if(!mRot.remap(numbufs, args)) {
ALOGE("%s failed", __FUNCTION__);
return false;
}
return true;
}
inline bool Rotator::close() {
return mRot.close();
}
inline bool Rotator::start() {
return mRot.start();
}
inline bool Rotator::start(const utils::PipeArgs& args) {
return mRot.start(args);
}
inline bool Rotator::unmapNonCurrent() {
return mRot.unmapNonCurrent();
}
inline void Rotator::setEnable(){ mRot.setEnable(); }
inline void Rotator::setDisable(){ mRot.setDisable(); }
inline bool Rotator::enabled() const { return mRot.enabled(); }
inline void Rotator::setDataMemId(int fd) {
mRot.setDataMemId(fd); }
inline void Rotator::setRotDataSrcMemId(int fd) {
mRot.setRotDataSrcMemId(fd);
}
inline void Rotator::setSrcFB(bool mark) { mRot.setSrcFB(mark); }
inline int Rotator::getDstMemId() const {
return mRot.getDstMemId();
}
inline uint32_t Rotator::getDstOffset() const {
return mRot.getDstOffset();
}
inline void Rotator::setDataReqId(int id) {
mRot.setDataReqId(id);
}
inline void Rotator::setSrcWhf(
const overlay::utils::Whf& whf) {
mRot.setSrcWhf(whf);
}
inline void Rotator::setRotations(uint32_t rot) {
mRot.setRotations (rot);
}
inline int Rotator::getSessId() const {
return mRot.getSessId(); }
inline void Rotator::dump() const {
ALOGE("== Dump Rotator start ==");
mRot.dump();
ALOGE("== Dump Rotator end ==");
}
inline overlay::utils::Whf Rotator::getSrcWhf() const {
return mRot.getSrcWhf(); }
inline bool Rotator::prepareQueueBuf(uint32_t offset)
{
return mRot.prepareQueueBuf(offset);
}
inline bool Rotator::play(int fd)
{
return mRot.play(fd);
}
template <int ROT_OUT_FMT>
bool MdpRot::start(const utils::PipeArgs& args) {
// Do nothing when no orientation
if(utils::OVERLAY_TRANSFORM_0 == args.orientation &&
utils::ROT_FLAG_ENABLED != args.rotFlags) {
return true;
}
utils::Whf whf(args.whf);
mRotImgInfo.src.format = whf.format;
mRotImgInfo.src.width = whf.w;
mRotImgInfo.src.height = whf.h;
mRotImgInfo.src_rect.w = whf.w;
mRotImgInfo.src_rect.h = whf.h;
mRotImgInfo.dst.width = whf.w;
mRotImgInfo.dst.height = whf.h;
if(whf.format == MDP_Y_CRCB_H2V2_TILE ||
whf.format == MDP_Y_CBCR_H2V2_TILE) {
mRotImgInfo.src.width = utils::alignup(whf.w, 64);
mRotImgInfo.src.height = utils::alignup(whf.h, 32);
mRotImgInfo.src_rect.w = utils::alignup(whf.w, 64);
mRotImgInfo.src_rect.h = utils::alignup(whf.h, 32);
mRotImgInfo.dst.width = utils::alignup(whf.w, 64);
mRotImgInfo.dst.height = utils::alignup(whf.h, 32);
mRotImgInfo.dst.format = MDP_Y_CRCB_H2V2;
}
// either utils::getRotOutFmt(whf.format); or supplied fmt
// utils::RotOutFmt<ROT_OUT_FMT_DEFAULT>::fmt;
mRotImgInfo.dst.format = utils::RotOutFmt<ROT_OUT_FMT>::fmt(whf.format);
mRotImgInfo.dst_x = 0;
mRotImgInfo.dst_y = 0;
mRotImgInfo.src_rect.x = 0;
mRotImgInfo.src_rect.y = 0;
mRotImgInfo.rotations = 0;
// ROT_FLAG_DISABLED / ENABLED
// Refer to overlayUtils.h eRotFlags
// for more info
mRotImgInfo.enable = args.rotFlags;
mRotImgInfo.session_id = mRotImgInfo.session_id ?
mRotImgInfo.session_id : 0;
return start();
}
} // overlay
namespace {
// just a helper func for Rotator common operations x-(y+z)
int compute(uint32_t x, uint32_t y, uint32_t z) {
return x-(y+z);
}
}
#endif // OVERLAY_ROTATOR_H

907
liboverlay/overlayState.h Normal file
View File

@ -0,0 +1,907 @@
/*
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OVERLAY_STATE_H
#define OVERLAY_STATE_H
#include "overlayUtils.h"
#include "overlayImpl.h"
#include "overlayRotator.h"
#include "pipes/overlayGenPipe.h"
#include "pipes/overlayBypassPipe.h"
#include "pipes/overlayHdmiPipe.h"
#include "pipes/overlayUIMirrorPipe.h"
#include "pipes/overlay3DPipe.h"
// FIXME make int to be uint32 whenever possible
namespace overlay {
/*
* Used by Overlay class. Invokes each event
* */
/* TODO case of RGBx will call mOv open with diff
* params customized for RGBx pipes */
class OverlayState : utils::NoCopy {
public:
/**/
explicit OverlayState();
/**/
~OverlayState();
/* return current state */
utils::eOverlayState state() const;
/* Overlay Event */
/* Hard reset to a new state. If the state is the same
* as the current one, it would be a no-op */
OverlayImplBase* reset(utils::eOverlayState s);
/* Caller pass the state to the handleEvent function.
* The input is the current OverlayImplBase*, and output is
* a pointer to (possibly new) instance of OverlayImplBase
* The eFormat can be 2D/3D etc. */
OverlayImplBase* handleEvent(utils::eOverlayState s,
OverlayImplBase* ov);
/* Transitions from XXX to XXX */
OverlayImplBase* handle_closed(utils::eOverlayState s);
OverlayImplBase* handle_2D_2DPanel(utils::eOverlayState s,
OverlayImplBase* ov);
OverlayImplBase* handle_2D_2DTV(utils::eOverlayState s,
OverlayImplBase* ov);
OverlayImplBase* handle_3D_2DPanel(utils::eOverlayState s,
OverlayImplBase* ov);
OverlayImplBase* handle_3D_3DPanel(utils::eOverlayState s,
OverlayImplBase* ov);
OverlayImplBase* handle_3D_3DTV(utils::eOverlayState s,
OverlayImplBase* ov);
OverlayImplBase* handle_3D_2DTV(utils::eOverlayState s,
OverlayImplBase* ov);
OverlayImplBase* handle_UI_Mirror(utils::eOverlayState s,
OverlayImplBase* ov);
OverlayImplBase* handle_2D_trueUI_Mirror(utils::eOverlayState s,
OverlayImplBase* ov);
OverlayImplBase* handle_bypass(utils::eOverlayState s,
OverlayImplBase* ov);
/* Transition from any state to 2D video on 2D panel */
OverlayImplBase* handle_xxx_to_2D_2DPanel(OverlayImplBase* ov);
/* Transition from any state to 2D video on 2D panel and 2D TV */
OverlayImplBase* handle_xxx_to_2D_2DTV(OverlayImplBase* ov);
/* Transition from any state to 3D video on 2D panel */
OverlayImplBase* handle_xxx_to_3D_2DPanel(OverlayImplBase* ov);
/* Transition from any state to 3D video on 2D panel and 2D TV */
OverlayImplBase* handle_xxx_to_3D_2DTV(OverlayImplBase* ov);
/* Transition from any state to 2D video true UI mirroring (2D video + UI) */
OverlayImplBase* handle_xxx_to_2D_trueUI_Mirror(OverlayImplBase* ov);
/* Transitions from any state to 1 layer composition bypass */
OverlayImplBase* handle_xxx_to_bypass1(OverlayImplBase* ov);
/* Transitions from any state to 2 layers composition bypass */
OverlayImplBase* handle_xxx_to_bypass2(OverlayImplBase* ov);
/* Transitions from any state to 3 layers composition bypass */
OverlayImplBase* handle_xxx_to_bypass3(OverlayImplBase* ov);
/* Dump */
void dump() const;
private:
/* States here */
utils::eOverlayState mState;
};
//------------------------State Traits --------------------------
// primary has nothing
template <int STATE> struct StateTraits {};
/*
* For 3D_xxx we need channel ID besides the FBx since
* get crop/position 3D need that to determine pos/crop
* info.
* */
template <> struct StateTraits<utils::OV_2D_VIDEO_ON_PANEL>
{
typedef overlay::GenericPipe<utils::PRIMARY> pipe0;
typedef overlay::NullPipe pipe1; // place holder
typedef overlay::NullPipe pipe2; // place holder
typedef Rotator rot0;
typedef NullRotator rot1;
typedef NullRotator rot2;
typedef overlay::OverlayImpl<pipe0> ovimpl;
};
template <> struct StateTraits<utils::OV_2D_VIDEO_ON_PANEL_TV>
{
typedef overlay::GenericPipe<utils::PRIMARY> pipe0;
typedef overlay::HdmiPipe pipe1;
typedef overlay::NullPipe pipe2; // place holder
typedef Rotator rot0;
typedef NullRotator rot1;
typedef NullRotator rot2;
typedef overlay::OverlayImpl<pipe0, pipe1> ovimpl;
};
template <> struct StateTraits<utils::OV_3D_VIDEO_ON_2D_PANEL>
{
typedef overlay::M3DPrimaryPipe<utils::OV_PIPE0> pipe0;
typedef overlay::NullPipe pipe1; // place holder
typedef overlay::NullPipe pipe2; // place holder
typedef Rotator rot0;
typedef NullRotator rot1;
typedef NullRotator rot2;
typedef overlay::OverlayImpl<pipe0> ovimpl;
};
template <> struct StateTraits<utils::OV_3D_VIDEO_ON_3D_PANEL>
{
typedef overlay::S3DPrimaryPipe<utils::OV_PIPE0> pipe0;
typedef overlay::S3DPrimaryPipe<utils::OV_PIPE1> pipe1;
typedef overlay::NullPipe pipe2; // place holder
typedef Rotator rot0;
typedef Rotator rot1;
typedef NullRotator rot2;
typedef overlay::OverlayImpl<pipe0, pipe1> ovimpl;
};
template <> struct StateTraits<utils::OV_3D_VIDEO_ON_3D_TV>
{
typedef overlay::S3DExtPipe<utils::OV_PIPE0> pipe0;
typedef overlay::S3DExtPipe<utils::OV_PIPE1> pipe1;
typedef overlay::NullPipe pipe2; // place holder
typedef NullRotator rot0;
typedef NullRotator rot1;
typedef NullRotator rot2;
typedef overlay::OverlayImpl<pipe0, pipe1> ovimpl;
};
template <> struct StateTraits<utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV>
{
typedef overlay::M3DPrimaryPipe<utils::OV_PIPE0> pipe0;
typedef overlay::M3DExtPipe<utils::OV_PIPE1> pipe1;
typedef overlay::NullPipe pipe2; // place holder
typedef Rotator rot0;
typedef NullRotator rot1;
typedef NullRotator rot2;
typedef overlay::OverlayImpl<pipe0, pipe1> ovimpl;
};
template <> struct StateTraits<utils::OV_UI_MIRROR>
{
typedef overlay::UIMirrorPipe pipe0;
typedef overlay::NullPipe pipe1; // place holder
typedef overlay::NullPipe pipe2; // place holder
typedef Rotator rot0;
typedef NullRotator rot1;
typedef NullRotator rot2;
typedef overlay::OverlayImpl<pipe0> ovimpl;
};
template <> struct StateTraits<utils::OV_2D_TRUE_UI_MIRROR>
{
typedef overlay::GenericPipe<utils::PRIMARY> pipe0;
typedef overlay::HdmiPipe pipe1;
typedef overlay::UIMirrorPipe pipe2;
typedef Rotator rot0;
typedef NullRotator rot1;
typedef Rotator rot2;
typedef overlay::OverlayImpl<pipe0, pipe1, pipe2> ovimpl;
};
template <> struct StateTraits<utils::OV_BYPASS_1_LAYER>
{
typedef overlay::BypassPipe<utils::OV_MDP_PIPE_VG, utils::IS_FG_SET, utils::WAIT, utils::ZORDER_0> pipe0;
typedef overlay::NullPipe pipe1; // place holder
typedef overlay::NullPipe pipe2; // place holder
typedef NullRotator rot0;
typedef NullRotator rot1;
typedef NullRotator rot2;
typedef overlay::OverlayImpl<pipe0> ovimpl;
};
template <> struct StateTraits<utils::OV_BYPASS_2_LAYER>
{
typedef overlay::BypassPipe<utils::OV_MDP_PIPE_VG, utils::IS_FG_SET, utils::NO_WAIT, utils::ZORDER_0> pipe0;
typedef overlay::BypassPipe<utils::OV_MDP_PIPE_VG, utils::IS_FG_OFF, utils::WAIT, utils::ZORDER_1> pipe1;
typedef overlay::NullPipe pipe2; // place holder
typedef NullRotator rot0;
typedef NullRotator rot1;
typedef NullRotator rot2;
typedef overlay::OverlayImpl<pipe0, pipe1> ovimpl;
};
template <> struct StateTraits<utils::OV_BYPASS_3_LAYER>
{
typedef overlay::BypassPipe<utils::OV_MDP_PIPE_VG, utils::IS_FG_SET, utils::NO_WAIT, utils::ZORDER_0> pipe0;
typedef overlay::BypassPipe<utils::OV_MDP_PIPE_VG, utils::IS_FG_OFF, utils::NO_WAIT, utils::ZORDER_1> pipe1;
typedef overlay::BypassPipe<utils::OV_MDP_PIPE_RGB, utils::IS_FG_OFF, utils::WAIT, utils::ZORDER_2> pipe2;
typedef NullRotator rot0;
typedef NullRotator rot1;
typedef NullRotator rot2;
typedef overlay::OverlayImpl<pipe0, pipe1, pipe2> ovimpl;
};
//------------------------Inlines --------------------------------
inline OverlayState::OverlayState() : mState(utils::OV_CLOSED)
{}
inline OverlayState::~OverlayState() {}
inline utils::eOverlayState OverlayState::state() const
{
return mState;
}
inline OverlayImplBase* OverlayState::reset(utils::eOverlayState s)
{
return handleEvent(s, 0);
}
inline void OverlayState::dump() const
{
ALOGE("== Dump state %d start/end ==", mState);
}
template <int STATE>
inline OverlayImplBase* handle_closed_to_xxx()
{
OverlayImplBase* ov = new typename StateTraits<STATE>::ovimpl;
RotatorBase* rot0 = new typename StateTraits<STATE>::rot0;
RotatorBase* rot1 = new typename StateTraits<STATE>::rot1;
RotatorBase* rot2 = new typename StateTraits<STATE>::rot2;
if(!ov->open(rot0, rot1, rot2)) {
ALOGE("Overlay failed to open in state %d", STATE);
return 0;
}
return ov;
}
inline OverlayImplBase* handle_xxx_to_closed(OverlayImplBase* ov)
{
OVASSERT(ov, "%s: ov is null", __FUNCTION__);
if(!ov->close()) {
ALOGE("%s: Failed to ov close", __FUNCTION__);
}
delete ov;
ov = 0;
return 0;
}
/* Hard transitions from any state to any state will close and then open */
template <int STATE>
inline OverlayImplBase* handle_xxx_to_xxx(OverlayImplBase* ov)
{
OVASSERT(ov, "%s: ov is null", __FUNCTION__);
handle_xxx_to_closed(ov);
return handle_closed_to_xxx<STATE>();
}
inline OverlayImplBase* OverlayState::handleEvent(utils::eOverlayState newState,
OverlayImplBase* ov)
{
OverlayImplBase* newov = ov; // at least, we return the same
if (mState != newState) {
ALOGE_IF(DEBUG_OVERLAY, "%s: state changed %s-->%s",
__FUNCTION__, getStateString(mState), getStateString(newState));
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: no state change, state=%s",
__FUNCTION__, getStateString(newState));
return newov;
}
switch(mState)
{
case utils::OV_CLOSED:
newov = handle_closed(newState);
break;
case utils::OV_2D_VIDEO_ON_PANEL:
newov = handle_2D_2DPanel(newState, ov);
break;
case utils::OV_2D_VIDEO_ON_PANEL_TV:
newov = handle_2D_2DTV(newState, ov);
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL:
newov = handle_3D_2DPanel(newState, ov);
break;
case utils::OV_3D_VIDEO_ON_3D_PANEL:
newov = handle_3D_3DPanel(newState, ov);
break;
case utils::OV_3D_VIDEO_ON_3D_TV:
newov = handle_3D_3DTV(newState, ov);
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
newov = handle_3D_2DTV(newState, ov);
break;
case utils::OV_UI_MIRROR:
newov = handle_UI_Mirror(newState, ov);
break;
case utils::OV_2D_TRUE_UI_MIRROR:
newov = handle_2D_trueUI_Mirror(newState, ov);
break;
case utils::OV_BYPASS_1_LAYER:
case utils::OV_BYPASS_2_LAYER:
case utils::OV_BYPASS_3_LAYER:
newov = handle_bypass(newState, ov);
break;
default:
ALOGE("%s: unknown state=%d", __FUNCTION__, mState);
}
// FIXME, how to communicate bad transition?
// Should we have bool returned from transition func?
return newov;
}
// Transitions from closed to XXX
inline OverlayImplBase* OverlayState::handle_closed(utils::eOverlayState s)
{
OverlayImplBase* ov = 0;
switch(s)
{
case utils::OV_CLOSED:
// no state change
break;
case utils::OV_2D_VIDEO_ON_PANEL:
ov = handle_closed_to_xxx<utils::OV_2D_VIDEO_ON_PANEL>();
break;
case utils::OV_2D_VIDEO_ON_PANEL_TV:
ov = handle_closed_to_xxx<utils::OV_2D_VIDEO_ON_PANEL_TV>();
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL:
ov = handle_closed_to_xxx<utils::OV_3D_VIDEO_ON_2D_PANEL>();
break;
case utils::OV_3D_VIDEO_ON_3D_PANEL:
ov = handle_closed_to_xxx<utils::OV_3D_VIDEO_ON_3D_PANEL>();
break;
case utils::OV_3D_VIDEO_ON_3D_TV:
ov = handle_closed_to_xxx<utils::OV_3D_VIDEO_ON_3D_TV>();
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
ov = handle_closed_to_xxx<utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV>();
break;
case utils::OV_UI_MIRROR:
ov = handle_closed_to_xxx<utils::OV_UI_MIRROR>();
break;
case utils::OV_2D_TRUE_UI_MIRROR:
ov = handle_closed_to_xxx<utils::OV_2D_TRUE_UI_MIRROR>();
break;
case utils::OV_BYPASS_1_LAYER:
ov = handle_closed_to_xxx<utils::OV_BYPASS_1_LAYER>();
break;
case utils::OV_BYPASS_2_LAYER:
ov = handle_closed_to_xxx<utils::OV_BYPASS_2_LAYER>();
break;
case utils::OV_BYPASS_3_LAYER:
ov = handle_closed_to_xxx<utils::OV_BYPASS_3_LAYER>();
break;
default:
ALOGE("%s: unknown state=%d", __FUNCTION__, s);
}
mState = s;
return ov;
}
// Transitions from 2D video on 2D panel to XXX
inline OverlayImplBase* OverlayState::handle_2D_2DPanel(
utils::eOverlayState s,
OverlayImplBase* ov)
{
OverlayImplBase* newov = ov;
switch(s)
{
case utils::OV_CLOSED:
newov = handle_xxx_to_closed(ov);
break;
case utils::OV_2D_VIDEO_ON_PANEL:
// no state change
break;
case utils::OV_2D_VIDEO_ON_PANEL_TV:
newov = handle_xxx_to_2D_2DTV(ov);
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_2D_PANEL>(ov);
break;
case utils::OV_3D_VIDEO_ON_3D_PANEL:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_3D_PANEL>(ov);
break;
case utils::OV_3D_VIDEO_ON_3D_TV:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_3D_TV>(ov);
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV>(ov);
break;
case utils::OV_UI_MIRROR:
newov = handle_xxx_to_xxx<utils::OV_UI_MIRROR>(ov);
break;
case utils::OV_2D_TRUE_UI_MIRROR:
newov = handle_xxx_to_2D_trueUI_Mirror(ov);
break;
case utils::OV_BYPASS_1_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_1_LAYER>(ov);
break;
case utils::OV_BYPASS_2_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_2_LAYER>(ov);
break;
case utils::OV_BYPASS_3_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_3_LAYER>(ov);
break;
default:
ALOGE("%s: unknown state=%d", __FUNCTION__, s);
}
mState = s;
return newov;
}
// Transitions from 2D video on 2D panel and 2D TV to XXX
inline OverlayImplBase* OverlayState::handle_2D_2DTV(
utils::eOverlayState s,
OverlayImplBase* ov)
{
OverlayImplBase* newov = ov;
switch(s)
{
case utils::OV_CLOSED:
newov = handle_xxx_to_closed(ov);
break;
case utils::OV_2D_VIDEO_ON_PANEL:
newov = handle_xxx_to_2D_2DPanel(ov);
break;
case utils::OV_2D_VIDEO_ON_PANEL_TV:
// no state change
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_2D_PANEL>(ov);
break;
case utils::OV_3D_VIDEO_ON_3D_PANEL:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_3D_PANEL>(ov);
break;
case utils::OV_3D_VIDEO_ON_3D_TV:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_3D_TV>(ov);
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV>(ov);
break;
case utils::OV_UI_MIRROR:
newov = handle_xxx_to_xxx<utils::OV_UI_MIRROR>(ov);
break;
case utils::OV_2D_TRUE_UI_MIRROR:
newov = handle_xxx_to_2D_trueUI_Mirror(ov);
break;
case utils::OV_BYPASS_1_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_1_LAYER>(ov);
break;
case utils::OV_BYPASS_2_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_2_LAYER>(ov);
break;
case utils::OV_BYPASS_3_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_3_LAYER>(ov);
break;
default:
ALOGE("%s: unknown state=%d", __FUNCTION__, s);
}
mState = s;
return newov;
}
// Transitions from 3D video on 2D panel to XXX
inline OverlayImplBase* OverlayState::handle_3D_2DPanel(
utils::eOverlayState s,
OverlayImplBase* ov)
{
OverlayImplBase* newov = ov;
switch(s)
{
case utils::OV_CLOSED:
newov = handle_xxx_to_closed(ov);
break;
case utils::OV_2D_VIDEO_ON_PANEL:
newov = handle_xxx_to_xxx<utils::OV_2D_VIDEO_ON_PANEL>(ov);
break;
case utils::OV_2D_VIDEO_ON_PANEL_TV:
newov = handle_xxx_to_xxx<utils::OV_2D_VIDEO_ON_PANEL_TV>(ov);
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL:
// no state change
break;
case utils::OV_3D_VIDEO_ON_3D_PANEL:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_3D_PANEL>(ov);
break;
case utils::OV_3D_VIDEO_ON_3D_TV:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_3D_TV>(ov);
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
newov = handle_xxx_to_3D_2DTV(ov);
break;
case utils::OV_UI_MIRROR:
newov = handle_xxx_to_xxx<utils::OV_UI_MIRROR>(ov);
break;
case utils::OV_2D_TRUE_UI_MIRROR:
newov = handle_xxx_to_xxx<utils::OV_2D_TRUE_UI_MIRROR>(ov);
break;
case utils::OV_BYPASS_1_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_1_LAYER>(ov);
break;
case utils::OV_BYPASS_2_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_2_LAYER>(ov);
break;
case utils::OV_BYPASS_3_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_3_LAYER>(ov);
break;
default:
ALOGE("%s: unknown state=%d", __FUNCTION__, s);
}
mState = s;
return newov;
}
// Transitions from 3D video on 3D panel to XXX
inline OverlayImplBase* OverlayState::handle_3D_3DPanel(
utils::eOverlayState s,
OverlayImplBase* ov)
{
OverlayImplBase* newov = ov;
switch(s)
{
case utils::OV_CLOSED:
newov = handle_xxx_to_closed(ov);
break;
case utils::OV_2D_VIDEO_ON_PANEL:
newov = handle_xxx_to_xxx<utils::OV_2D_VIDEO_ON_PANEL>(ov);
break;
case utils::OV_2D_VIDEO_ON_PANEL_TV:
newov = handle_xxx_to_xxx<utils::OV_2D_VIDEO_ON_PANEL_TV>(ov);
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_2D_PANEL>(ov);
break;
case utils::OV_3D_VIDEO_ON_3D_PANEL:
// no state change
break;
case utils::OV_3D_VIDEO_ON_3D_TV:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_3D_TV>(ov);
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV>(ov);
break;
case utils::OV_UI_MIRROR:
newov = handle_xxx_to_xxx<utils::OV_UI_MIRROR>(ov);
break;
case utils::OV_2D_TRUE_UI_MIRROR:
newov = handle_xxx_to_xxx<utils::OV_2D_TRUE_UI_MIRROR>(ov);
break;
case utils::OV_BYPASS_1_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_1_LAYER>(ov);
break;
case utils::OV_BYPASS_2_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_2_LAYER>(ov);
break;
case utils::OV_BYPASS_3_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_3_LAYER>(ov);
break;
default:
ALOGE("%s: unknown state=%d", __FUNCTION__, s);
}
mState = s;
return newov;
}
// Transitions from 3D video on 3D TV to XXX
inline OverlayImplBase* OverlayState::handle_3D_3DTV(
utils::eOverlayState s,
OverlayImplBase* ov)
{
OverlayImplBase* newov = ov;
switch(s)
{
case utils::OV_CLOSED:
newov = handle_xxx_to_closed(ov);
break;
case utils::OV_2D_VIDEO_ON_PANEL:
newov = handle_xxx_to_xxx<utils::OV_2D_VIDEO_ON_PANEL>(ov);
break;
case utils::OV_2D_VIDEO_ON_PANEL_TV:
newov = handle_xxx_to_xxx<utils::OV_2D_VIDEO_ON_PANEL_TV>(ov);
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_2D_PANEL>(ov);
break;
case utils::OV_3D_VIDEO_ON_3D_PANEL:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_3D_PANEL>(ov);
break;
case utils::OV_3D_VIDEO_ON_3D_TV:
// no state change
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV>(ov);
break;
case utils::OV_UI_MIRROR:
newov = handle_xxx_to_xxx<utils::OV_UI_MIRROR>(ov);
break;
case utils::OV_2D_TRUE_UI_MIRROR:
newov = handle_xxx_to_xxx<utils::OV_2D_TRUE_UI_MIRROR>(ov);
break;
case utils::OV_BYPASS_1_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_1_LAYER>(ov);
break;
case utils::OV_BYPASS_2_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_2_LAYER>(ov);
break;
case utils::OV_BYPASS_3_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_3_LAYER>(ov);
break;
default:
ALOGE("%s: unknown state=%d", __FUNCTION__, s);
}
mState = s;
return newov;
}
// Transitions from 3D video on 2D panel and 2D TV to XXX
inline OverlayImplBase* OverlayState::handle_3D_2DTV(
utils::eOverlayState s,
OverlayImplBase* ov)
{
OverlayImplBase* newov = ov;
switch(s)
{
case utils::OV_CLOSED:
newov = handle_xxx_to_closed(ov);
break;
case utils::OV_2D_VIDEO_ON_PANEL:
newov = handle_xxx_to_xxx<utils::OV_2D_VIDEO_ON_PANEL>(ov);
break;
case utils::OV_2D_VIDEO_ON_PANEL_TV:
newov = handle_xxx_to_xxx<utils::OV_2D_VIDEO_ON_PANEL_TV>(ov);
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL:
newov = handle_xxx_to_3D_2DPanel(ov);
break;
case utils::OV_3D_VIDEO_ON_3D_PANEL:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_3D_PANEL>(ov);
break;
case utils::OV_3D_VIDEO_ON_3D_TV:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_3D_TV>(ov);
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
// no state change
break;
case utils::OV_UI_MIRROR:
newov = handle_xxx_to_xxx<utils::OV_UI_MIRROR>(ov);
break;
case utils::OV_2D_TRUE_UI_MIRROR:
newov = handle_xxx_to_xxx<utils::OV_2D_TRUE_UI_MIRROR>(ov);
break;
case utils::OV_BYPASS_1_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_1_LAYER>(ov);
break;
case utils::OV_BYPASS_2_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_2_LAYER>(ov);
break;
case utils::OV_BYPASS_3_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_3_LAYER>(ov);
break;
default:
ALOGE("%s: unknown state=%d", __FUNCTION__, s);
}
mState = s;
return newov;
}
// Transitions from UI mirroring to XXX
inline OverlayImplBase* OverlayState::handle_UI_Mirror(utils::eOverlayState s,
OverlayImplBase* ov)
{
OverlayImplBase* newov = ov;
switch(s)
{
case utils::OV_CLOSED:
newov = handle_xxx_to_closed(ov);
break;
case utils::OV_2D_VIDEO_ON_PANEL:
newov = handle_xxx_to_xxx<utils::OV_2D_VIDEO_ON_PANEL>(ov);
break;
case utils::OV_2D_VIDEO_ON_PANEL_TV:
newov = handle_xxx_to_xxx<utils::OV_2D_VIDEO_ON_PANEL_TV>(ov);
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_2D_PANEL>(ov);
break;
case utils::OV_3D_VIDEO_ON_3D_PANEL:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_3D_PANEL>(ov);
break;
case utils::OV_3D_VIDEO_ON_3D_TV:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_3D_TV>(ov);
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV>(ov);
break;
case utils::OV_UI_MIRROR:
// no state change
break;
case utils::OV_2D_TRUE_UI_MIRROR:
newov = handle_xxx_to_xxx<utils::OV_2D_TRUE_UI_MIRROR>(ov);
break;
case utils::OV_BYPASS_1_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_1_LAYER>(ov);
break;
case utils::OV_BYPASS_2_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_2_LAYER>(ov);
break;
case utils::OV_BYPASS_3_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_3_LAYER>(ov);
break;
default:
ALOGE("%s: unknown state=%d", __FUNCTION__, s);
}
mState = s;
return newov;
}
// Transitions from 2D video true UI mirroring (2D video + UI) to XXX
inline OverlayImplBase* OverlayState::handle_2D_trueUI_Mirror(utils::eOverlayState s,
OverlayImplBase* ov)
{
OverlayImplBase* newov = ov;
switch(s)
{
case utils::OV_CLOSED:
newov = handle_xxx_to_closed(ov);
break;
case utils::OV_2D_VIDEO_ON_PANEL:
newov = handle_xxx_to_2D_2DPanel(ov);
break;
case utils::OV_2D_VIDEO_ON_PANEL_TV:
newov = handle_xxx_to_2D_2DTV(ov);
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_2D_PANEL>(ov);
break;
case utils::OV_3D_VIDEO_ON_3D_PANEL:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_3D_PANEL>(ov);
break;
case utils::OV_3D_VIDEO_ON_3D_TV:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_3D_TV>(ov);
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV>(ov);
break;
case utils::OV_UI_MIRROR:
newov = handle_xxx_to_xxx<utils::OV_UI_MIRROR>(ov);
break;
case utils::OV_2D_TRUE_UI_MIRROR:
// no state change
break;
case utils::OV_BYPASS_1_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_1_LAYER>(ov);
break;
case utils::OV_BYPASS_2_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_2_LAYER>(ov);
break;
case utils::OV_BYPASS_3_LAYER:
newov = handle_xxx_to_xxx<utils::OV_BYPASS_3_LAYER>(ov);
break;
default:
ALOGE("%s: unknown state=%d", __FUNCTION__, s);
}
mState = s;
return newov;
}
// Transitions from composition bypass to XXX
inline OverlayImplBase* OverlayState::handle_bypass(utils::eOverlayState s,
OverlayImplBase* ov)
{
OverlayImplBase* newov = ov;
switch(s)
{
case utils::OV_CLOSED:
newov = handle_xxx_to_closed(ov);
break;
case utils::OV_2D_VIDEO_ON_PANEL:
newov = handle_xxx_to_xxx<utils::OV_2D_VIDEO_ON_PANEL>(ov);
break;
case utils::OV_2D_VIDEO_ON_PANEL_TV:
newov = handle_xxx_to_xxx<utils::OV_2D_VIDEO_ON_PANEL_TV>(ov);
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_2D_PANEL>(ov);
break;
case utils::OV_3D_VIDEO_ON_3D_PANEL:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_3D_PANEL>(ov);
break;
case utils::OV_3D_VIDEO_ON_3D_TV:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_3D_TV>(ov);
break;
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
newov = handle_xxx_to_xxx<utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV>(ov);
break;
case utils::OV_UI_MIRROR:
newov = handle_xxx_to_xxx<utils::OV_UI_MIRROR>(ov);
break;
case utils::OV_2D_TRUE_UI_MIRROR:
newov = handle_xxx_to_xxx<utils::OV_2D_TRUE_UI_MIRROR>(ov);
break;
case utils::OV_BYPASS_1_LAYER:
newov = handle_xxx_to_bypass1(ov);
break;
case utils::OV_BYPASS_2_LAYER:
newov = handle_xxx_to_bypass2(ov);
break;
case utils::OV_BYPASS_3_LAYER:
newov = handle_xxx_to_bypass3(ov);
break;
default:
ALOGE("%s: unknown state=%d", __FUNCTION__, s);
}
mState = s;
return newov;
}
} // overlay
#endif // OVERLAY_STATE_H

View File

@ -0,0 +1,503 @@
/*
* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "overlayState.h"
namespace overlay {
/*
* Transition from any state to 2D video on 2D panel
*/
OverlayImplBase* OverlayState::handle_xxx_to_2D_2DPanel(
OverlayImplBase* ov)
{
OVASSERT(ov, "%s: ov is null", __FUNCTION__);
ALOGE("%s", __FUNCTION__);
// Create new ovimpl based on new state
typedef StateTraits<utils::OV_2D_VIDEO_ON_PANEL> NewState;
OverlayImplBase* newov = new NewState::ovimpl;
//===========================================================
// For each pipe:
// - If pipe matches, copy from previous into new ovimpl
// - Otherwise open for new and delete from previous ovimpl
//===========================================================
// pipe0/rot0 (GenericPipe)
if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_GENERIC) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (GenericPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE0);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe0 (GenericPipe)", __FUNCTION__);
RotatorBase* rot0 = new NewState::rot0;
ov->closePipe(utils::OV_PIPE0);
newov->openPipe(rot0, utils::OV_PIPE0);
}
// pipe1/rot1 (NullPipe)
if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_NULL) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (NullPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE1);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe1 (NullPipe)", __FUNCTION__);
RotatorBase* rot1 = new NewState::rot1;
ov->closePipe(utils::OV_PIPE1);
newov->openPipe(rot1, utils::OV_PIPE1);
}
// pipe2/rot2 (NullPipe)
if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_NULL) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (NullPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE2);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe2 (NullPipe)", __FUNCTION__);
RotatorBase* rot2 = new NewState::rot2;
ov->closePipe(utils::OV_PIPE2);
newov->openPipe(rot2, utils::OV_PIPE2);
}
// All pipes are copied or deleted so no more need for previous ovimpl
delete ov;
ov = 0;
return newov;
}
/*
* Transition from any state to 2D video on 2D panel and 2D TV
*/
OverlayImplBase* OverlayState::handle_xxx_to_2D_2DTV(
OverlayImplBase* ov)
{
OVASSERT(ov, "%s: ov is null", __FUNCTION__);
ALOGE("%s", __FUNCTION__);
// Create new ovimpl based on new state
typedef StateTraits<utils::OV_2D_VIDEO_ON_PANEL_TV> NewState;
OverlayImplBase* newov = new NewState::ovimpl;
//===========================================================
// For each pipe:
// - If pipe matches, copy from previous into new ovimpl
// - Otherwise open for new and delete from previous ovimpl
//===========================================================
// pipe0/rot0 (GenericPipe)
if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_GENERIC) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (GenericPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE0);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe0 (GenericPipe)", __FUNCTION__);
RotatorBase* rot0 = new NewState::rot0;
ov->closePipe(utils::OV_PIPE0);
newov->openPipe(rot0, utils::OV_PIPE0);
}
// pipe1/rot1 (HdmiPipe)
if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_HDMI) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (HdmiPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE1);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe1 (HdmiPipe)", __FUNCTION__);
RotatorBase* rot1 = new NewState::rot1;
ov->closePipe(utils::OV_PIPE1);
newov->openPipe(rot1, utils::OV_PIPE1);
}
// pipe2/rot2 (NullPipe)
if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_NULL) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (NullPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE2);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe2 (NullPipe)", __FUNCTION__);
RotatorBase* rot2 = new NewState::rot2;
ov->closePipe(utils::OV_PIPE2);
newov->openPipe(rot2, utils::OV_PIPE2);
}
// All pipes are copied or deleted so no more need for previous ovimpl
delete ov;
ov = 0;
return newov;
}
/*
* Transition from any state to 3D video on 2D panel
*/
OverlayImplBase* OverlayState::handle_xxx_to_3D_2DPanel(
OverlayImplBase* ov)
{
OVASSERT(ov, "%s: ov is null", __FUNCTION__);
ALOGE("%s", __FUNCTION__);
// Create new ovimpl based on new state
typedef StateTraits<utils::OV_3D_VIDEO_ON_2D_PANEL> NewState;
OverlayImplBase* newov = new NewState::ovimpl;
//===========================================================
// For each pipe:
// - If pipe matches, copy from previous into new ovimpl
// - Otherwise open for new and delete from previous ovimpl
//===========================================================
// pipe0/rot0 (M3DPrimaryPipe)
if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_M3D_PRIMARY) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (M3DPrimaryPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE0);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe0 (M3DPrimaryPipe)", __FUNCTION__);
RotatorBase* rot0 = new NewState::rot0;
ov->closePipe(utils::OV_PIPE0);
newov->openPipe(rot0, utils::OV_PIPE0);
}
// pipe1/rot1 (NullPipe)
if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_NULL) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (NullPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE1);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe1 (NullPipe)", __FUNCTION__);
RotatorBase* rot1 = new NewState::rot1;
ov->closePipe(utils::OV_PIPE1);
newov->openPipe(rot1, utils::OV_PIPE1);
}
// pipe2/rot2 (NullPipe)
if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_NULL) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (NullPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE2);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe2 (NullPipe)", __FUNCTION__);
RotatorBase* rot2 = new NewState::rot2;
ov->closePipe(utils::OV_PIPE2);
newov->openPipe(rot2, utils::OV_PIPE2);
}
// All pipes are copied or deleted so no more need for previous ovimpl
delete ov;
ov = 0;
return newov;
}
/*
* Transition from any state to 3D video on 2D panel and 2D TV
*/
OverlayImplBase* OverlayState::handle_xxx_to_3D_2DTV(
OverlayImplBase* ov)
{
OVASSERT(ov, "%s: ov is null", __FUNCTION__);
ALOGE("%s", __FUNCTION__);
// Create new ovimpl based on new state
typedef StateTraits<utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV> NewState;
OverlayImplBase* newov = new NewState::ovimpl;
//===========================================================
// For each pipe:
// - If pipe matches, copy from previous into new ovimpl
// - Otherwise open for new and delete from previous ovimpl
//===========================================================
// pipe0/rot0 (M3DPrimaryPipe)
if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_M3D_PRIMARY) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (M3DPrimaryPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE0);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe0 (M3DPrimaryPipe)", __FUNCTION__);
RotatorBase* rot0 = new NewState::rot0;
ov->closePipe(utils::OV_PIPE0);
newov->openPipe(rot0, utils::OV_PIPE0);
}
// pipe1/rot1 (M3DExtPipe)
if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_M3D_EXTERNAL) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (M3DExtPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE1);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe1 (M3DExtPipe)", __FUNCTION__);
RotatorBase* rot1 = new NewState::rot1;
ov->closePipe(utils::OV_PIPE1);
newov->openPipe(rot1, utils::OV_PIPE1);
}
// pipe2/rot2 (NullPipe)
if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_NULL) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (NullPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE2);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe2 (NullPipe)", __FUNCTION__);
RotatorBase* rot2 = new NewState::rot2;
ov->closePipe(utils::OV_PIPE2);
newov->openPipe(rot2, utils::OV_PIPE2);
}
// All pipes are copied or deleted so no more need for previous ovimpl
delete ov;
ov = 0;
return newov;
}
/*
* Transition from any state to 2D true UI mirroring (2D video + UI)
*/
OverlayImplBase* OverlayState::handle_xxx_to_2D_trueUI_Mirror(
OverlayImplBase* ov)
{
OVASSERT(ov, "%s: ov is null", __FUNCTION__);
ALOGE("%s", __FUNCTION__);
// Create new ovimpl based on new state
typedef StateTraits<utils::OV_2D_TRUE_UI_MIRROR> NewState;
OverlayImplBase* newov = new NewState::ovimpl;
//===========================================================
// For each pipe:
// - If pipe matches, copy from previous into new ovimpl
// - Otherwise open for new and delete from previous ovimpl
//===========================================================
// pipe0/rot0 (GenericPipe)
if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_GENERIC) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (GenericPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE0);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe0 (GenericPipe)", __FUNCTION__);
RotatorBase* rot0 = new NewState::rot0;
ov->closePipe(utils::OV_PIPE0);
newov->openPipe(rot0, utils::OV_PIPE0);
}
// pipe1/rot1 (HdmiPipe)
if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_HDMI) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (HdmiPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE1);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe1 (HdmiPipe)", __FUNCTION__);
RotatorBase* rot1 = new NewState::rot1;
ov->closePipe(utils::OV_PIPE1);
newov->openPipe(rot1, utils::OV_PIPE1);
}
// pipe2/rot2 (UIMirrorPipe)
if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_UI_MIRROR) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (UIMirrorPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE2);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe2 (UIMirrorPipe)", __FUNCTION__);
RotatorBase* rot2 = new NewState::rot2;
ov->closePipe(utils::OV_PIPE2);
newov->openPipe(rot2, utils::OV_PIPE2);
}
// All pipes are copied or deleted so no more need for previous ovimpl
delete ov;
ov = 0;
return newov;
}
/*
* Transitions from any state to 1 layer composition bypass
*/
OverlayImplBase* OverlayState::handle_xxx_to_bypass1(OverlayImplBase* ov)
{
OVASSERT(ov, "%s: ov is null", __FUNCTION__);
ALOGE("%s", __FUNCTION__);
// Create new ovimpl based on new state
typedef StateTraits<utils::OV_BYPASS_1_LAYER> NewState;
OverlayImplBase* newov = new NewState::ovimpl;
//===========================================================
// For each pipe:
// - If pipe matches, copy from previous into new ovimpl
// - Otherwise open for new and delete from previous ovimpl
//===========================================================
// pipe0/rot0 (BypassPipe)
if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_BYPASS) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (BypassPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE0);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe0 (BypassPipe)", __FUNCTION__);
RotatorBase* rot0 = new NewState::rot0;
ov->closePipe(utils::OV_PIPE0);
newov->openPipe(rot0, utils::OV_PIPE0);
}
// pipe1/rot1 (NullPipe)
if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_NULL) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (NullPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE1);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe1 (NullPipe)", __FUNCTION__);
RotatorBase* rot1 = new NewState::rot1;
ov->closePipe(utils::OV_PIPE1);
newov->openPipe(rot1, utils::OV_PIPE1);
}
// pipe2/rot2 (NullPipe)
if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_NULL) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (NullPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE2);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe2 (NullPipe)", __FUNCTION__);
RotatorBase* rot2 = new NewState::rot2;
ov->closePipe(utils::OV_PIPE2);
newov->openPipe(rot2, utils::OV_PIPE2);
}
// All pipes are copied or deleted so no more need for previous ovimpl
delete ov;
ov = 0;
return newov;
}
/*
* Transitions from any state to 2 layers composition bypass
*/
OverlayImplBase* OverlayState::handle_xxx_to_bypass2(OverlayImplBase* ov)
{
OVASSERT(ov, "%s: ov is null", __FUNCTION__);
ALOGE("%s", __FUNCTION__);
// Create new ovimpl based on new state
typedef StateTraits<utils::OV_BYPASS_2_LAYER> NewState;
OverlayImplBase* newov = new NewState::ovimpl;
//===========================================================
// For each pipe:
// - If pipe matches, copy from previous into new ovimpl
// - Otherwise open for new and delete from previous ovimpl
//===========================================================
// pipe0/rot0 (BypassPipe)
if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_BYPASS) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (BypassPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE0);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe0 (BypassPipe)", __FUNCTION__);
RotatorBase* rot0 = new NewState::rot0;
ov->closePipe(utils::OV_PIPE0);
newov->openPipe(rot0, utils::OV_PIPE0);
}
// pipe1/rot1 (BypassPipe)
if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_BYPASS) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (BypassPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE1);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe1 (BypassPipe)", __FUNCTION__);
RotatorBase* rot1 = new NewState::rot1;
ov->closePipe(utils::OV_PIPE1);
newov->openPipe(rot1, utils::OV_PIPE1);
}
// pipe2/rot2 (NullPipe)
if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_NULL) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (NullPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE2);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe2 (NullPipe)", __FUNCTION__);
RotatorBase* rot2 = new NewState::rot2;
ov->closePipe(utils::OV_PIPE2);
newov->openPipe(rot2, utils::OV_PIPE2);
}
// All pipes are copied or deleted so no more need for previous ovimpl
delete ov;
ov = 0;
return newov;
}
/*
* Transitions from any state to 3 layers composition bypass
*/
OverlayImplBase* OverlayState::handle_xxx_to_bypass3(OverlayImplBase* ov)
{
OVASSERT(ov, "%s: ov is null", __FUNCTION__);
ALOGE("%s", __FUNCTION__);
// Create new ovimpl based on new state
typedef StateTraits<utils::OV_BYPASS_3_LAYER> NewState;
OverlayImplBase* newov = new NewState::ovimpl;
//===========================================================
// For each pipe:
// - If pipe matches, copy from previous into new ovimpl
// - Otherwise open for new and delete from previous ovimpl
//===========================================================
// pipe0/rot0 (BypassPipe)
if (ov->getOvPipeType(utils::OV_PIPE0) == utils::OV_PIPE_TYPE_BYPASS) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe0 (BypassPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE0);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe0 (BypassPipe)", __FUNCTION__);
RotatorBase* rot0 = new NewState::rot0;
ov->closePipe(utils::OV_PIPE0);
newov->openPipe(rot0, utils::OV_PIPE0);
}
// pipe1/rot1 (BypassPipe)
if (ov->getOvPipeType(utils::OV_PIPE1) == utils::OV_PIPE_TYPE_BYPASS) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe1 (BypassPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE1);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe1 (BypassPipe)", __FUNCTION__);
RotatorBase* rot1 = new NewState::rot1;
ov->closePipe(utils::OV_PIPE1);
newov->openPipe(rot1, utils::OV_PIPE1);
}
// pipe2/rot2 (BypassPipe)
if (ov->getOvPipeType(utils::OV_PIPE2) == utils::OV_PIPE_TYPE_BYPASS) {
ALOGE_IF(DEBUG_OVERLAY, "%s: Copy pipe2 (BypassPipe)", __FUNCTION__);
newov->copyOvPipe(ov, utils::OV_PIPE2);
} else {
ALOGE_IF(DEBUG_OVERLAY, "%s: Open pipe2 (BypassPipe)", __FUNCTION__);
RotatorBase* rot2 = new NewState::rot2;
ov->closePipe(utils::OV_PIPE2);
newov->openPipe(rot2, utils::OV_PIPE2);
}
// All pipes are copied or deleted so no more need for previous ovimpl
delete ov;
ov = 0;
return newov;
}
} // overlay

337
liboverlay/overlayUtils.cpp Normal file
View File

@ -0,0 +1,337 @@
/*
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <utils/Log.h>
#include <linux/msm_mdp.h>
#include <cutils/properties.h>
#include "gralloc_priv.h"
#include "fb_priv.h"
#include "overlayUtils.h"
#include "mdpWrapper.h"
// just a helper static thingy
namespace {
struct IOFile {
IOFile(const char* s, const char* mode) : fp(0) {
fp = ::fopen(s, mode);
if(!fp) {
ALOGE("Failed open %s", s);
}
}
template <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::devTemplate = "/dev/graphics/fb%u";
const char* const Res::rotPath = "/dev/msm_rotator";
const char* const Res::format3DFile =
"/sys/class/graphics/fb1/format_3d";
const char* const Res::edid3dInfoFile =
"/sys/class/graphics/fb1/3d_present";
const char* const Res::barrierFile =
"/sys/devices/platform/mipi_novatek.0/enable_3d_barrier";
//--------------------------------------------------------
namespace utils {
//--------------------------------------------------------
FrameBufferInfo::FrameBufferInfo() {
mFBWidth = 0;
mFBHeight = 0;
mBorderFillSupported = false;
OvFD mFd;
// Use open defined in overlayFD file to open fd for fb0
if(!overlay::open(mFd, 0, Res::devTemplate)) {
ALOGE("FrameBufferInfo: failed to open fd");
return;
}
if (!mFd.valid()) {
ALOGE("FrameBufferInfo: FD not valid");
return;
}
fb_var_screeninfo vinfo;
if (!mdp_wrapper::getVScreenInfo(mFd.getFD(), vinfo)) {
ALOGE("FrameBufferInfo: failed getVScreenInfo on fb0");
mFd.close();
return;
}
mdp_overlay ov;
memset(&ov, 0, sizeof(ov));
ov.id = 1;
if (!mdp_wrapper::getOverlay(mFd.getFD(), ov)) {
ALOGE("FrameBufferInfo: failed getOverlay on fb0");
mFd.close();
return;
}
mFd.close();
mFBWidth = vinfo.xres;
mFBHeight = vinfo.yres;
mBorderFillSupported = (ov.flags & MDP_BORDERFILL_SUPPORTED) ?
true : false;
}
FrameBufferInfo* FrameBufferInfo::getInstance() {
if (!sFBInfoInstance) {
sFBInfoInstance = new FrameBufferInfo;
}
return sFBInfoInstance;
}
int FrameBufferInfo::getWidth() const {
return mFBWidth;
}
int FrameBufferInfo::getHeight() const {
return mFBHeight;
}
bool FrameBufferInfo::supportTrueMirroring() const {
return mBorderFillSupported;
}
//--------------------------------------------------------
uint32_t getSize(const Whf& whf) {
int aligned_height=0, pitch=0;
uint32_t size = whf.w * whf.h;
switch (whf.format) {
case MDP_RGBA_8888:
case MDP_BGRA_8888:
case MDP_RGBX_8888:
size *= 4;
break;
case MDP_RGB_565:
case MDP_Y_CBCR_H2V1:
size *= 2;
break;
case MDP_Y_CBCR_H2V2:
case MDP_Y_CRCB_H2V2:
size = (size * 3) / 2;
break;
case MDP_Y_CRCB_H2V2_TILE:
case MDP_Y_CBCR_H2V2_TILE:
aligned_height = align(whf.h , 32);
pitch = align(whf.w, 128);
size = pitch * aligned_height;
size = align(size, 8192);
aligned_height = align(whf.h >> 1, 32);
size += pitch * aligned_height;
size = align(size, 8192);
break;
default:
ALOGE("getSize unknown format %d", whf.format);
return 0;
}
return size;
}
int getMdpFormat(int format) {
switch (format) {
case HAL_PIXEL_FORMAT_RGBA_8888 :
return MDP_RGBA_8888;
case HAL_PIXEL_FORMAT_BGRA_8888:
return MDP_BGRA_8888;
case HAL_PIXEL_FORMAT_RGB_565:
return MDP_RGB_565;
case HAL_PIXEL_FORMAT_RGBX_8888:
return MDP_RGBX_8888;
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
return MDP_Y_CBCR_H2V1;
case HAL_PIXEL_FORMAT_YCrCb_422_SP:
return MDP_Y_CRCB_H2V1;
case HAL_PIXEL_FORMAT_YCbCr_420_SP:
return MDP_Y_CBCR_H2V2;
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
return MDP_Y_CRCB_H2V2;
case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
return MDP_Y_CBCR_H2V2_TILE;
case HAL_PIXEL_FORMAT_YV12:
return MDP_Y_CR_CB_H2V2;
default:
ALOGE("Error getMdpFormat format=%d", format);
return -1;
}
// not reached
return -1;
}
bool isHDMIConnected () {
char value[PROPERTY_VALUE_MAX] = {0};
property_get("hw.hdmiON", value, "0");
int isHDMI = atoi(value);
return isHDMI ? true : false;
}
bool is3DTV() {
char is3DTV = '0';
IOFile fp(Res::edid3dInfoFile, "r");
(void)fp.read(is3DTV, 1);
ALOGI("3DTV EDID flag: %d", is3DTV);
return (is3DTV == '0') ? false : true;
}
bool isPanel3D() {
OvFD fd;
if(!overlay::open(fd, 0 /*fb*/, Res::devTemplate)){
ALOGE("isPanel3D Can't open framebuffer 0");
return false;
}
fb_fix_screeninfo finfo;
if(!mdp_wrapper::getFScreenInfo(fd.getFD(), finfo)) {
ALOGE("isPanel3D read fb0 failed");
}
fd.close();
return (FB_TYPE_3D_PANEL == finfo.type) ? true : false;
}
bool usePanel3D() {
if(!isPanel3D())
return false;
char value[PROPERTY_VALUE_MAX];
property_get("persist.user.panel3D", value, "0");
int usePanel3D = atoi(value);
return usePanel3D ? true : false;
}
bool send3DInfoPacket (uint32_t format3D) {
IOFile fp(Res::format3DFile, "wb");
(void)fp.write("%d", format3D);
if(!fp.valid()) {
ALOGE("send3DInfoPacket: no sysfs entry for setting 3d mode");
return false;
}
return true;
}
bool enableBarrier (uint32_t orientation) {
IOFile fp(Res::barrierFile, "wb");
(void)fp.write("%d", orientation);
if(!fp.valid()) {
ALOGE("enableBarrier no sysfs entry for "
"enabling barriers on 3D panel");
return false;
}
return true;
}
uint32_t getS3DFormat(uint32_t fmt) {
// The S3D is part of the HAL_PIXEL_FORMAT_YV12 value. Add
// an explicit check for the format
if (fmt == HAL_PIXEL_FORMAT_YV12) {
return 0;
}
uint32_t fmt3D = format3D(fmt);
uint32_t fIn3D = format3DInput(fmt3D); // MSB 2 bytes - inp
uint32_t fOut3D = format3DOutput(fmt3D); // LSB 2 bytes - out
fmt3D = fIn3D | fOut3D;
if (!fIn3D) {
fmt3D |= fOut3D << SHIFT_TOT_3D; //Set the input format
}
if (!fOut3D) {
switch (fIn3D) {
case HAL_3D_IN_SIDE_BY_SIDE_L_R:
case HAL_3D_IN_SIDE_BY_SIDE_R_L:
// For all side by side formats, set the output
// format as Side-by-Side i.e 0x1
fmt3D |= HAL_3D_IN_SIDE_BY_SIDE_L_R >> SHIFT_TOT_3D;
break;
default:
fmt3D |= fIn3D >> SHIFT_TOT_3D; //Set the output format
}
}
return fmt3D;
}
void normalizeCrop(uint32_t& xy, uint32_t& wh) {
if (xy & 0x0001) {
// x or y is odd, increment it's value
xy += 1;
// Since we've incremented x(y), we need to decrement
// w(h) accordingly
if (wh & 0x0001) {
// w or h is odd, decrement it by 1, to make it even
even_out(wh);
} else {
// w(h) is already even, hence we decrement by 2
wh -=2;
}
} else {
even_out(wh);
}
}
void scale(mdp_overlay& ov)
{
/* Scaling of upto a max of 8 times supported */
overlay::utils::Dim dst(overlay::utils::getDstRectDim(ov));
overlay::utils::Dim src(overlay::utils::getSrcRectDim(ov));
if(dst.w >(src.w * overlay::utils::HW_OV_MAGNIFICATION_LIMIT)) {
dst.w = overlay::utils::HW_OV_MAGNIFICATION_LIMIT * src.w;
}
if(dst.h >(src.h * overlay::utils::HW_OV_MAGNIFICATION_LIMIT)) {
dst.h = overlay::utils::HW_OV_MAGNIFICATION_LIMIT * src.h;
}
setDstRectDim(dst, ov);
}
} // utils
} // overlay

1112
liboverlay/overlayUtils.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,617 @@
/*
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OVERLAY_M3D_EXT_PIPE_H
#define OVERLAY_M3D_EXT_PIPE_H
#include "overlayGenPipe.h"
#include "overlayUtils.h"
namespace overlay {
///////////// M3DExt Pipe ////////////////////////////
/**
* A specific impl of GenericPipe for 3D.
* Whenever needed to have a pass through - we do it.
* If there is a special need for special/diff behavior
* do it here
* PANEL is always EXTERNAL for this pipe.
* CHAN = 0,1 it's either Channel 1 or channel 2 needed for
* 3D crop and position */
template <int CHAN>
class M3DExtPipe : utils::NoCopy {
public:
/* Please look at overlayGenPipe.h for info */
explicit M3DExtPipe();
~M3DExtPipe();
bool open(RotatorBase* rot);
bool close();
bool commit();
void setId(int id);
void setMemoryId(int id);
bool queueBuffer(uint32_t offset);
bool dequeueBuffer(void*& buf);
bool waitForVsync();
bool setCrop(const utils::Dim& d);
bool start(const utils::PipeArgs& args);
bool setPosition(const utils::Dim& dim);
bool setParameter(const utils::Params& param);
bool setSource(const utils::PipeArgs& args);
const utils::PipeArgs& getArgs() const;
utils::eOverlayPipeType getOvPipeType() const;
void dump() const;
private:
overlay::GenericPipe<utils::EXTERNAL> mM3d;
// Cache the M3D format
uint32_t mM3Dfmt;
};
///////////// M3DPrimary Pipe ////////////////////////////
/**
* A specific impl of GenericPipe for 3D.
* Whenever needed to have a pass through - we do it.
* If there is a special need for special/diff behavior
* do it here
* PANEL is always PRIMARY for this pipe.
* CHAN = 0,1 it's either Channel 1 or channel 2 needed for
* 3D crop and position */
template <int CHAN>
class M3DPrimaryPipe : utils::NoCopy {
public:
/* Please look at overlayGenPipe.h for info */
explicit M3DPrimaryPipe();
~M3DPrimaryPipe();
bool open(RotatorBase* rot);
bool close();
bool commit();
void setId(int id);
void setMemoryId(int id);
bool queueBuffer(uint32_t offset);
bool dequeueBuffer(void*& buf);
bool waitForVsync();
bool setCrop(const utils::Dim& d);
bool start(const utils::PipeArgs& args);
bool setPosition(const utils::Dim& dim);
bool setParameter(const utils::Params& param);
bool setSource(const utils::PipeArgs& args);
const utils::PipeArgs& getArgs() const;
utils::eOverlayPipeType getOvPipeType() const;
void dump() const;
private:
overlay::GenericPipe<utils::PRIMARY> mM3d;
// Cache the M3D format
uint32_t mM3Dfmt;
};
///////////// S3DExt Pipe ////////////////////////////////
/**
* A specific impl of GenericPipe for 3D.
* Whenever needed to have a pass through - we do it.
* If there is a special need for special/diff behavior
* do it here.
* PANEL is always EXTERNAL for this pipe.
* CHAN = 0,1 it's either Channel 1 or channel 2 needed for
* 3D crop and position */
template <int CHAN>
class S3DExtPipe : utils::NoCopy {
public:
/* Please look at overlayGenPipe.h for info */
explicit S3DExtPipe();
~S3DExtPipe();
bool open(RotatorBase* rot);
bool close();
bool commit();
void setId(int id);
void setMemoryId(int id);
bool queueBuffer(uint32_t offset);
bool dequeueBuffer(void*& buf);
bool waitForVsync();
bool setCrop(const utils::Dim& d);
bool start(const utils::PipeArgs& args);
bool setPosition(const utils::Dim& dim);
bool setParameter(const utils::Params& param);
bool setSource(const utils::PipeArgs& args);
const utils::PipeArgs& getArgs() const;
utils::eOverlayPipeType getOvPipeType() const;
void dump() const;
private:
overlay::GenericPipe<utils::EXTERNAL> mS3d;
// Cache the 3D format
uint32_t mS3Dfmt;
};
///////////// S3DPrimary Pipe ////////////////////////////
/**
* A specific impl of GenericPipe for 3D.
* Whenever needed to have a pass through - we do it.
* If there is a special need for special/diff behavior
* do it here
* PANEL is always PRIMARY for this pipe.
* CHAN = 0,1 it's either Channel 1 or channel 2 needed for
* 3D crop and position */
template <int CHAN>
class S3DPrimaryPipe : utils::NoCopy {
public:
/* Please look at overlayGenPipe.h for info */
explicit S3DPrimaryPipe();
~S3DPrimaryPipe();
bool open(RotatorBase* rot);
bool close();
bool commit();
void setId(int id);
void setMemoryId(int id);
bool queueBuffer(uint32_t offset);
bool dequeueBuffer(void*& buf);
bool waitForVsync();
bool setCrop(const utils::Dim& d);
bool start(const utils::PipeArgs& args);
bool setPosition(const utils::Dim& dim);
bool setParameter(const utils::Params& param);
bool setSource(const utils::PipeArgs& args);
const utils::PipeArgs& getArgs() const;
utils::eOverlayPipeType getOvPipeType() const;
void dump() const;
private:
/* needed for 3D related IOCTL */
MdpCtrl3D mCtrl3D;
overlay::GenericPipe<utils::PRIMARY> mS3d;
// Cache the 3D format
uint32_t mS3Dfmt;
};
//------------------------Inlines and Templates--------------------------
///////////// M3DExt Pipe ////////////////////////////
template <int CHAN>
inline M3DExtPipe<CHAN>::M3DExtPipe() : mM3Dfmt(0) {}
template <int CHAN>
inline M3DExtPipe<CHAN>::~M3DExtPipe() { close(); }
template <int CHAN>
inline bool M3DExtPipe<CHAN>::open(RotatorBase* rot) {
ALOGE_IF(DEBUG_OVERLAY, "M3DExtPipe open");
if(!mM3d.open(rot)) {
ALOGE("3Dpipe failed to open");
return false;
}
return true;
}
template <int CHAN>
inline bool M3DExtPipe<CHAN>::close() {
return mM3d.close();
}
template <int CHAN>
inline bool M3DExtPipe<CHAN>::commit() { return mM3d.commit(); }
template <int CHAN>
inline void M3DExtPipe<CHAN>::setId(int id) { mM3d.setId(id); }
template <int CHAN>
inline void M3DExtPipe<CHAN>::setMemoryId(int id) { mM3d.setMemoryId(id); }
template <int CHAN>
inline bool M3DExtPipe<CHAN>::queueBuffer(uint32_t offset) {
return mM3d.queueBuffer(offset); }
template <int CHAN>
inline bool M3DExtPipe<CHAN>::dequeueBuffer(void*& buf) {
return mM3d.dequeueBuffer(buf); }
template <int CHAN>
inline bool M3DExtPipe<CHAN>::waitForVsync() {
return mM3d.waitForVsync(); }
template <int CHAN>
inline bool M3DExtPipe<CHAN>::setCrop(const utils::Dim& d) {
utils::Dim _dim;
if(!utils::getCropS3D<CHAN>(d, _dim, mM3Dfmt)){
ALOGE("M3DExtPipe setCrop failed to getCropS3D");
_dim = d;
}
return mM3d.setCrop(_dim);
}
template <int CHAN>
inline bool M3DExtPipe<CHAN>::start(const utils::PipeArgs& args) {
if(!mM3d.start(args)) {
ALOGE("M3DExtPipe start failed");
return false;
}
return true;
}
template <int CHAN>
inline bool M3DExtPipe<CHAN>::setPosition(const utils::Dim& d) {
utils::Dim _dim;
// original setPositionHandleState has getPositionS3D(...,true)
// which means format is HAL_3D_OUT_SBS_MASK
// HAL_3D_OUT_SBS_MASK is 0x1000 >> 12 == 0x1 as the orig
// code suggets
utils::Whf _whf(mM3d.getScreenInfo().mFBWidth,
mM3d.getScreenInfo().mFBHeight,
mM3Dfmt);
if(!utils::getPositionS3D<CHAN>(_whf, _dim)) {
ALOGE("S3DPrimaryPipe setPosition err in getPositionS3D");
_dim = d;
}
return mM3d.setPosition(_dim);
}
template <int CHAN>
inline bool M3DExtPipe<CHAN>::setParameter(const utils::Params& param) {
return mM3d.setParameter(param);
}
template <int CHAN>
inline bool M3DExtPipe<CHAN>::setSource(const utils::PipeArgs& args)
{
// extract 3D fmt
mM3Dfmt = utils::format3DInput(utils::getS3DFormat(args.whf.format)) |
utils::HAL_3D_OUT_MONOS_MASK;
if(mM3d.isClosed()){
if(!this->start(args)) {
ALOGE("M3DExtPipe setSource failed to start");
return false;
}
}
return mM3d.setSource(args);
}
template <int CHAN>
inline const utils::PipeArgs& M3DExtPipe<CHAN>::getArgs() const {
return mM3d.getArgs();
}
template <int CHAN>
inline utils::eOverlayPipeType M3DExtPipe<CHAN>::getOvPipeType() const {
return utils::OV_PIPE_TYPE_M3D_EXTERNAL;
}
template <int CHAN>
inline void M3DExtPipe<CHAN>::dump() const {
ALOGE("M3DExtPipe Pipe fmt=%d", mM3Dfmt);
mM3d.dump();
}
///////////// M3DPrimary Pipe ////////////////////////////
template <int CHAN>
inline M3DPrimaryPipe<CHAN>::M3DPrimaryPipe() : mM3Dfmt(0) {}
template <int CHAN>
inline M3DPrimaryPipe<CHAN>::~M3DPrimaryPipe() { close(); }
template <int CHAN>
inline bool M3DPrimaryPipe<CHAN>::open(RotatorBase* rot) {
ALOGE_IF(DEBUG_OVERLAY, "M3DPrimaryPipe open");
if(!mM3d.open(rot)) {
ALOGE("3Dpipe failed to open");
return false;
}
return true;
}
template <int CHAN>
inline bool M3DPrimaryPipe<CHAN>::close() {
return mM3d.close();
}
template <int CHAN>
inline bool M3DPrimaryPipe<CHAN>::commit() { return mM3d.commit(); }
template <int CHAN>
inline void M3DPrimaryPipe<CHAN>::setId(int id) { mM3d.setId(id); }
template <int CHAN>
inline void M3DPrimaryPipe<CHAN>::setMemoryId(int id) { mM3d.setMemoryId(id); }
template <int CHAN>
inline bool M3DPrimaryPipe<CHAN>::queueBuffer(uint32_t offset) {
return mM3d.queueBuffer(offset); }
template <int CHAN>
inline bool M3DPrimaryPipe<CHAN>::dequeueBuffer(void*& buf) {
return mM3d.dequeueBuffer(buf); }
template <int CHAN>
inline bool M3DPrimaryPipe<CHAN>::waitForVsync() {
return mM3d.waitForVsync(); }
template <int CHAN>
inline bool M3DPrimaryPipe<CHAN>::setCrop(const utils::Dim& d) {
utils::Dim _dim;
if(!utils::getCropS3D<CHAN>(d, _dim, mM3Dfmt)){
ALOGE("M3DPrimaryPipe setCrop failed to getCropS3D");
_dim = d;
}
return mM3d.setCrop(_dim);
}
template <int CHAN>
inline bool M3DPrimaryPipe<CHAN>::start(const utils::PipeArgs& args) {
if(!mM3d.start(args)) {
ALOGE("M3DPrimaryPipe start failed");
return false;
}
return true;
}
template <int CHAN>
inline bool M3DPrimaryPipe<CHAN>::setPosition(const utils::Dim& d) {
return mM3d.setPosition(d);
}
template <int CHAN>
inline bool M3DPrimaryPipe<CHAN>::setParameter(const utils::Params& param) {
return mM3d.setParameter(param);
}
template <int CHAN>
inline bool M3DPrimaryPipe<CHAN>::setSource(const utils::PipeArgs& args)
{
// extract 3D fmt
mM3Dfmt = utils::format3DInput(utils::getS3DFormat(args.whf.format)) |
utils::HAL_3D_OUT_MONOS_MASK;
if (mM3d.isClosed()) {
if (!this->start(args)) {
ALOGE("M3DPrimaryPipe setSource failed to start");
return false;
}
}
return mM3d.setSource(args);
}
template <int CHAN>
inline const utils::PipeArgs& M3DPrimaryPipe<CHAN>::getArgs() const {
return mM3d.getArgs();
}
template <int CHAN>
inline utils::eOverlayPipeType M3DPrimaryPipe<CHAN>::getOvPipeType() const {
return utils::OV_PIPE_TYPE_M3D_PRIMARY;
}
template <int CHAN>
inline void M3DPrimaryPipe<CHAN>::dump() const {
ALOGE("M3DPrimaryPipe Pipe fmt=%d", mM3Dfmt);
mM3d.dump();
}
///////////// S3DExt Pipe ////////////////////////////////
template <int CHAN>
inline S3DExtPipe<CHAN>::S3DExtPipe() : mS3Dfmt(0) {}
template <int CHAN>
inline S3DExtPipe<CHAN>::~S3DExtPipe() { close(); }
template <int CHAN>
inline bool S3DExtPipe<CHAN>::open(RotatorBase* rot) {
ALOGE_IF(DEBUG_OVERLAY, "S3DExtPipe open");
if(!mS3d.open(rot)) {
ALOGE("3Dpipe failed to open");
return false;
}
return true;
}
template <int CHAN>
inline bool S3DExtPipe<CHAN>::close() {
if(!utils::send3DInfoPacket(0)) {
ALOGE("S3DExtPipe close failed send3D info packet");
}
return mS3d.close();
}
template <int CHAN>
inline bool S3DExtPipe<CHAN>::commit() { return mS3d.commit(); }
template <int CHAN>
inline void S3DExtPipe<CHAN>::setId(int id) { mS3d.setId(id); }
template <int CHAN>
inline void S3DExtPipe<CHAN>::setMemoryId(int id) { mS3d.setMemoryId(id); }
template <int CHAN>
inline bool S3DExtPipe<CHAN>::queueBuffer(uint32_t offset) {
//this->dump();
return mS3d.queueBuffer(offset); }
template <int CHAN>
inline bool S3DExtPipe<CHAN>::dequeueBuffer(void*& buf) {
return mS3d.dequeueBuffer(buf); }
template <int CHAN>
inline bool S3DExtPipe<CHAN>::waitForVsync() {
return mS3d.waitForVsync(); }
template <int CHAN>
inline bool S3DExtPipe<CHAN>::setCrop(const utils::Dim& d) {
utils::Dim _dim;
if(!utils::getCropS3D<CHAN>(d, _dim, mS3Dfmt)){
ALOGE("S3DExtPipe setCrop failed to getCropS3D");
_dim = d;
}
return mS3d.setCrop(_dim);
}
template <int CHAN>
inline bool S3DExtPipe<CHAN>::start(const utils::PipeArgs& args) {
OVASSERT(mS3Dfmt, "S3DExtPipe mS3Dfmt should not be 0 here");
if(!mS3d.start(args)) {
ALOGE("S3DExtPipe start failed");
return false;
}
uint32_t fmt = mS3Dfmt & utils::OUTPUT_3D_MASK;
if(!utils::send3DInfoPacket(fmt)){
ALOGE("Error S3DExtPipe start error send3DInfoPacket %d", fmt);
return false;
}
return true;
}
template <int CHAN>
inline bool S3DExtPipe<CHAN>::setPosition(const utils::Dim& d)
{
utils::Dim _dim;
utils::Whf _whf(mS3d.getScreenInfo().mFBWidth,
mS3d.getScreenInfo().mFBHeight,
mS3Dfmt);
if(!utils::getPositionS3D<CHAN>(_whf, _dim)) {
ALOGE("S3DExtPipe setPosition err in getPositionS3D");
_dim = d;
}
return mS3d.setPosition(_dim);
}
template <int CHAN>
inline bool S3DExtPipe<CHAN>::setParameter(const utils::Params& param) {
return mS3d.setParameter(param);
}
template <int CHAN>
inline bool S3DExtPipe<CHAN>::setSource(const utils::PipeArgs& args) {
mS3Dfmt = utils::getS3DFormat(args.whf.format);
if(mS3d.isClosed()){
if(!this->start(args)) {
ALOGE("S3DExtPipe setSource failed to start");
return false;
}
}
return mS3d.setSource(args);
}
template <int CHAN>
inline const utils::PipeArgs& S3DExtPipe<CHAN>::getArgs() const {
return mS3d.getArgs();
}
template <int CHAN>
inline utils::eOverlayPipeType S3DExtPipe<CHAN>::getOvPipeType() const {
return utils::OV_PIPE_TYPE_S3D_EXTERNAL;
}
template <int CHAN>
inline void S3DExtPipe<CHAN>::dump() const {
ALOGE("S3DExtPipe Pipe fmt=%d", mS3Dfmt);
mS3d.dump();
}
///////////// S3DPrimary Pipe ////////////////////////////
template <int CHAN>
inline S3DPrimaryPipe<CHAN>::S3DPrimaryPipe() : mS3Dfmt(0) {}
template <int CHAN>
inline S3DPrimaryPipe<CHAN>::~S3DPrimaryPipe() { close(); }
template <int CHAN>
inline bool S3DPrimaryPipe<CHAN>::open(RotatorBase* rot) {
ALOGE_IF(DEBUG_OVERLAY, "S3DPrimaryPipe open");
if(!mS3d.open(rot)) {
ALOGE("3Dpipe failed to open");
return false;
}
// set the ctrl fd
mCtrl3D.setFd(mS3d.getCtrlFd());
return true;
}
template <int CHAN>
inline bool S3DPrimaryPipe<CHAN>::close() {
if(!utils::enableBarrier(0)) {
ALOGE("S3DExtPipe close failed enable barrier");
}
mCtrl3D.close();
return mS3d.close();
}
template <int CHAN>
inline bool S3DPrimaryPipe<CHAN>::commit() { return mS3d.commit(); }
template <int CHAN>
inline void S3DPrimaryPipe<CHAN>::setId(int id) { mS3d.setId(id); }
template <int CHAN>
inline void S3DPrimaryPipe<CHAN>::setMemoryId(int id) { mS3d.setMemoryId(id); }
template <int CHAN>
inline bool S3DPrimaryPipe<CHAN>::queueBuffer(uint32_t offset) {
return mS3d.queueBuffer(offset); }
template <int CHAN>
inline bool S3DPrimaryPipe<CHAN>::dequeueBuffer(void*& buf) {
return mS3d.dequeueBuffer(buf); }
template <int CHAN>
inline bool S3DPrimaryPipe<CHAN>::waitForVsync() {
return mS3d.waitForVsync(); }
template <int CHAN>
inline bool S3DPrimaryPipe<CHAN>::setCrop(const utils::Dim& d) {
utils::Dim _dim;
if(!utils::getCropS3D<CHAN>(d, _dim, mS3Dfmt)){
ALOGE("S3DPrimaryPipe setCrop failed to getCropS3D");
_dim = d;
}
return mS3d.setCrop(_dim);
}
template <int CHAN>
inline bool S3DPrimaryPipe<CHAN>::start(const utils::PipeArgs& args) {
if(!mS3d.start(args)) {
ALOGE("S3DPrimaryPipe start failed");
return false;
}
return true;
}
template <int CHAN>
inline bool S3DPrimaryPipe<CHAN>::setPosition(const utils::Dim& d)
{
utils::Whf fbwhf(mS3d.getScreenInfo().mFBWidth,
mS3d.getScreenInfo().mFBHeight,
0 /* fmt dont care*/);
mCtrl3D.setWh(fbwhf);
if(!mCtrl3D.useVirtualFB()) {
ALOGE("Failed to use VFB on %d (non fatal)", utils::FB0);
return false;
}
utils::Dim _dim;
// original setPositionHandleState has getPositionS3D(...,true)
// which means format is HAL_3D_OUT_SBS_MASK
// HAL_3D_OUT_SBS_MASK is 0x1000 >> 12 == 0x1 as the orig
// code suggets
utils::Whf _whf(d.w, d.h, utils::HAL_3D_OUT_SBS_MASK);
if(!utils::getPositionS3D<CHAN>(_whf, _dim)) {
ALOGE("S3DPrimaryPipe setPosition err in getPositionS3D");
_dim = d;
}
return mS3d.setPosition(_dim);
}
/* for S3DPrimaryPipe, we need to have barriers once
* So the easiest way to achieve it, is to make sure FB0 is having it before
* setParam is running */
template <>
inline bool S3DPrimaryPipe<utils::OV_PIPE0>::setParameter(
const utils::Params& param) {
if(utils::OVERLAY_TRANSFORM == param.param){
uint32_t barrier=0;
switch(param.value) {
case HAL_TRANSFORM_ROT_90:
case HAL_TRANSFORM_ROT_270:
barrier = utils::BARRIER_LAND;
break;
default:
barrier = utils::BARRIER_PORT;
break;
}
if(!utils::enableBarrier(barrier)) {
ALOGE("S3DPrimaryPipe setParameter failed to enable barrier");
}
}
return mS3d.setParameter(param);
}
template <int CHAN>
inline bool S3DPrimaryPipe<CHAN>::setParameter(const utils::Params& param) {
return mS3d.setParameter(param);
}
template <int CHAN>
inline bool S3DPrimaryPipe<CHAN>::setSource(const utils::PipeArgs& args)
{
mS3Dfmt = utils::getS3DFormat(args.whf.format);
if(mS3d.isClosed()){
if(!this->start(args)) {
ALOGE("S3DPrimaryPipe setSource failed to start");
return false;
}
}
return mS3d.setSource(args);
}
template <int CHAN>
inline const utils::PipeArgs& S3DPrimaryPipe<CHAN>::getArgs() const {
return mS3d.getArgs();
}
template <int CHAN>
inline utils::eOverlayPipeType S3DPrimaryPipe<CHAN>::getOvPipeType() const {
return utils::OV_PIPE_TYPE_S3D_PRIMARY;
}
template <int CHAN>
inline void S3DPrimaryPipe<CHAN>::dump() const {
ALOGE("S3DPrimaryPipe Pipe fmt=%d", mS3Dfmt);
mS3d.dump();
}
} // overlay
#endif // OVERLAY_M3D_EXT_PIPE_H

View File

@ -0,0 +1,213 @@
/*
* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OVERLAY_BYPASS_PIPE_H
#define OVERLAY_BYPASS_PIPE_H
#include "overlayGenPipe.h"
#include "overlayUtils.h"
#include "overlayCtrlData.h"
#include "overlayMdp.h"
#include "overlayRotator.h"
namespace overlay {
/* A specific impl of GenericPipe
* Whenever needed to have a pass through - we do it.
* If there is a special need for a different behavior - do it here
* PipeType = 0 (RGB), 1 (VG) */
template <utils::eMdpPipeType PipeType, utils::eIsFg IsFg, utils::eWait Wait,
utils::eZorder Zorder>
class BypassPipe : utils::NoCopy {
public:
/* Please look at overlayGenPipe.h for info */
explicit BypassPipe();
~BypassPipe();
bool open(RotatorBase* rot);
bool close();
bool commit();
void setId(int id);
void setMemoryId(int id);
bool queueBuffer(uint32_t offset);
bool dequeueBuffer(void*& buf);
bool waitForVsync();
bool setCrop(const utils::Dim& dim);
bool start(const utils::PipeArgs& args);
bool setPosition(const utils::Dim& dim);
bool setParameter(const utils::Params& param);
bool setSource(const utils::PipeArgs& args);
const utils::PipeArgs& getArgs() const;
utils::eOverlayPipeType getOvPipeType() const;
void dump() const;
private:
overlay::GenericPipe<ovutils::PRIMARY> mBypass;
};
//------------------Inlines and Templates---------------------
template <utils::eMdpPipeType PipeType, utils::eIsFg IsFg, utils::eWait Wait,
utils::eZorder Zorder>
inline BypassPipe<PipeType, IsFg, Wait, Zorder>::BypassPipe() {}
template <utils::eMdpPipeType PipeType, utils::eIsFg IsFg, utils::eWait Wait,
utils::eZorder Zorder>
inline BypassPipe<PipeType, IsFg, Wait, Zorder>::~BypassPipe() {
close();
}
template <utils::eMdpPipeType PipeType, utils::eIsFg IsFg, utils::eWait Wait,
utils::eZorder Zorder>
inline bool BypassPipe<PipeType, IsFg, Wait, Zorder>::open(RotatorBase* rot) {
ALOGE_IF(DEBUG_OVERLAY, "BypassPipe open");
return mBypass.open(rot);
}
template <utils::eMdpPipeType PipeType, utils::eIsFg IsFg, utils::eWait Wait,
utils::eZorder Zorder>
inline bool BypassPipe<PipeType, IsFg, Wait, Zorder>::close() {
return mBypass.close();
}
template <utils::eMdpPipeType PipeType, utils::eIsFg IsFg, utils::eWait Wait,
utils::eZorder Zorder>
inline bool BypassPipe<PipeType, IsFg, Wait, Zorder>::commit() {
return mBypass.commit();
}
template <utils::eMdpPipeType PipeType, utils::eIsFg IsFg, utils::eWait Wait,
utils::eZorder Zorder>
inline void BypassPipe<PipeType, IsFg, Wait, Zorder>::setId(int id) {
mBypass.setId(id);
}
template <utils::eMdpPipeType PipeType, utils::eIsFg IsFg, utils::eWait Wait,
utils::eZorder Zorder>
inline void BypassPipe<PipeType, IsFg, Wait, Zorder>::setMemoryId(int id) {
mBypass.setMemoryId(id);
}
template <utils::eMdpPipeType PipeType, utils::eIsFg IsFg, utils::eWait Wait,
utils::eZorder Zorder>
inline bool BypassPipe<PipeType, IsFg, Wait, Zorder>::queueBuffer(
uint32_t offset) {
return mBypass.queueBuffer(offset);
}
template <utils::eMdpPipeType PipeType, utils::eIsFg IsFg, utils::eWait Wait,
utils::eZorder Zorder>
inline bool BypassPipe<PipeType, IsFg, Wait, Zorder>::dequeueBuffer(
void*& buf) {
return mBypass.dequeueBuffer(buf);
}
template <utils::eMdpPipeType PipeType, utils::eIsFg IsFg, utils::eWait Wait,
utils::eZorder Zorder>
inline bool BypassPipe<PipeType, IsFg, Wait, Zorder>::waitForVsync() {
return mBypass.waitForVsync();
}
template <utils::eMdpPipeType PipeType, utils::eIsFg IsFg, utils::eWait Wait,
utils::eZorder Zorder>
inline bool BypassPipe<PipeType, IsFg, Wait, Zorder>::setCrop(
const utils::Dim& dim) {
return mBypass.setCrop(dim);
}
template <utils::eMdpPipeType PipeType, utils::eIsFg IsFg, utils::eWait Wait,
utils::eZorder Zorder>
inline bool BypassPipe<PipeType, IsFg, Wait, Zorder>::start(
const utils::PipeArgs& args) {
return mBypass.start(args);
}
template <utils::eMdpPipeType PipeType, utils::eIsFg IsFg, utils::eWait Wait,
utils::eZorder Zorder>
inline bool BypassPipe<PipeType, IsFg, Wait, Zorder>::setPosition(
const utils::Dim& dim) {
return mBypass.setPosition(dim);
}
template <utils::eMdpPipeType PipeType, utils::eIsFg IsFg, utils::eWait Wait,
utils::eZorder Zorder>
inline bool BypassPipe<PipeType, IsFg, Wait, Zorder>::setParameter(
const utils::Params& param) {
return mBypass.setParameter(param);
}
template <utils::eMdpPipeType PipeType, utils::eIsFg IsFg, utils::eWait Wait,
utils::eZorder Zorder>
inline bool BypassPipe<PipeType, IsFg, Wait, Zorder>::setSource(
const utils::PipeArgs& args) {
utils::PipeArgs arg(args);
// Stride aligned to 32
arg.whf.w = utils::align(arg.whf.w, 32);
arg.whf.h = utils::align(arg.whf.h, 32);
// VG or RG pipe
if (PipeType == utils::OV_MDP_PIPE_VG) {
setMdpFlags(arg.mdpFlags, utils::OV_MDP_PIPE_SHARE);
}
// Set is_fg flag
arg.isFg = IsFg;
// Wait or no wait
arg.wait = Wait;
// Z-order
arg.zorder = Zorder;
return mBypass.setSource(arg);
}
template <utils::eMdpPipeType PipeType, utils::eIsFg IsFg, utils::eWait Wait,
utils::eZorder Zorder>
inline const utils::PipeArgs& BypassPipe<PipeType, IsFg, Wait,
Zorder>::getArgs() const {
return mBypass.getArgs();
}
template <utils::eMdpPipeType PipeType, utils::eIsFg IsFg, utils::eWait Wait,
utils::eZorder Zorder>
inline utils::eOverlayPipeType BypassPipe<PipeType, IsFg, Wait,
Zorder>::getOvPipeType() const {
return utils::OV_PIPE_TYPE_BYPASS;
}
template <utils::eMdpPipeType PipeType, utils::eIsFg IsFg, utils::eWait Wait,
utils::eZorder Zorder>
inline void BypassPipe<PipeType, IsFg, Wait, Zorder>::dump() const {
ALOGE("Bypass VG Pipe");
mBypass.dump();
}
} // overlay
#endif // OVERLAY_BYPASS_PIPE_H

View File

@ -0,0 +1,403 @@
/*
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OVERLAY_GENERIC_PIPE_H
#define OVERLAY_GENERIC_PIPE_H
#include "overlayUtils.h"
#include "overlayRotator.h"
#include "overlayCtrlData.h"
// FIXME make int to be uint32 whenever possible
namespace overlay {
template <int PANEL>
class GenericPipe : utils::NoCopy {
public:
/* ctor init */
explicit GenericPipe();
/* dtor close */
~GenericPipe();
/* CTRL/DATA/ROT open */
bool open(RotatorBase* rot);
/* CTRL/DATA close. Not owning rotator, will not close it */
bool close();
/* commit changes to the overlay "set"*/
bool commit();
/* "Data" related interface */
/* set ID directly to data channel */
void setId(int id);
/* Set FD / memid */
void setMemoryId(int id);
/* queue buffer to the overlay */
bool queueBuffer(uint32_t offset);
/* dequeue buffer to the overlay NOTSUPPORTED */
bool dequeueBuffer(void*& buf);
/* wait for vsync to be done */
bool waitForVsync();
/* set crop data FIXME setROI (Region Of Intrest) */
bool setCrop(const utils::Dim& d);
/* "Ctrl" related interface */
/*
* Start a session, opens the rotator
* FIXME, we might want to open the rotator separately
*/
bool start(const utils::PipeArgs& args);
/* set mdp posision using dim */
bool setPosition(const utils::Dim& dim);
/* set param using Params (param,value pair) */
bool setParameter(const utils::Params& param);
/* set source using whf, orient and wait flag */
bool setSource(const utils::PipeArgs& args);
/* return cached startup args */
const utils::PipeArgs& getArgs() const;
/* retrieve screen info */
utils::ScreenInfo getScreenInfo() const;
/* retrieve cached crop data */
utils::Dim getCrop() const;
/* return aspect ratio from ctrl data */
utils::Dim getAspectRatio(const utils::Whf& whf) const;
/* return aspect ratio from ctrl data for true UI mirroring */
utils::Dim getAspectRatio(const utils::Dim& dim) const;
/* is closed */
bool isClosed() const;
/* is open */
bool isOpen() const;
/* return Ctrl fd. Used for S3D */
int getCtrlFd() const;
/* Get the overlay pipe type */
utils::eOverlayPipeType getOvPipeType() const;
/* dump the state of the object */
void dump() const;
private:
/* set Closed channel */
bool setClosed();
// kick off rotator.
bool startRotator();
/* Ctrl/Data aggregator */
CtrlData mCtrlData;
/* caching startup params. useful when need
* to have the exact copy of that pipe.
* For example when HDMI is connected, and we would
* like to open/start the pipe with the args */
utils::PipeArgs mArgs;
/* rotator mdp base
* Can point to NullRotator or to Rotator*/
RotatorBase* mRot;
/* my flags */
enum { CLOSED = 1<<0 };
uint32_t mFlags;
};
//------------------------Inlines and Templates ----------------------
template <int PANEL>
GenericPipe<PANEL>::GenericPipe() : mRot(0), mFlags(CLOSED) {}
template <int PANEL>
GenericPipe<PANEL>::~GenericPipe() {
close();
}
template <int PANEL>
bool GenericPipe<PANEL>::open(RotatorBase* rot)
{
OVASSERT(rot, "rot is null");
// open ctrl and data
uint32_t fbnum = utils::getFBForPanel(PANEL);
ALOGE_IF(DEBUG_OVERLAY, "GenericPipe open");
if(!mCtrlData.ctrl.open(fbnum, rot)) {
ALOGE("GenericPipe failed to open ctrl");
return false;
}
if(!mCtrlData.data.open(fbnum, rot)) {
ALOGE("GenericPipe failed to open data");
return false;
}
mRot = rot;
// NOTE: we won't have the flags as non CLOSED since we
// consider the pipe opened for business only when we call
// start()
return true;
}
template <int PANEL>
bool GenericPipe<PANEL>::close() {
if(isClosed()) return true;
bool ret = true;
if(!mCtrlData.ctrl.close()) {
ALOGE("GenericPipe failed to close ctrl");
ret = false;
}
if (!mCtrlData.data.close()) {
ALOGE("GenericPipe failed to close data");
ret = false;
}
setClosed();
return ret;
}
template <int PANEL>
inline bool GenericPipe<PANEL>::commit(){
OVASSERT(isOpen(), "State is closed, cannot commit");
return mCtrlData.ctrl.commit();
}
template <int PANEL>
inline void GenericPipe<PANEL>::setMemoryId(int id) {
OVASSERT(isOpen(), "State is closed, cannot setMemoryId");
mCtrlData.data.setMemoryId(id);
}
template <int PANEL>
inline void GenericPipe<PANEL>::setId(int id) {
mCtrlData.data.setId(id); }
template <int PANEL>
inline int GenericPipe<PANEL>::getCtrlFd() const {
return mCtrlData.ctrl.getFd();
}
template <int PANEL>
inline bool GenericPipe<PANEL>::setCrop(
const overlay::utils::Dim& d) {
OVASSERT(isOpen(), "State is closed, cannot setCrop");
return mCtrlData.ctrl.setCrop(d);
}
template <int PANEL>
bool GenericPipe<PANEL>::start(const utils::PipeArgs& args)
{
/* open before your start control rotator */
uint32_t sz = args.whf.size; //utils::getSizeByMdp(args.whf);
OVASSERT(sz, "GenericPipe sz=%d", sz);
if(!mRot->open()) {
ALOGE("GenericPipe start failed to open rot");
return false;
}
if(!mCtrlData.ctrl.start(args)){
ALOGE("GenericPipe failed to start");
return false;
}
int ctrlId = mCtrlData.ctrl.getId();
OVASSERT(-1 != ctrlId, "Ctrl ID should not be -1");
// set ID requeset to assoc ctrl to data
setId(ctrlId);
// set ID request to assoc MDP data to ROT MDP data
mRot->setDataReqId(mCtrlData.data.getId());
// cache the args for future reference.
mArgs = args;
// we got here so we are open+start and good to go
mFlags = 0; // clear flags from CLOSED
// TODO make it more robust when more flags
// are added
return true;
}
template <int PANEL>
inline const utils::PipeArgs& GenericPipe<PANEL>::getArgs() const
{
return mArgs;
}
template <int PANEL>
bool GenericPipe<PANEL>::startRotator() {
// kick off rotator
if(!mRot->start()) {
ALOGE("GenericPipe failed to start rotator");
return false;
}
return true;
}
template <int PANEL>
inline bool GenericPipe<PANEL>::queueBuffer(uint32_t offset) {
OVASSERT(isOpen(), "State is closed, cannot queueBuffer");
return mCtrlData.data.queueBuffer(offset);
}
template <int PANEL>
inline bool GenericPipe<PANEL>::dequeueBuffer(void*&) {
OVASSERT(isOpen(), "State is closed, cannot dequeueBuffer");
// can also set error to NOTSUPPORTED in the future
return false;
}
template <int PANEL>
inline bool GenericPipe<PANEL>::waitForVsync() {
OVASSERT(isOpen(), "State is closed, cannot waitForVsync");
return mCtrlData.data.waitForVsync();
}
template <int PANEL>
inline bool GenericPipe<PANEL>::setPosition(const utils::Dim& dim)
{
OVASSERT(isOpen(), "State is closed, cannot setPosition");
return mCtrlData.ctrl.setPosition(dim);
}
template <int PANEL>
inline bool GenericPipe<PANEL>::setParameter(
const utils::Params& param)
{
OVASSERT(isOpen(), "State is closed, cannot setParameter");
// Currently setParameter would start rotator
if(!mCtrlData.ctrl.setParameter(param)) {
ALOGE("GenericPipe failed to setparam");
return false;
}
// if rot flags are ENABLED it means we would always
// like to have rot. Even with 0 rot. (solves tearing)
if(utils::ROT_FLAG_ENABLED == mArgs.rotFlags) {
mRot->setEnable();
}
return startRotator();
}
template <int PANEL>
inline bool GenericPipe<PANEL>::setSource(
const utils::PipeArgs& args)
{
// cache the recent args.
mArgs = args;
// setSource is the 1st thing that is being called on a pipe.
// If pipe is closed, we should start everything.
// we assume it is being opened with the correct FDs.
if(isClosed()) {
if(!this->start(args)) {
ALOGE("GenericPipe setSource failed to start");
return false;
}
return true;
}
return mCtrlData.ctrl.setSource(args);
}
template <int PANEL>
inline utils::Dim GenericPipe<PANEL>::getAspectRatio(
const utils::Whf& whf) const
{
return mCtrlData.ctrl.getAspectRatio(whf);
}
template <int PANEL>
inline utils::Dim GenericPipe<PANEL>::getAspectRatio(
const utils::Dim& dim) const
{
return mCtrlData.ctrl.getAspectRatio(dim);
}
template <int PANEL>
inline utils::ScreenInfo GenericPipe<PANEL>::getScreenInfo() const
{
return mCtrlData.ctrl.getScreenInfo();
}
template <int PANEL>
inline utils::Dim GenericPipe<PANEL>::getCrop() const
{
return mCtrlData.ctrl.getCrop();
}
template <int PANEL>
inline utils::eOverlayPipeType GenericPipe<PANEL>::getOvPipeType() const {
return utils::OV_PIPE_TYPE_GENERIC;
}
template <int PANEL>
void GenericPipe<PANEL>::dump() const
{
ALOGE("== Dump Generic pipe start ==");
ALOGE("flags=0x%x", mFlags);
OVASSERT(mRot, "GenericPipe should have a valid Rot");
mCtrlData.ctrl.dump();
mCtrlData.data.dump();
mRot->dump();
ALOGE("== Dump Generic pipe end ==");
}
template <int PANEL>
inline bool GenericPipe<PANEL>::isClosed() const {
return utils::getBit(mFlags, CLOSED);
}
template <int PANEL>
inline bool GenericPipe<PANEL>::isOpen() const {
return !isClosed();
}
template <int PANEL>
inline bool GenericPipe<PANEL>::setClosed() {
return utils::setBit(mFlags, CLOSED);
}
} //namespace overlay
#endif // OVERLAY_GENERIC_PIPE_H

View File

@ -0,0 +1,128 @@
/*
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OVERLAY_HDMI_PIPE_H
#define OVERLAY_HDMI_PIPE_H
#include "overlayGenPipe.h"
#include "overlayUtils.h"
#include "overlayCtrlData.h"
#include "overlayMdp.h"
#include "overlayRotator.h"
namespace overlay {
/* A specific impl of GenericPipe
* Whenever needed to have a pass through - we do it.
* If there is a special need for a different behavior - do it here */
class HdmiPipe : utils::NoCopy {
public:
/* Please look at overlayGenPipe.h for info */
explicit HdmiPipe();
~HdmiPipe();
bool open(RotatorBase* rot);
bool close();
bool commit();
void setId(int id);
void setMemoryId(int id);
bool queueBuffer(uint32_t offset);
bool dequeueBuffer(void*& buf);
bool waitForVsync();
bool setCrop(const utils::Dim& dim);
bool start(const utils::PipeArgs& args);
bool setPosition(const utils::Dim& dim);
bool setParameter(const utils::Params& param);
bool setSource(const utils::PipeArgs& args);
const utils::PipeArgs& getArgs() const;
utils::eOverlayPipeType getOvPipeType() const;
void dump() const;
private:
overlay::GenericPipe<ovutils::EXTERNAL> mHdmi;
};
//------------------Inlines -----------------------------
inline HdmiPipe::HdmiPipe() {}
inline HdmiPipe::~HdmiPipe() { close(); }
inline bool HdmiPipe::open(RotatorBase* rot) {
ALOGE_IF(DEBUG_OVERLAY, "HdmiPipe open");
return mHdmi.open(rot);
}
inline bool HdmiPipe::close() { return mHdmi.close(); }
inline bool HdmiPipe::commit() { return mHdmi.commit(); }
inline void HdmiPipe::setId(int id) { mHdmi.setId(id); }
inline void HdmiPipe::setMemoryId(int id) { mHdmi.setMemoryId(id); }
inline bool HdmiPipe::queueBuffer(uint32_t offset) {
return mHdmi.queueBuffer(offset); }
inline bool HdmiPipe::dequeueBuffer(void*& buf) {
return mHdmi.dequeueBuffer(buf); }
inline bool HdmiPipe::waitForVsync() {
return mHdmi.waitForVsync(); }
inline bool HdmiPipe::setCrop(const utils::Dim& dim) {
return mHdmi.setCrop(dim); }
inline bool HdmiPipe::start(const utils::PipeArgs& args) {
return mHdmi.start(args); }
inline bool HdmiPipe::setPosition(const utils::Dim& dim)
{
utils::Dim d;
// Need to change dim to aspect ratio
if (utils::FrameBufferInfo::getInstance()->supportTrueMirroring()) {
// Use dim info to calculate aspect ratio for true UI mirroring
d = mHdmi.getAspectRatio(dim);
} else {
// Use cached crop data to get aspect ratio
utils::Dim crop = mHdmi.getCrop();
utils::Whf whf(crop.w, crop.h, 0);
d = mHdmi.getAspectRatio(whf);
}
ALOGE_IF(DEBUG_OVERLAY, "Calculated aspect ratio for HDMI: x=%d, y=%d, w=%d, h=%d, o=%d",
d.x, d.y, d.w, d.h, d.o);
return mHdmi.setPosition(d);
}
inline bool HdmiPipe::setParameter(const utils::Params& param) {
return mHdmi.setParameter(param); }
inline bool HdmiPipe::setSource(const utils::PipeArgs& args) {
utils::PipeArgs arg(args);
return mHdmi.setSource(arg);
}
inline const utils::PipeArgs& HdmiPipe::getArgs() const {
return mHdmi.getArgs();
}
inline utils::eOverlayPipeType HdmiPipe::getOvPipeType() const {
return utils::OV_PIPE_TYPE_HDMI;
}
inline void HdmiPipe::dump() const {
ALOGE("HDMI Pipe");
mHdmi.dump();
}
} // overlay
#endif // OVERLAY_HDMI_PIPE_H

View File

@ -0,0 +1,192 @@
/*
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OVERLAY_UI_PIPE_H
#define OVERLAY_UI_PIPE_H
#include "overlayGenPipe.h"
#include "overlayUtils.h"
#include "overlayCtrlData.h"
#include "overlayMdp.h"
#include "overlayRotator.h"
namespace overlay {
/* A specific impl of GenericPipe
* Whenever needed to have a pass through - we do it.
* If there is a special need for a different behavior - do it here */
class UIMirrorPipe : utils::NoCopy {
public:
/* Please look at overlayGenPipe.h for info */
explicit UIMirrorPipe();
~UIMirrorPipe();
bool open(RotatorBase* rot);
bool close();
bool commit();
void setId(int id);
void setMemoryId(int id);
bool queueBuffer(uint32_t offset);
bool dequeueBuffer(void*& buf);
bool waitForVsync();
bool setCrop(const utils::Dim& dim);
bool start(const utils::PipeArgs& args);
bool setPosition(const utils::Dim& dim);
bool setParameter(const utils::Params& param);
bool setSource(const utils::PipeArgs& args);
const utils::PipeArgs& getArgs() const;
utils::eOverlayPipeType getOvPipeType() const;
void dump() const;
private:
overlay::GenericPipe<ovutils::EXTERNAL> mUI;
};
//----------------------------Inlines -----------------------------
inline UIMirrorPipe::UIMirrorPipe() {}
inline UIMirrorPipe::~UIMirrorPipe() { close(); }
inline bool UIMirrorPipe::open(RotatorBase* rot) {
ALOGE_IF(DEBUG_OVERLAY, "UIMirrorPipe open");
bool ret = mUI.open(rot);
//If source to rotator is framebuffer, which is the case we UI Mirror pipe,
//we need to inform driver during playback. Since FB does not use ION.
rot->setSrcFB(true);
return ret;
}
inline bool UIMirrorPipe::close() { return mUI.close(); }
inline bool UIMirrorPipe::commit() { return mUI.commit(); }
inline void UIMirrorPipe::setId(int id) { mUI.setId(id); }
inline void UIMirrorPipe::setMemoryId(int id) { mUI.setMemoryId(id); }
inline bool UIMirrorPipe::queueBuffer(uint32_t offset) {
return mUI.queueBuffer(offset); }
inline bool UIMirrorPipe::dequeueBuffer(void*& buf) {
return mUI.dequeueBuffer(buf); }
inline bool UIMirrorPipe::waitForVsync() {
return mUI.waitForVsync(); }
inline bool UIMirrorPipe::setCrop(const utils::Dim& dim) {
return mUI.setCrop(dim); }
inline bool UIMirrorPipe::start(const utils::PipeArgs& args) {
if(!mUI.start(args)) {
ALOGE("%s failed to start", __FUNCTION__);
return false;
}
return true;
}
inline bool UIMirrorPipe::setPosition(const utils::Dim& dim) {
ovutils::Dim pdim;
switch (dim.o) {
case 0:
case HAL_TRANSFORM_ROT_180:
{
ovutils::Whf whf(dim.x, dim.y, 0);
pdim = mUI.getAspectRatio(whf);
break;
}
case HAL_TRANSFORM_ROT_90:
case HAL_TRANSFORM_ROT_270:
{
// Calculate the Aspectratio for the UI in the landscape mode
// Width and height will be swapped as there is rotation
ovutils::Whf whf(dim.y, dim.x, 0);
pdim = mUI.getAspectRatio(whf);
break;
}
default:
ALOGE("%s: Unknown orientation %d", __FUNCTION__, dim.o);
return false;
}
ovutils::even_out(pdim.x);
ovutils::even_out(pdim.y);
ovutils::even_out(pdim.w);
ovutils::even_out(pdim.h);
return mUI.setPosition(pdim);
}
inline bool UIMirrorPipe::setParameter(const utils::Params& param) {
OVASSERT(utils::OVERLAY_TRANSFORM_UI == param.param,
"%p Expecting OVERLAY_TRANSFORM_UI", __FUNCTION__);
int orientation = param.value;
// Figure out orientation to transform to
switch (param.value) {
case 0:
orientation = 0;
break;
case HAL_TRANSFORM_ROT_180:
orientation = HAL_TRANSFORM_ROT_180;
break;
case HAL_TRANSFORM_ROT_90:
orientation = HAL_TRANSFORM_ROT_270;
break;
case HAL_TRANSFORM_ROT_270:
orientation = HAL_TRANSFORM_ROT_90;
break;
default:
ALOGE("%s: Unknown orientation %d", __FUNCTION__, param.value);
return false;
}
ovutils::eTransform transform =
static_cast<ovutils::eTransform>(orientation);
const ovutils::Params prms (ovutils::OVERLAY_TRANSFORM, transform);
return mUI.setParameter(prms);
}
inline bool UIMirrorPipe::setSource(const utils::PipeArgs& args) {
utils::PipeArgs arg(args);
// Rotator flag enabled because buffer comes from fb
arg.rotFlags = utils::ROT_FLAG_ENABLED;
// For true UI mirroring, want the UI to go through available RGB pipe
// so do not set the PIPE SHARE flag which allocates VG pipe
if (utils::FrameBufferInfo::getInstance()->supportTrueMirroring()) {
arg.mdpFlags = static_cast<utils::eMdpFlags>(
arg.mdpFlags & ~utils::OV_MDP_PIPE_SHARE);
}
return mUI.setSource(arg);
}
inline const utils::PipeArgs& UIMirrorPipe::getArgs() const {
return mUI.getArgs();
}
inline utils::eOverlayPipeType UIMirrorPipe::getOvPipeType() const {
return utils::OV_PIPE_TYPE_UI_MIRROR;
}
inline void UIMirrorPipe::dump() const {
ALOGE("UI Mirror Pipe");
mUI.dump();
}
} // overlay
#endif // OVERLAY_UI_PIPE_H

View File

@ -1,19 +1,19 @@
LOCAL_PATH := $(call my-dir)
#Headers to export
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
qcom_ui.cpp
LOCAL_SRC_FILES := qcomutils/profiler.cpp \
qcomutils/IdleInvalidator.cpp
LOCAL_SHARED_LIBRARIES := \
libutils \
libcutils \
libui \
libEGL
libEGL \
LOCAL_C_INCLUDES := $(TOP)/hardware/qcom/display/libgralloc \
$(TOP)/frameworks/native/services/surfaceflinger \
$(TOP)/external/skia/include/core \
$(TOP)/external/skia/include/images
LOCAL_C_INCLUDES := hardware/qcom/display/libgralloc \
frameworks/base/services/surfaceflinger \
LOCAL_CFLAGS := -DLOG_TAG=\"libQcomUI\"
@ -23,6 +23,10 @@ else
LOCAL_SHARED_LIBRARIES += libmemalloc
endif
ifeq ($(TARGET_USES_MDP3), true)
LOCAL_CFLAGS += -DUSE_MDP3
endif
LOCAL_CFLAGS += -DDEBUG_CALC_FPS
LOCAL_MODULE := libQcomUI

File diff suppressed because it is too large Load Diff

View File

@ -33,18 +33,19 @@
#include <cutils/native_handle.h>
#include <ui/GraphicBuffer.h>
#include <hardware/hwcomposer.h>
#include <hardware/hwcomposer_defs.h>
#include <ui/Region.h>
#include <EGL/egl.h>
#include <GLES/gl.h>
#include <utils/Singleton.h>
#include <cutils/properties.h>
#include "../libgralloc/gralloc_priv.h"
using namespace android;
using android::sp;
using android::GraphicBuffer;
#define HWC_BYPASS_INDEX_MASK 0x00000030
#define DEFAULT_WIDTH_RATIO 1
#define DEFAULT_HEIGHT_RATIO 1
/*
* Qcom specific Native Window perform operations
@ -53,15 +54,7 @@ enum {
NATIVE_WINDOW_SET_BUFFERS_SIZE = 0x10000000,
NATIVE_WINDOW_UPDATE_BUFFERS_GEOMETRY = 0x20000000,
NATIVE_WINDOW_SET_S3D_FORMAT = 0x40000000,
};
// Enum containing the supported composition types
enum {
COMPOSITION_TYPE_GPU = 0,
COMPOSITION_TYPE_MDP = 0x1,
COMPOSITION_TYPE_C2D = 0x2,
COMPOSITION_TYPE_CPU = 0x4,
COMPOSITION_TYPE_DYN = 0x8
NATIVE_WINDOW_SET_PIXEL_ASPECT_RATIO = 0x80000000,
};
/*
@ -80,17 +73,22 @@ enum {
LAYER_ASYNCHRONOUS = 1<<1,
};
/*
* Layer Transformation - refers to Layer::setGeometry()
*/
#define SHIFT_SRC_TRANSFORM 4
#define SRC_TRANSFORM_MASK 0x00F0
#define FINAL_TRANSFORM_MASK 0x000F
/*
* Flags set by the layer and sent to HWC
*/
enum {
HWC_LAYER_NOT_UPDATING = 0x00000002,
HWC_LAYER_ASYNCHRONOUS = 0x00000004,
HWC_USE_ORIGINAL_RESOLUTION = 0x10000000,
HWC_DO_NOT_USE_OVERLAY = 0x20000000,
HWC_COMP_BYPASS = 0x40000000,
HWC_USE_EXT_ONLY = 0x80000000, //Layer displayed on external only
HWC_USE_EXT_BLOCK = 0x01000000, //Layer displayed on external only
HWC_COMP_BYPASS = 0x10000000,
HWC_USE_EXT_ONLY = 0x20000000, //Layer displayed on external only
HWC_USE_EXT_BLOCK = 0x40000000, //Layer displayed on external only
HWC_BYPASS_RESERVE_0 = 0x00000010,
HWC_BYPASS_RESERVE_1 = 0x00000020,
};
@ -101,10 +99,41 @@ enum HWCCompositionType {
HWC_USE_COPYBIT // This layer is to be handled by copybit
};
enum external_display {
EXT_DISPLAY_OFF,
EXT_DISPLAY_HDMI,
EXT_DISPLAY_WIFI
enum external_display_type {
EXT_TYPE_NONE,
EXT_TYPE_HDMI,
EXT_TYPE_WIFI
};
/* Events to the Display HAL perform function
As of now used for external display related such as
connect, disconnect, orientation, video started etc.,
*/
enum {
EVENT_EXTERNAL_DISPLAY, // External display on/off Event
EVENT_VIDEO_OVERLAY, // Video Overlay start/stop Event
EVENT_ORIENTATION_CHANGE, // Orientation Change Event
EVENT_OVERLAY_STATE_CHANGE, // Overlay State Change Event
EVENT_OPEN_SECURE_START, // Start of secure session setup config by stagefright
EVENT_OPEN_SECURE_END, // End of secure session setup config by stagefright
EVENT_CLOSE_SECURE_START, // Start of secure session teardown config
EVENT_CLOSE_SECURE_END, // End of secure session teardown config
EVENT_RESET_POSTBUFFER, // Reset post framebuffer mutex
EVENT_WAIT_POSTBUFFER, // Wait until post framebuffer returns
};
// Video information sent to framebuffer HAl
// used for handling UI mirroring.
enum {
VIDEO_OVERLAY_ENDED = 0,
VIDEO_2D_OVERLAY_STARTED,
VIDEO_3D_OVERLAY_STARTED
};
// Information about overlay state change
enum {
OVERLAY_STATE_CHANGE_START = 0,
OVERLAY_STATE_CHANGE_END
};
/*
@ -115,86 +144,18 @@ struct qBufGeometry {
int height;
int format;
void set(int w, int h, int f) {
width = w;
height = h;
format = f;
width = w;
height = h;
format = f;
}
};
#ifndef DEBUG_CALC_FPS
#define CALC_FPS() ((void)0)
#define CALC_INIT() ((void)0)
#else
#define CALC_FPS() CalcFps::getInstance().Fps()
#define CALC_INIT() CalcFps::getInstance().Init()
class CalcFps : public Singleton<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;
};
#endif
#if 0
class QCBaseLayer
{
// int mS3DFormat;
// int mS3DFormat;
int32_t mComposeS3DFormat;
public:
public:
QCBaseLayer()
{
mComposeS3DFormat = 0;
@ -203,10 +164,10 @@ public:
eS3D_SIDE_BY_SIDE = 0x10000,
eS3D_TOP_BOTTOM = 0x20000
};
/*
virtual status_t setStereoscopic3DFormat(int format) { mS3DFormat = format; return 0; }
virtual int getStereoscopic3DFormat() const { return mS3DFormat; }
*/
/*
virtual status_t setStereoscopic3DFormat(int format) { mS3DFormat = format; return 0; }
virtual int getStereoscopic3DFormat() const { return mS3DFormat; }
*/
void setS3DComposeFormat (int32_t hints)
{
if (hints & HWC_HINT_DRAW_S3D_SIDE_BY_SIDE)
@ -242,21 +203,6 @@ int checkBuffer(native_handle_t *buffer_handle, int size, int usage);
*/
bool isGPUSupportedFormat(int format);
/*
* Adreno is not optimized for GL_TEXTURE_EXTERNAL_OES
* texure target. DO NOT choose TEXTURE_EXTERNAL_OES
* target for RGB formats.
*
* Based on the pixel format, decide the texture target.
*
* @param : pixel format to check
*
* @return : GL_TEXTURE_2D for RGB formats, and
* GL_TEXTURE_EXTERNAL_OES for YUV formats.
*
*/
int decideTextureTarget (const int pixel_format);
/*
* Gets the number of arguments required for this operation.
@ -277,8 +223,8 @@ int getNumberOfArgsForOperation(int operation);
* @return True if a memory reallocation is required.
*/
bool needNewBuffer(const qBufGeometry currentGeometry,
const qBufGeometry requiredGeometry,
const qBufGeometry updatedGeometry);
const qBufGeometry requiredGeometry,
const qBufGeometry updatedGeometry);
/*
* Update the geometry of this buffer without reallocation.
@ -326,13 +272,6 @@ int getPerFrameFlags(int hwclFlags, int layerFlags);
bool isUpdatingFB(HWCCompositionType compositionType);
/*
* Get the current composition Type
*
* @return the compositon Type
*/
int getCompositionType();
/*
* Clear region implementation for C2D/MDP versions.
*
@ -355,9 +294,8 @@ int qcomuiClearRegion(Region region, EGLDisplay dpy, EGLSurface sur);
* @return: external display to be enabled
*
*/
external_display handleEventHDMI(external_display newEvent, external_display
currEvent);
external_display_type handleEventHDMI(external_display_type disp, int value,
external_display_type currDispType);
/*
* Checks if layers need to be dumped based on system property "debug.sf.dump"
* for raw dumps and "debug.sf.dump.png" for png dumps.
@ -389,6 +327,10 @@ bool needToDumpLayers();
*
*/
void dumpLayer(int moduleCompositionType, int listFlags, size_t layerIndex,
hwc_layer_t hwLayers[]);
hwc_layer_t hwLayers[]);
bool needsAspectRatio (int wRatio, int hRatio);
void applyPixelAspectRatio (int wRatio, int hRatio, int orientation, int fbWidth,
int fbHeight, Rect& visibleRect, GLfloat vertices[][2]);
#endif // INCLUDE_LIBQCOM_UI

View File

@ -0,0 +1,88 @@
/*
* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "IdleInvalidator.h"
#include <unistd.h>
#define II_DEBUG 1
static const char *threadName = "Invalidator";
InvalidatorHandler IdleInvalidator::mHandler = NULL;
android::sp<IdleInvalidator> IdleInvalidator::sInstance(0);
IdleInvalidator::IdleInvalidator(): Thread(false), mHwcContext(0),
mSleepAgain(false), mSleepTime(0) {
ALOGE_IF(II_DEBUG, "shs %s", __func__);
}
int IdleInvalidator::init(InvalidatorHandler reg_handler, void* user_data,
unsigned int idleSleepTime) {
ALOGE_IF(II_DEBUG, "shs %s", __func__);
/* store registered handler */
mHandler = reg_handler;
mHwcContext = user_data;
mSleepTime = idleSleepTime; //Time in millis
return 0;
}
bool IdleInvalidator::threadLoop() {
ALOGE_IF(II_DEBUG, "shs %s", __func__);
usleep(mSleepTime * 1000);
if(mSleepAgain) {
//We need to sleep again!
mSleepAgain = false;
return true;
}
mHandler((void*)mHwcContext);
return false;
}
int IdleInvalidator::readyToRun() {
ALOGE_IF(II_DEBUG, "shs %s", __func__);
return 0; /*NO_ERROR*/
}
void IdleInvalidator::onFirstRef() {
ALOGE_IF(II_DEBUG, "shs %s", __func__);
}
void IdleInvalidator::markForSleep() {
mSleepAgain = true;
//Triggers the threadLoop to run, if not already running.
run(threadName, android::PRIORITY_AUDIO);
}
IdleInvalidator *IdleInvalidator::getInstance() {
ALOGE_IF(II_DEBUG, "shs %s", __func__);
if(sInstance.get() == NULL)
sInstance = new IdleInvalidator();
return sInstance.get();
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef INCLUDE_IDLEINVALIDATOR
#define INCLUDE_IDLEINVALIDATOR
#include <cutils/log.h>
#include <utils/threads.h>
typedef void (*InvalidatorHandler)(void*);
class IdleInvalidator : public android::Thread {
void *mHwcContext;
bool mSleepAgain;
unsigned int mSleepTime;
static InvalidatorHandler mHandler;
static android::sp<IdleInvalidator> sInstance;
public:
IdleInvalidator();
/* init timer obj */
int init(InvalidatorHandler reg_handler, void* user_data, unsigned int
idleSleepTime);
void markForSleep();
/*Overrides*/
virtual bool threadLoop();
virtual int readyToRun();
virtual void onFirstRef();
static IdleInvalidator *getInstance();
};
#endif // INCLUDE_IDLEINVALIDATOR

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef INCLUDE_LIBQCOM_COMPTYPES
#define INCLUDE_LIBQCOM_COMPTYPES
#include <stdint.h>
#include <utils/Singleton.h>
#include <cutils/properties.h>
using namespace android;
// Enum containing the supported composition types
enum {
COMPOSITION_TYPE_GPU = 0,
COMPOSITION_TYPE_MDP = 0x1,
COMPOSITION_TYPE_C2D = 0x2,
COMPOSITION_TYPE_CPU = 0x4,
COMPOSITION_TYPE_DYN = 0x8
};
/* This class caches the composition type
*/
class QCCompositionType : public Singleton <QCCompositionType>
{
public:
QCCompositionType();
~QCCompositionType() { }
int getCompositionType() {return mCompositionType;}
private:
int mCompositionType;
};
ANDROID_SINGLETON_STATIC_INSTANCE(QCCompositionType);
inline QCCompositionType::QCCompositionType()
{
char property[PROPERTY_VALUE_MAX];
mCompositionType = 0;
if (property_get("debug.sf.hw", property, NULL) > 0) {
if(atoi(property) == 0) {
mCompositionType = COMPOSITION_TYPE_CPU;
} else { //debug.sf.hw = 1
property_get("debug.composition.type", property, NULL);
if (property == NULL) {
mCompositionType = COMPOSITION_TYPE_GPU;
} else if ((strncmp(property, "mdp", 3)) == 0) {
mCompositionType = COMPOSITION_TYPE_MDP;
} else if ((strncmp(property, "c2d", 3)) == 0) {
mCompositionType = COMPOSITION_TYPE_C2D;
} else if ((strncmp(property, "dyn", 3)) == 0) {
#ifdef USE_MDP3
mCompositionType = COMPOSITION_TYPE_DYN | COMPOSITION_TYPE_MDP;
#else
mCompositionType = COMPOSITION_TYPE_DYN | COMPOSITION_TYPE_C2D;
#endif
} else {
mCompositionType = COMPOSITION_TYPE_GPU;
}
}
} else { //debug.sf.hw is not set. Use cpu composition
mCompositionType = COMPOSITION_TYPE_CPU;
}
}
#endif //INCLUDE_LIBQCOM_COMPTYPES

188
libqcomui/qcomutils/profiler.cpp Executable file
View File

@ -0,0 +1,188 @@
/*
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "profiler.h"
#ifdef DEBUG_CALC_FPS
#define LOG_TAG "CALCFPS"
#define LOG_NDDEBUG 0
ANDROID_SINGLETON_STATIC_INSTANCE(CalcFps) ;
CalcFps::CalcFps() {
debug_fps_level = 0;
Init();
}
CalcFps::~CalcFps() {
}
void CalcFps::Init() {
char prop[PROPERTY_VALUE_MAX];
property_get("debug.gr.calcfps", prop, "0");
debug_fps_level = atoi(prop);
if (debug_fps_level > MAX_DEBUG_FPS_LEVEL) {
ALOGW("out of range value for debug.gr.calcfps, using 0");
debug_fps_level = 0;
}
ALOGD("DEBUG_CALC_FPS: %d", debug_fps_level);
populate_debug_fps_metadata();
}
void CalcFps::Fps() {
if (debug_fps_level > 0)
calc_fps(ns2us(systemTime()));
}
void CalcFps::populate_debug_fps_metadata(void)
{
char prop[PROPERTY_VALUE_MAX];
/*defaults calculation of fps to based on number of frames*/
property_get("debug.gr.calcfps.type", prop, "0");
debug_fps_metadata.type = (debug_fps_metadata_t::DfmType) atoi(prop);
/*defaults to 1000ms*/
property_get("debug.gr.calcfps.timeperiod", prop, "1000");
debug_fps_metadata.time_period = atoi(prop);
property_get("debug.gr.calcfps.period", prop, "10");
debug_fps_metadata.period = atoi(prop);
if (debug_fps_metadata.period > MAX_FPS_CALC_PERIOD_IN_FRAMES) {
debug_fps_metadata.period = MAX_FPS_CALC_PERIOD_IN_FRAMES;
}
/* default ignorethresh_us: 500 milli seconds */
property_get("debug.gr.calcfps.ignorethresh_us", prop, "500000");
debug_fps_metadata.ignorethresh_us = atoi(prop);
debug_fps_metadata.framearrival_steps =
(debug_fps_metadata.ignorethresh_us / 16666);
if (debug_fps_metadata.framearrival_steps > MAX_FRAMEARRIVAL_STEPS) {
debug_fps_metadata.framearrival_steps = MAX_FRAMEARRIVAL_STEPS;
debug_fps_metadata.ignorethresh_us =
debug_fps_metadata.framearrival_steps * 16666;
}
/* 2ms margin of error for the gettimeofday */
debug_fps_metadata.margin_us = 2000;
for (unsigned int i = 0; i < MAX_FRAMEARRIVAL_STEPS; i++)
debug_fps_metadata.accum_framearrivals[i] = 0;
ALOGD("period: %d", debug_fps_metadata.period);
ALOGD("ignorethresh_us: %lld", debug_fps_metadata.ignorethresh_us);
}
void CalcFps::print_fps(float fps)
{
if (debug_fps_metadata_t::DFM_FRAMES == debug_fps_metadata.type)
ALOGD("FPS for last %d frames: %3.2f", debug_fps_metadata.period, fps);
else
ALOGD("FPS for last (%f ms, %d frames): %3.2f",
debug_fps_metadata.time_elapsed,
debug_fps_metadata.curr_frame, fps);
debug_fps_metadata.curr_frame = 0;
debug_fps_metadata.time_elapsed = 0.0;
if (debug_fps_level > 1) {
ALOGD("Frame Arrival Distribution:");
for (unsigned int i = 0;
i < ((debug_fps_metadata.framearrival_steps / 6) + 1);
i++) {
ALOGD("%lld %lld %lld %lld %lld %lld",
debug_fps_metadata.accum_framearrivals[i*6],
debug_fps_metadata.accum_framearrivals[i*6+1],
debug_fps_metadata.accum_framearrivals[i*6+2],
debug_fps_metadata.accum_framearrivals[i*6+3],
debug_fps_metadata.accum_framearrivals[i*6+4],
debug_fps_metadata.accum_framearrivals[i*6+5]);
}
/* We are done with displaying, now clear the stats */
for (unsigned int i = 0;
i < debug_fps_metadata.framearrival_steps;
i++)
debug_fps_metadata.accum_framearrivals[i] = 0;
}
return;
}
void CalcFps::calc_fps(nsecs_t currtime_us)
{
static nsecs_t oldtime_us = 0;
nsecs_t diff = currtime_us - oldtime_us;
oldtime_us = currtime_us;
if (debug_fps_metadata_t::DFM_FRAMES == debug_fps_metadata.type &&
diff > debug_fps_metadata.ignorethresh_us) {
return;
}
if (debug_fps_metadata.curr_frame < MAX_FPS_CALC_PERIOD_IN_FRAMES) {
debug_fps_metadata.framearrivals[debug_fps_metadata.curr_frame] = diff;
}
debug_fps_metadata.curr_frame++;
if (debug_fps_level > 1) {
unsigned int currstep = (diff + debug_fps_metadata.margin_us) / 16666;
if (currstep < debug_fps_metadata.framearrival_steps) {
debug_fps_metadata.accum_framearrivals[currstep-1]++;
}
}
if (debug_fps_metadata_t::DFM_FRAMES == debug_fps_metadata.type) {
if (debug_fps_metadata.curr_frame == debug_fps_metadata.period) {
/* time to calculate and display FPS */
nsecs_t sum = 0;
for (unsigned int i = 0; i < debug_fps_metadata.period; i++)
sum += debug_fps_metadata.framearrivals[i];
print_fps((debug_fps_metadata.period * float(1000000))/float(sum));
}
}
else if (debug_fps_metadata_t::DFM_TIME == debug_fps_metadata.type) {
debug_fps_metadata.time_elapsed += ((float)diff/1000.0);
if (debug_fps_metadata.time_elapsed >= debug_fps_metadata.time_period) {
float fps = (1000.0 * debug_fps_metadata.curr_frame)/
(float)debug_fps_metadata.time_elapsed;
print_fps(fps);
}
}
return;
}
#endif

107
libqcomui/qcomutils/profiler.h Executable file
View File

@ -0,0 +1,107 @@
/*
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef INCLUDE_PROFILER
#define INCLUDE_PROFILER
#include <stdio.h>
#include <utils/Singleton.h>
#include <cutils/properties.h>
#include <cutils/log.h>
using namespace android;
#ifndef DEBUG_CALC_FPS
#define CALC_FPS() ((void)0)
#define CALC_INIT() ((void)0)
#else
#define CALC_FPS() CalcFps::getInstance().Fps()
#define CALC_INIT() CalcFps::getInstance().Init()
class CalcFps : public Singleton<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;
};
#endif
#endif // INCLUDE_PROFILER

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (c) 2011 Code Aurora Forum. All rights reserved.
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -52,7 +52,7 @@ void TileRenderer::startTileRendering(OpenGLRenderer* renderer,
if (!left && !right && !top && !bottom) {
//can't do tile rendering
LOGE("can't tile render; drity region, width, height not available");
ALOGE("can't tile render; drity region, width, height not available");
return;
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -25,14 +25,14 @@ namespace uirenderer {
class OpenGLRenderer;
class TileRenderer: public Singleton<TileRenderer> {
public:
public:
TileRenderer();
~TileRenderer();
void startTileRendering(OpenGLRenderer* renderer, int left, int top, int right, int bottom);
void endTileRendering(OpenGLRenderer*);
private:
private:
bool mIsTiled;
};