display: Move HALs to new location

Change-Id: Ib1d843b4cfd71f5bbb0e5184277cbe7497180f8e
This commit is contained in:
Naseer Ahmed 2011-11-16 12:50:43 -08:00
commit cbb0b78679
32 changed files with 13231 additions and 0 deletions

1
Android.mk Normal file
View File

@ -0,0 +1 @@
# Empty Android.mk

73
libcopybit/Android.mk Normal file
View File

@ -0,0 +1,73 @@
# 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
LOCAL_SRC_FILES := copybit_c2d.cpp
LOCAL_MODULE := copybit.$(TARGET_BOARD_PLATFORM)
LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
LOCAL_C_INCLUDES += hardware/msm7k/libgralloc-qsd8k
LOCAL_CFLAGS += -DCOPYBIT_Z180=1 -DC2D_SUPPORT_DISPLAY=1
include $(BUILD_SHARED_LIBRARY)
else
ifneq "$(findstring msm7630,$(TARGET_PRODUCT))" "msm7630"
ifeq ($(TARGET_BOARD_PLATFORM),msm7k)
include $(CLEAR_VARS)
ifeq ($(TARGET_GRALLOC_USES_ASHMEM),true)
LOCAL_CFLAGS += -DUSE_ASHMEM
ifeq "$(findstring msm7627,$(TARGET_PRODUCT))" "msm7627"
LOCAL_CFLAGS += -DTARGET_7x27
endif
endif
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := copybit.cpp
LOCAL_MODULE := copybit.msm7k
LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
LOCAL_C_INCLUDES += hardware/msm7k/libgralloc-qsd8k
LOCAL_CFLAGS += -DCOPYBIT_MSM7K=1
include $(BUILD_SHARED_LIBRARY)
endif
ifeq ($(TARGET_BOARD_PLATFORM),qsd8k)
include $(CLEAR_VARS)
ifeq ($(TARGET_GRALLOC_USES_ASHMEM),true)
LOCAL_CFLAGS += -DUSE_ASHMEM
endif
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := copybit.cpp
LOCAL_MODULE := copybit.qsd8k
LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
LOCAL_C_INCLUDES += hardware/msm7k/libgralloc-qsd8k
LOCAL_CFLAGS += -DCOPYBIT_QSD8K=1
include $(BUILD_SHARED_LIBRARY)
endif
endif
endif

View File

190
libcopybit/NOTICE Normal file
View File

@ -0,0 +1,190 @@
Copyright (c) 2008, The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

618
libcopybit/c2d2.h Normal file
View File

@ -0,0 +1,618 @@
/* Copyright (c) 2010, 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
#include <EGL/egl.h> /* for EGL surfaces */
#ifndef C2D_API
#define C2D_API /* define API export as needed */
#endif
#ifndef int32
typedef int int32;
#endif
#ifndef uint32
typedef unsigned int uint32;
#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 COMP_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_EGL = 0, /* Arbitrary EGL surface */
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 allready mapped */
/* this bit is valid with HOST types */
} C2D_SURFACE_TYPE;
/* Structure for registering an EGL surface as a blit surface */
typedef struct {
EGLDisplay display; /* EGL display */
EGLContext context; /* EGL context, reserved - pass EGL_NO_CONTEXT */
EGLSurface surface; /* EGL surface */
} C2D_EGL_SURFACE_DEF;
/* 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.
* arbitrary EGL surface (including proprietary Command List Surface):
* surface_type = C2D_SURFACE_EGL
* surface_definition = C2D_EGL_SURFACE_DEF
* all fields in definition structure should be set
* context field is reserved and can be ignored
* 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);
/*****************************************************************************/
#ifdef __cplusplus
}
#endif
#endif /* __c2d2_h_ */

498
libcopybit/copybit.cpp Normal file
View File

@ -0,0 +1,498 @@
/*
* 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.
*/
#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 <hardware/copybit.h>
#include "gralloc_priv.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;
uint8_t 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;
}
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;
img->width = rhs->w;
img->height = rhs->h;
img->format = get_format(rhs->format);
img->offset = hnd->offset;
#if defined(COPYBIT_MSM7K)
#if defined(USE_ASHMEM) && (TARGET_7x27)
img->memory_id = hnd->fd;
#else //USE_ASHMEM not defined
img->memory_id = hnd->fd;
#endif //end USE_ASHMEM
#else
img->memory_id = hnd->fd;
#endif
}
/** 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;
if (dev->mFlags & COPYBIT_TRANSFORM_ROT_90) {
e->src_rect.x = (clip.t - dst->t) + src->t;
e->src_rect.y = (dst->r - clip.r) + src->l;
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 {
e->src_rect.x = (clip.l - dst->l) + src->l;
e->src_rect.y = (clip.t - dst->t) + src->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(&e->src_rect.x, &e->src_rect.w, src->r - src->l, W);
MULDIV(&e->src_rect.y, &e->src_rect.h, src->b - src->t, H);
if (dev->mFlags & COPYBIT_TRANSFORM_FLIP_V) {
if (dev->mFlags & COPYBIT_TRANSFORM_ROT_90) {
e->src_rect.x = e->src.width - (e->src_rect.x + e->src_rect.w) - horiz_padding;
}else{
e->src_rect.y = e->src.height - (e->src_rect.y + e->src_rect.h) - vert_padding;
}
}
if (dev->mFlags & COPYBIT_TRANSFORM_FLIP_H) {
if (dev->mFlags & COPYBIT_TRANSFORM_ROT_90) {
e->src_rect.y = e->src.height - (e->src_rect.y + e->src_rect.h) - vert_padding;
}else{
e->src_rect.x = e->src.width - (e->src_rect.x + e->src_rect.w) - horiz_padding;
}
}
}
/** 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);
LOGE_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++) {
LOGD("%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:
LOGE("Invalid value for COPYBIT_ROTATION_DEG");
status = -EINVAL;
break;
}
break;
case COPYBIT_PLANE_ALPHA:
if (value < 0) value = 0;
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_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;
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:
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
return -EINVAL;
}
if (src->w > MAX_DIMENSION || src->h > MAX_DIMENSION)
return -EINVAL;
if (dst->w > MAX_DIMENSION || dst->h > MAX_DIMENSION)
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;
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 {
status = -EINVAL;
}
return status;
}
/** Perform a blit type operation */
static int blit_copybit(
struct copybit_device_t *dev,
struct copybit_image_t const *dst,
struct copybit_image_t const *src,
struct copybit_region_t const *region)
{
struct copybit_rect_t dr = { 0, 0, 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;
LOGE("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 {
LOGE("Error not msm frame buffer");
status = -EINVAL;
}
} else {
LOGE("Error executing ioctl for screen info");
status = -errno;
}
}
if (status == 0) {
*device = &ctx->device.common;
} else {
close_copybit(&ctx->device.common);
}
return status;
}

1036
libcopybit/copybit_c2d.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,66 @@
# 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.
ifneq ($(TARGET_USES_ION),true)
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
LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include \
hardware/qcom/display/libgralloc
LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
LOCAL_SRC_FILES := \
allocator.cpp \
framebuffer.cpp \
gpu.cpp \
gralloc.cpp \
mapper.cpp \
pmemalloc.cpp
LOCAL_MODULE := gralloc.$(TARGET_BOARD_PLATFORM)
LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).gralloc\" -DHOST -DDEBUG_CALC_FPS
ifneq (, $(filter msm7625_ffa msm7625_surf msm7627_ffa msm7627_surf msm7627_7x_ffa msm7627_7x_surf, $(QCOM_TARGET_PRODUCT)))
LOCAL_CFLAGS += -DTARGET_MSM7x27
endif
ifeq ($(TARGET_HAVE_HDMI_OUT),true)
LOCAL_CFLAGS += -DHDMI_DUAL_DISPLAY
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../liboverlay
LOCAL_SHARED_LIBRARIES += liboverlay
endif
ifeq ($(TARGET_GRALLOC_USES_ASHMEM),true)
LOCAL_CFLAGS += -DUSE_ASHMEM
endif
include $(BUILD_SHARED_LIBRARY)
# Build a host library for testing
ifeq ($(HOST_OS),linux)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
gpu.cpp \
pmemalloc.cpp
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := libgralloc_qsd8k_host
LOCAL_CFLAGS:= -DLOG_TAG=\"gralloc-qsd8k\"
include $(BUILD_HOST_STATIC_LIBRARY)
endif
endif

View File

190
libgralloc-qsd8k/NOTICE Normal file
View File

@ -0,0 +1,190 @@
Copyright (c) 2008-2009, The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View File

@ -0,0 +1,165 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <cutils/log.h>
#include "allocator.h"
// align all the memory blocks on a cache-line boundary
const int SimpleBestFitAllocator::kMemoryAlign = 32;
SimpleBestFitAllocator::SimpleBestFitAllocator()
: mHeapSize(0)
{
}
SimpleBestFitAllocator::SimpleBestFitAllocator(size_t size)
: mHeapSize(0)
{
setSize(size);
}
SimpleBestFitAllocator::~SimpleBestFitAllocator()
{
while(!mList.isEmpty()) {
delete mList.remove(mList.head());
}
}
ssize_t SimpleBestFitAllocator::setSize(size_t size)
{
Locker::Autolock _l(mLock);
if (mHeapSize != 0) return -EINVAL;
size_t pagesize = getpagesize();
mHeapSize = ((size + pagesize-1) & ~(pagesize-1));
chunk_t* node = new chunk_t(0, mHeapSize / kMemoryAlign);
mList.insertHead(node);
return size;
}
size_t SimpleBestFitAllocator::size() const
{
return mHeapSize;
}
ssize_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags)
{
Locker::Autolock _l(mLock);
if (mHeapSize == 0) return -EINVAL;
ssize_t offset = alloc(size, flags);
return offset;
}
ssize_t SimpleBestFitAllocator::deallocate(size_t offset)
{
Locker::Autolock _l(mLock);
if (mHeapSize == 0) return -EINVAL;
chunk_t const * const freed = dealloc(offset);
if (freed) {
return 0;
}
return -ENOENT;
}
ssize_t SimpleBestFitAllocator::alloc(size_t size, uint32_t flags)
{
if (size == 0) {
return 0;
}
size = (size + kMemoryAlign-1) / kMemoryAlign;
chunk_t* free_chunk = 0;
chunk_t* cur = mList.head();
size_t pagesize = getpagesize();
while (cur) {
int extra = ( -cur->start & ((pagesize/kMemoryAlign)-1) ) ;
// best fit
if (cur->free && (cur->size >= (size+extra))) {
if ((!free_chunk) || (cur->size < free_chunk->size)) {
free_chunk = cur;
}
if (cur->size == size) {
break;
}
}
cur = cur->next;
}
if (free_chunk) {
const size_t free_size = free_chunk->size;
free_chunk->free = 0;
free_chunk->size = size;
if (free_size > size) {
int extra = ( -free_chunk->start & ((pagesize/kMemoryAlign)-1) ) ;
if (extra) {
chunk_t* split = new chunk_t(free_chunk->start, extra);
free_chunk->start += extra;
mList.insertBefore(free_chunk, split);
}
LOGE_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);
mList.insertAfter(free_chunk, split);
}
}
return (free_chunk->start)*kMemoryAlign;
}
return -ENOMEM;
}
SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start)
{
start = start / kMemoryAlign;
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);
// merge freed blocks together
chunk_t* freed = cur;
cur->free = 1;
do {
chunk_t* const p = cur->prev;
chunk_t* const n = cur->next;
if (p && (p->free || !cur->size)) {
freed = p;
p->size += cur->size;
mList.remove(cur);
delete cur;
}
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);
return freed;
}
cur = cur->next;
}
return 0;
}

View File

@ -0,0 +1,130 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef GRALLOC_ALLOCATOR_H_
#define GRALLOC_ALLOCATOR_H_
#include <stdint.h>
#include <sys/types.h>
#include "gr.h"
#include "pmemalloc.h"
// ----------------------------------------------------------------------------
/*
* A simple templatized doubly linked-list implementation
*/
template <typename NODE>
class LinkedList
{
NODE* mFirst;
NODE* mLast;
public:
LinkedList() : mFirst(0), mLast(0) { }
bool isEmpty() const { return mFirst == 0; }
NODE const* head() const { return mFirst; }
NODE* head() { return mFirst; }
NODE const* tail() const { return mLast; }
NODE* tail() { return mLast; }
void insertAfter(NODE* node, NODE* newNode) {
newNode->prev = node;
newNode->next = node->next;
if (node->next == 0) mLast = newNode;
else node->next->prev = newNode;
node->next = newNode;
}
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;
}
void insertHead(NODE* newNode) {
if (mFirst == 0) {
mFirst = mLast = newNode;
newNode->prev = newNode->next = 0;
} else {
newNode->prev = 0;
newNode->next = mFirst;
mFirst->prev = newNode;
mFirst = newNode;
}
}
void insertTail(NODE* newNode) {
if (mLast == 0) {
insertHead(newNode);
} else {
newNode->prev = mLast;
newNode->next = 0;
mLast->next = newNode;
mLast = newNode;
}
}
NODE* remove(NODE* node) {
if (node->prev == 0) mFirst = node->next;
else node->prev->next = node->next;
if (node->next == 0) mLast = node->prev;
else node->next->prev = node->prev;
return node;
}
};
class SimpleBestFitAllocator : public PmemUserspaceAllocator::Deps::Allocator
{
public:
SimpleBestFitAllocator();
SimpleBestFitAllocator(size_t size);
virtual ~SimpleBestFitAllocator();
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;
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);
static const int kMemoryAlign;
mutable Locker mLock;
LinkedList<chunk_t> mList;
size_t mHeapSize;
};
#endif /* GRALLOC_ALLOCATOR_H_ */

File diff suppressed because it is too large Load Diff

505
libgralloc-qsd8k/gpu.cpp Executable file
View File

@ -0,0 +1,505 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <cutils/properties.h>
#ifdef HOST
#include <linux/ashmem.h>
#endif
#include "gr.h"
#include "gpu.h"
static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
static const int QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka = 0x7FA30C03;
static const int QOMX_INTERLACE_FLAG = 0x49283654;
static const int QOMX_3D_VIDEO_FLAG = 0x23784238;
gpu_context_t::gpu_context_t(Deps& deps, PmemAllocator& pmemAllocator,
PmemAllocator& pmemAdspAllocator, const private_module_t* module) :
deps(deps),
pmemAllocator(pmemAllocator),
pmemAdspAllocator(pmemAdspAllocator)
{
// 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;
common.module = const_cast<hw_module_t*>(&module->base.common);
common.close = gralloc_close;
alloc = gralloc_alloc;
allocSize = gralloc_alloc_size;
free = gralloc_free;
}
int gpu_context_t::gralloc_alloc_framebuffer_locked(size_t size, int usage,
buffer_handle_t* pHandle)
{
private_module_t* m = reinterpret_cast<private_module_t*>(common.module);
// we don't support allocations with both the FB and PMEM_ADSP flags
if (usage & GRALLOC_USAGE_PRIVATE_ADSP_HEAP) {
return -EINVAL;
}
// allocate the framebuffer
if (m->framebuffer == NULL) {
// initialize the framebuffer, the framebuffer is mapped once
// and forever.
int err = deps.mapFrameBufferLocked(m);
if (err < 0) {
return err;
}
}
const uint32_t bufferMask = m->bufferMask;
const uint32_t numBuffers = m->numBuffers;
const size_t bufferSize = m->finfo.line_length * m->info.yres;
if (numBuffers == 1) {
// If we have only one buffer, we never use page-flipping. Instead,
// we return a regular buffer which will be memcpy'ed to the main
// screen when post is called.
int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;
return gralloc_alloc_buffer(bufferSize, newUsage, pHandle, BUFFER_TYPE_UI, m->fbFormat, m->info.xres, m->info.yres);
}
if (bufferMask >= ((1LU<<numBuffers)-1)) {
// We ran out of buffers.
return -ENOMEM;
}
// create a "fake" handles for it
intptr_t vaddr = intptr_t(m->framebuffer->base);
private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), bufferSize,
private_handle_t::PRIV_FLAGS_USES_PMEM |
private_handle_t::PRIV_FLAGS_FRAMEBUFFER,
BUFFER_TYPE_UI, m->fbFormat, m->info.xres, m->info.yres);
// find a free slot
for (uint32_t i=0 ; i<numBuffers ; i++) {
if ((bufferMask & (1LU<<i)) == 0) {
m->bufferMask |= (1LU<<i);
break;
}
vaddr += bufferSize;
}
hnd->base = vaddr;
hnd->offset = vaddr - intptr_t(m->framebuffer->base);
*pHandle = hnd;
return 0;
}
int gpu_context_t::gralloc_alloc_framebuffer(size_t size, int usage,
buffer_handle_t* pHandle)
{
private_module_t* m = reinterpret_cast<private_module_t*>(common.module);
pthread_mutex_lock(&m->lock);
int err = gralloc_alloc_framebuffer_locked(size, usage, pHandle);
pthread_mutex_unlock(&m->lock);
return err;
}
int gpu_context_t::alloc_ashmem_buffer(size_t size, unsigned int postfix, void** pBase,
int* pOffset, int* pFd)
{
int err = 0;
int fd = -1;
void* base = 0;
int offset = 0;
char name[ASHMEM_NAME_LEN];
snprintf(name, ASHMEM_NAME_LEN, "gralloc-buffer-%x", postfix);
int prot = PROT_READ | PROT_WRITE;
fd = ashmem_create_region(name, size);
if (fd < 0) {
LOGE("couldn't create ashmem (%s)", strerror(errno));
err = -errno;
} else {
if (ashmem_set_prot_region(fd, prot) < 0) {
LOGE("ashmem_set_prot_region(fd=%d, prot=%x) failed (%s)",
fd, prot, strerror(errno));
close(fd);
err = -errno;
} else {
base = mmap(0, size, prot, MAP_SHARED|MAP_POPULATE|MAP_LOCKED, fd, 0);
if (base == MAP_FAILED) {
LOGE("alloc mmap(fd=%d, size=%d, prot=%x) failed (%s)",
fd, size, prot, strerror(errno));
close(fd);
err = -errno;
} else {
memset((char*)base + offset, 0, size);
}
}
}
if(err == 0) {
*pFd = fd;
*pBase = base;
*pOffset = offset;
#ifdef HOST
if (ioctl(fd, ASHMEM_CACHE_INV_RANGE, NULL)) {
LOGE("ASHMEM_CACHE_INV_RANGE failed fd = %d", fd);
}
#endif
}
return err;
}
int gpu_context_t::gralloc_alloc_buffer(size_t size, int usage, buffer_handle_t* pHandle,
int bufferType, int format, int width, int height)
{
int err = 0;
int flags = 0;
int fd = -1;
void* base = 0; // XXX JMG: This should change to just get an address from
// the PmemAllocator rather than getting the base & offset separately
int offset = 0;
int lockState = 0;
size = roundUpToPageSize(size);
#ifndef USE_ASHMEM
if (usage & GRALLOC_USAGE_HW_TEXTURE) {
// enable pmem in that case, so our software GL can fallback to
// the copybit module.
flags |= private_handle_t::PRIV_FLAGS_USES_PMEM;
}
if (usage & GRALLOC_USAGE_HW_2D) {
flags |= private_handle_t::PRIV_FLAGS_USES_PMEM;
}
#else
// Enable use of PMEM only when MDP composition is used (and other conditions apply).
// Else fall back on using ASHMEM
if ((get_composition_type() == MDP_COMPOSITION) &&
((usage & GRALLOC_USAGE_HW_TEXTURE) || (usage & GRALLOC_USAGE_HW_2D)) ) {
flags |= private_handle_t::PRIV_FLAGS_USES_PMEM;
}
if (usage & GRALLOC_USAGE_PRIVATE_EBI_HEAP) {
flags |= private_handle_t::PRIV_FLAGS_USES_PMEM;
}
#endif
if ((usage & GRALLOC_USAGE_PRIVATE_ADSP_HEAP) || (usage & GRALLOC_USAGE_PRIVATE_SMI_HEAP)
|| (usage & GRALLOC_USAGE_EXTERNAL_DISP) || (usage & GRALLOC_USAGE_PROTECTED)) {
flags |= private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP;
flags &= ~private_handle_t::PRIV_FLAGS_USES_PMEM;
}
private_module_t* m = reinterpret_cast<private_module_t*>(common.module);
if((flags & private_handle_t::PRIV_FLAGS_USES_PMEM) == 0 &&
(flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) == 0) {
flags |= private_handle_t::PRIV_FLAGS_USES_ASHMEM;
err = alloc_ashmem_buffer(size, (unsigned int)pHandle, &base, &offset, &fd);
if(err >= 0)
lockState |= private_handle_t::LOCK_STATE_MAPPED;
}
else if ((flags & private_handle_t::PRIV_FLAGS_USES_PMEM) != 0 ||
(flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) != 0) {
PmemAllocator* pma = 0;
if ((flags & private_handle_t::PRIV_FLAGS_USES_PMEM) != 0) {
if ((flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) != 0) {
LOGE("attempting to allocate a gralloc buffer with both the "
"USES_PMEM and USES_PMEM_ADSP flags. Unsetting the "
"USES_PMEM_ADSP flag.");
flags &= ~private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP;
}
pma = &pmemAllocator;
} else { // (flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) != 0
pma = &pmemAdspAllocator;
}
// PMEM buffers are always mmapped
lockState |= private_handle_t::LOCK_STATE_MAPPED;
err = pma->alloc_pmem_buffer(size, usage, &base, &offset, &fd, format);
if (err < 0) {
// Pmem allocation failed. Try falling back to ashmem iff we are:
// a. not using MDP composition
// b. not allocating memory for a buffer to be used by overlays
// c. The client has not explicitly requested a PMEM buffer
if ((get_composition_type() != MDP_COMPOSITION) &&
(bufferType != BUFFER_TYPE_VIDEO) &&
((usage & GRALLOC_USAGE_PRIVATE_EBI_HEAP) == 0) &&
((usage & GRALLOC_USAGE_PRIVATE_ADSP_HEAP) == 0)) {
// the caller didn't request PMEM, so we can try something else
flags &= ~private_handle_t::PRIV_FLAGS_USES_PMEM;
err = 0;
LOGE("Pmem allocation failed. Trying ashmem");
goto try_ashmem;
} else {
LOGE("couldn't open pmem (%s)", strerror(errno));
}
}
} else {
try_ashmem:
err = alloc_ashmem_buffer(size, (unsigned int)pHandle, &base, &offset, &fd);
if (err >= 0) {
lockState |= private_handle_t::LOCK_STATE_MAPPED;
flags |= private_handle_t::PRIV_FLAGS_USES_ASHMEM;
} else {
LOGE("Ashmem fallback failed");
}
}
if (err == 0) {
private_handle_t* hnd = new private_handle_t(fd, size, flags, bufferType, format, width, height);
hnd->offset = offset;
hnd->base = int(base)+offset;
hnd->lockState = lockState;
*pHandle = hnd;
}
LOGE_IF(err, "gralloc failed err=%s", strerror(-err));
return err;
}
static inline size_t ALIGN(size_t x, size_t align) {
return (x + align-1) & ~(align-1);
}
void gpu_context_t::getGrallocInformationFromFormat(int inputFormat, int *colorFormat, int *bufferType)
{
*bufferType = BUFFER_TYPE_VIDEO;
*colorFormat = inputFormat;
if (inputFormat == HAL_PIXEL_FORMAT_YV12) {
*bufferType = BUFFER_TYPE_VIDEO;
} else if (inputFormat & S3D_FORMAT_MASK) {
// S3D format
*colorFormat = COLOR_FORMAT(inputFormat);
} else if (inputFormat & INTERLACE_MASK) {
// Interlaced
*colorFormat = inputFormat ^ HAL_PIXEL_FORMAT_INTERLACE;
} else if (inputFormat < 0x7) {
// RGB formats
*colorFormat = inputFormat;
*bufferType = BUFFER_TYPE_UI;
} else if ((inputFormat == HAL_PIXEL_FORMAT_R_8) ||
(inputFormat == HAL_PIXEL_FORMAT_RG_88)) {
*colorFormat = inputFormat;
*bufferType = BUFFER_TYPE_UI;
}
}
int gpu_context_t::alloc_impl(int w, int h, int format, int usage,
buffer_handle_t* pHandle, int* pStride, int bufferSize) {
if (!pHandle || !pStride)
return -EINVAL;
size_t size, alignedw, alignedh;
alignedw = ALIGN(w, 32);
alignedh = ALIGN(h, 32);
int colorFormat, bufferType;
getGrallocInformationFromFormat(format, &colorFormat, &bufferType);
switch (colorFormat) {
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_RGBX_8888:
case HAL_PIXEL_FORMAT_BGRA_8888:
size = alignedw * alignedh * 4;
break;
case HAL_PIXEL_FORMAT_RGB_888:
size = alignedw * alignedh * 3;
break;
case HAL_PIXEL_FORMAT_RGB_565:
case HAL_PIXEL_FORMAT_RGBA_5551:
case HAL_PIXEL_FORMAT_RGBA_4444:
size = alignedw * alignedh * 2;
break;
// adreno formats
case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO: // NV21
size = ALIGN(alignedw*alignedh, 4096);
size += ALIGN(2 * ALIGN(w/2, 32) * ALIGN(h/2, 32), 4096);
break;
case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: // NV12
// The chroma plane is subsampled,
// but the pitch in bytes is unchanged
// The GPU needs 4K alignment, but the video decoder needs 8K
alignedw = ALIGN(w, 128);
size = ALIGN( alignedw * alignedh, 8192);
size += ALIGN( alignedw * ALIGN(h/2, 32), 8192);
break;
case HAL_PIXEL_FORMAT_YCbCr_420_SP:
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
case HAL_PIXEL_FORMAT_YV12:
if ((w&1) || (h&1)) {
LOGE("w or h is odd for the YUV format");
return -EINVAL;
}
alignedw = ALIGN(w, 16);
alignedh = h;
size = alignedw*alignedh +
(ALIGN(alignedw/2, 16) * (alignedh/2))*2;
size = ALIGN(size, 4096);
break;
default:
LOGE("unrecognized pixel format: %d", format);
return -EINVAL;
}
if ((ssize_t)size <= 0)
return -EINVAL;
size = (bufferSize >= size)? bufferSize : size;
// 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;
}
int err;
if (usage & GRALLOC_USAGE_HW_FB) {
err = gralloc_alloc_framebuffer(size, usage, pHandle);
} else {
err = gralloc_alloc_buffer(size, usage, pHandle, bufferType, format, alignedw, alignedh);
}
if (err < 0) {
return err;
}
*pStride = alignedw;
return 0;
}
int gpu_context_t::free_impl(private_handle_t const* hnd) {
private_module_t* m = reinterpret_cast<private_module_t*>(common.module);
if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
// free this buffer
const size_t bufferSize = m->finfo.line_length * m->info.yres;
int index = (hnd->base - m->framebuffer->base) / bufferSize;
m->bufferMask &= ~(1<<index);
} else {
PmemAllocator* pmem_allocator = 0;
if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM) {
pmem_allocator = &pmemAllocator;
} else if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP) {
pmem_allocator = &pmemAdspAllocator;
} else if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_ASHMEM) {
// free ashmem
if (hnd->fd >= 0) {
if (hnd->base) {
int err = munmap((void*)hnd->base, hnd->size);
LOGE_IF(err<0, "ASHMEM_UNMAP failed (%s), "
"fd=%d, sub.offset=%d, sub.size=%d",
strerror(errno), hnd->fd, hnd->offset, hnd->size);
}
}
}
if (pmem_allocator) {
pmem_allocator->free_pmem_buffer(hnd->size, (void*)hnd->base,
hnd->offset, hnd->fd);
}
deps.terminateBuffer(&m->base, const_cast<private_handle_t*>(hnd));
}
deps.close(hnd->fd);
delete hnd; // XXX JMG: move this to the deps
return 0;
}
/******************************************************************************
* Static functions
*****************************************************************************/
int gpu_context_t::gralloc_alloc(alloc_device_t* dev, int w, int h, int format,
int usage, buffer_handle_t* pHandle, int* pStride)
{
if (!dev) {
return -EINVAL;
}
gpu_context_t* gpu = reinterpret_cast<gpu_context_t*>(dev);
return gpu->alloc_impl(w, h, format, usage, pHandle, pStride, 0);
}
int gpu_context_t::gralloc_alloc_size(alloc_device_t* dev, int w, int h, int format,
int usage, buffer_handle_t* pHandle, int* pStride, int bufferSize)
{
if (!dev) {
return -EINVAL;
}
gpu_context_t* gpu = reinterpret_cast<gpu_context_t*>(dev);
return gpu->alloc_impl(w, h, format, usage, pHandle, pStride, bufferSize);
}
int gpu_context_t::gralloc_free(alloc_device_t* dev,
buffer_handle_t handle)
{
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(handle);
gpu_context_t* gpu = reinterpret_cast<gpu_context_t*>(dev);
return gpu->free_impl(hnd);
}
/*****************************************************************************/
int gpu_context_t::gralloc_close(struct hw_device_t *dev)
{
gpu_context_t* ctx = reinterpret_cast<gpu_context_t*>(dev);
if (ctx) {
/* TODO: keep a list of all buffer_handle_t created, and free them
* all here.
*/
delete ctx;
}
return 0;
}
gpu_context_t::Deps::~Deps() {}

84
libgralloc-qsd8k/gpu.h Executable file
View File

@ -0,0 +1,84 @@
/*
* 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 GRALLOC_QSD8K_GPU_H_
#define GRALLOC_QSD8K_GPU_H_
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <cutils/log.h>
#include <cutils/ashmem.h>
#include "gralloc_priv.h"
#include "pmemalloc.h"
class gpu_context_t : public alloc_device_t {
public:
class Deps {
public:
virtual ~Deps();
// ashmem
virtual int ashmem_create_region(const char *name, size_t size) = 0;
// POSIX
virtual int close(int fd) = 0;
// Framebuffer (locally defined)
virtual int mapFrameBufferLocked(struct private_module_t* module) = 0;
virtual int terminateBuffer(gralloc_module_t const* module,
private_handle_t* hnd) = 0;
};
gpu_context_t(Deps& deps, PmemAllocator& pmemAllocator,
PmemAllocator& pmemAdspAllocator, const private_module_t* module);
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_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 alloc_impl(int w, int h, int format, int usage,
buffer_handle_t* pHandle, int* pStride, int bufferSize = 0);
static int gralloc_alloc(alloc_device_t* dev, int w, int h, int format,
int usage, buffer_handle_t* pHandle, int* pStride);
static int gralloc_free(alloc_device_t* dev, buffer_handle_t handle);
static int gralloc_alloc_size(alloc_device_t* dev, int w, int h, int format,
int usage, buffer_handle_t* pHandle, int* pStride, int bufferSize);
static int gralloc_close(struct hw_device_t *dev);
int get_composition_type() const { return compositionType; }
private:
Deps& deps;
PmemAllocator& pmemAllocator;
PmemAllocator& pmemAdspAllocator;
int compositionType;
int alloc_ashmem_buffer(size_t size, unsigned int postfix, void** pBase,
int* pOffset, int* pFd);
void getGrallocInformationFromFormat(int inputFormat, int *colorFormat, int *bufferType);
};
#endif // GRALLOC_QSD8K_GPU_H

69
libgralloc-qsd8k/gr.h Normal file
View File

@ -0,0 +1,69 @@
/*
* 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 GR_H_
#define GR_H_
#include <stdint.h>
#ifdef HAVE_ANDROID_OS // just want PAGE_SIZE define
# include <asm/page.h>
#else
# include <sys/user.h>
#endif
#include <limits.h>
#include <sys/cdefs.h>
#include <hardware/gralloc.h>
#include <pthread.h>
#include <errno.h>
#include <cutils/native_handle.h>
/*****************************************************************************/
struct private_module_t;
struct private_handle_t;
inline size_t roundUpToPageSize(size_t x) {
return (x + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
}
#define FALSE 0
#define TRUE 1
int mapFrameBufferLocked(struct private_module_t* module);
int terminateBuffer(gralloc_module_t const* module, private_handle_t* hnd);
size_t calculateBufferSize(int width, int height, int format);
int decideBufferHandlingMechanism(int format, const char *compositionUsed,
int hasBlitEngine, int *needConversion,
int *useBufferDirectly);
/*****************************************************************************/
class Locker {
pthread_mutex_t mutex;
public:
class Autolock {
Locker& locker;
public:
inline Autolock(Locker& locker) : locker(locker) { locker.lock(); }
inline ~Autolock() { locker.unlock(); }
};
inline Locker() { pthread_mutex_init(&mutex, 0); }
inline ~Locker() { pthread_mutex_destroy(&mutex); }
inline void lock() { pthread_mutex_lock(&mutex); }
inline void unlock() { pthread_mutex_unlock(&mutex); }
};
#endif /* GR_H_ */

231
libgralloc-qsd8k/gralloc.cpp Executable file
View File

@ -0,0 +1,231 @@
/*
* 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.
*/
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <linux/android_pmem.h>
#include "allocator.h"
#include "gr.h"
#include "gpu.h"
/*****************************************************************************/
static int gralloc_alloc_buffer(alloc_device_t* dev,
size_t size, int usage, buffer_handle_t* pHandle);
/*****************************************************************************/
int fb_device_open(const hw_module_t* module, const char* name,
hw_device_t** device);
static int gralloc_device_open(const hw_module_t* module, const char* name,
hw_device_t** device);
extern int gralloc_lock(gralloc_module_t const* module,
buffer_handle_t handle, int usage,
int l, int t, int w, int h,
void** vaddr);
extern int gralloc_unlock(gralloc_module_t const* module,
buffer_handle_t handle);
extern int gralloc_register_buffer(gralloc_module_t const* module,
buffer_handle_t handle);
extern int gralloc_unregister_buffer(gralloc_module_t const* module,
buffer_handle_t handle);
extern int gralloc_perform(struct gralloc_module_t const* module,
int operation, ... );
/*****************************************************************************/
/* On-device dependency implementation */
class PmemAllocatorDepsDeviceImpl : public PmemUserspaceAllocator::Deps,
public PmemKernelAllocator::Deps {
const private_module_t* module;
virtual size_t getPmemTotalSize(int fd, size_t* size) {
int err = 0;
#ifndef TARGET_MSM7x27
pmem_region region;
err = ioctl(fd, PMEM_GET_TOTAL_SIZE, &region);
if (err == 0) {
*size = region.len;
}
#else
#ifdef USE_ASHMEM
if(module != NULL)
*size = module->info.xres * module->info.yres * 2 * 2;
else
return -ENOMEM;
#else
*size = 23<<20; //23MB for 7x27
#endif
#endif
return err;
}
virtual int connectPmem(int fd, int master_fd) {
return ioctl(fd, PMEM_CONNECT, master_fd);
}
virtual int mapPmem(int fd, int offset, size_t size) {
struct pmem_region sub = { offset, size };
return ioctl(fd, PMEM_MAP, &sub);
}
virtual int unmapPmem(int fd, int offset, size_t size) {
struct pmem_region sub = { offset, size };
return ioctl(fd, PMEM_UNMAP, &sub);
}
virtual int alignPmem(int fd, size_t size, int align) {
struct pmem_allocation allocation;
allocation.size = size;
allocation.align = align;
return ioctl(fd, PMEM_ALLOCATE_ALIGNED, &allocation);
}
virtual int cleanPmem(int fd, unsigned long base, int offset, size_t size) {
struct pmem_addr pmem_addr;
pmem_addr.vaddr = base;
pmem_addr.offset = offset;
pmem_addr.length = size;
return ioctl(fd, PMEM_CLEAN_INV_CACHES, &pmem_addr);
}
virtual int getErrno() {
return errno;
}
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
off_t offset) {
return ::mmap(start, length, prot, flags, fd, offset);
}
virtual int munmap(void* start, size_t length) {
return ::munmap(start, length);
}
virtual int open(const char* pathname, int flags, int mode) {
return ::open(pathname, flags, mode);
}
virtual int close(int fd) {
return ::close(fd);
}
public:
void setModule(const private_module_t* m) {
module = m;
}
};
class GpuContextDepsDeviceImpl : public gpu_context_t::Deps {
public:
virtual int ashmem_create_region(const char *name, size_t size) {
return ::ashmem_create_region(name, size);
}
virtual int mapFrameBufferLocked(struct private_module_t* module) {
return ::mapFrameBufferLocked(module);
}
virtual int terminateBuffer(gralloc_module_t const* module,
private_handle_t* hnd) {
return ::terminateBuffer(module, hnd);
}
virtual int close(int fd) {
return ::close(fd);
}
};
static PmemAllocatorDepsDeviceImpl pmemAllocatorDeviceDepsImpl;
static GpuContextDepsDeviceImpl gpuContextDeviceDepsImpl;
/*****************************************************************************/
static SimpleBestFitAllocator pmemAllocMgr;
static PmemUserspaceAllocator pmemAllocator(pmemAllocatorDeviceDepsImpl, pmemAllocMgr,
"/dev/pmem");
static PmemKernelAllocator pmemAdspAllocator(pmemAllocatorDeviceDepsImpl);
/*****************************************************************************/
static struct hw_module_methods_t gralloc_module_methods = {
open: gralloc_device_open
};
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
},
registerBuffer: gralloc_register_buffer,
unregisterBuffer: gralloc_unregister_buffer,
lock: gralloc_lock,
unlock: gralloc_unlock,
perform: gralloc_perform,
},
framebuffer: 0,
fbFormat: 0,
flags: 0,
numBuffers: 0,
bufferMask: 0,
lock: PTHREAD_MUTEX_INITIALIZER,
currentBuffer: 0,
};
/*****************************************************************************/
int gralloc_device_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
int status = -EINVAL;
if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
const private_module_t* m = reinterpret_cast<const private_module_t*>(
module);
pmemAllocatorDeviceDepsImpl.setModule(m);
gpu_context_t *dev;
dev = new gpu_context_t(gpuContextDeviceDepsImpl, pmemAllocator,
pmemAdspAllocator, m);
*device = &dev->common;
status = 0;
} else {
status = fb_device_open(module, name, device);
}
return status;
}

344
libgralloc-qsd8k/gralloc_priv.h Executable file
View File

@ -0,0 +1,344 @@
/*
* 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.
*/
#ifndef GRALLOC_PRIV_H_
#define GRALLOC_PRIV_H_
#include <stdint.h>
#include <limits.h>
#include <sys/cdefs.h>
#include <hardware/gralloc.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <cutils/native_handle.h>
#include <linux/fb.h>
#if defined(__cplusplus) && defined(HDMI_DUAL_DISPLAY)
#include "overlayLib.h"
using namespace overlay;
#endif
enum {
/* gralloc usage bits indicating the type
* of allocation that should be used */
GRALLOC_USAGE_PRIVATE_ADSP_HEAP = GRALLOC_USAGE_PRIVATE_0,
GRALLOC_USAGE_PRIVATE_EBI_HEAP = GRALLOC_USAGE_PRIVATE_1,
GRALLOC_USAGE_PRIVATE_SMI_HEAP = GRALLOC_USAGE_PRIVATE_2,
GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP = GRALLOC_USAGE_PRIVATE_3,
/* Set this for allocating uncached memory (using O_DSYNC)
* cannot be used with the system heap */
GRALLOC_USAGE_PRIVATE_UNCACHED = 0x00010000,
};
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_ADSP "/dev/pmem_adsp"
#define DEVICE_PMEM_SMIPOOL "/dev/pmem_smipool"
/*****************************************************************************/
#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()) {
LOGE("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_YCbCr_422_SP = 0x100, // defined in hardware.h
//HAL_PIXEL_FORMAT_YCrCb_420_SP = 0x101, // defined in hardware.h
HAL_PIXEL_FORMAT_YCbCr_422_P = 0x102,
HAL_PIXEL_FORMAT_YCbCr_420_P = 0x103,
//HAL_PIXEL_FORMAT_YCbCr_422_I = 0x104, // defined in hardware.h
HAL_PIXEL_FORMAT_YCbCr_420_I = 0x105,
HAL_PIXEL_FORMAT_CbYCrY_422_I = 0x106,
HAL_PIXEL_FORMAT_CbYCrY_420_I = 0x107,
HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED = 0x108,
HAL_PIXEL_FORMAT_YCbCr_420_SP = 0x109,
HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO = 0x10A,
HAL_PIXEL_FORMAT_YCrCb_422_SP = 0x10B,
HAL_PIXEL_FORMAT_R_8 = 0x10D,
HAL_PIXEL_FORMAT_RG_88 = 0x10E,
HAL_PIXEL_FORMAT_INTERLACE = 0x180,
};
/* possible formats for 3D content*/
enum {
HAL_NO_3D = 0x0000,
HAL_3D_IN_SIDE_BY_SIDE_L_R = 0x10000,
HAL_3D_IN_TOP_BOTTOM = 0x20000,
HAL_3D_IN_INTERLEAVE = 0x40000,
HAL_3D_IN_SIDE_BY_SIDE_R_L = 0x80000,
HAL_3D_OUT_SIDE_BY_SIDE = 0x1000,
HAL_3D_OUT_TOP_BOTTOM = 0x2000,
HAL_3D_OUT_INTERLEAVE = 0x4000,
HAL_3D_OUT_MONOSCOPIC = 0x8000
};
enum {
BUFFER_TYPE_UI = 0,
BUFFER_TYPE_VIDEO
};
/*****************************************************************************/
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;
bool enableHDMIOutput;
bool exitHDMIUILoop;
float actionsafeWidthRatio;
float actionsafeHeightRatio;
bool hdmiStateChanged;
pthread_mutex_t overlayLock;
pthread_cond_t overlayPost;
#endif
};
/*****************************************************************************/
#ifdef __cplusplus
struct private_handle_t : public native_handle {
#else
struct private_handle_t {
native_handle_t nativeHandle;
#endif
enum {
PRIV_FLAGS_FRAMEBUFFER = 0x00000001,
PRIV_FLAGS_USES_PMEM = 0x00000002,
PRIV_FLAGS_USES_PMEM_ADSP = 0x00000004,
PRIV_FLAGS_USES_ION = 0x00000008,
PRIV_FLAGS_USES_ASHMEM = 0x00000010,
PRIV_FLAGS_NEEDS_FLUSH = 0x00000020,
PRIV_FLAGS_DO_NOT_FLUSH = 0x00000040,
};
enum {
LOCK_STATE_WRITE = 1<<31,
LOCK_STATE_MAPPED = 1<<30,
LOCK_STATE_READ_MASK = 0x3FFFFFFF
};
// file-descriptors
int fd;
// ints
int magic;
int flags;
int size;
int offset;
int bufferType;
// FIXME: the attributes below should be out-of-line
int base;
int lockState;
int writeOwner;
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;
#ifdef __cplusplus
static const int sNumInts = 13;
static const int sNumFds = 1;
static const int sMagic = 'gmsm';
private_handle_t(int fd, int size, int flags, int bufferType, int format, int width, int height) :
fd(fd), magic(sMagic), flags(flags), size(size), offset(0), bufferType(bufferType),
base(0), lockState(0), writeOwner(0), gpuaddr(0), pid(getpid()), format(format), width(width),
height(height)
{
version = sizeof(native_handle);
numInts = sNumInts;
numFds = sNumFds;
}
~private_handle_t() {
magic = 0;
}
bool usesPhysicallyContiguousMemory() {
return (flags & PRIV_FLAGS_USES_PMEM) != 0;
}
static int validate(const native_handle* h) {
const private_handle_t* hnd = (const private_handle_t*)h;
if (!h || h->version != sizeof(native_handle) ||
h->numInts != sNumInts || h->numFds != sNumFds ||
hnd->magic != sMagic)
{
LOGE("invalid gralloc handle (at %p)", h);
return -EINVAL;
}
return 0;
}
static private_handle_t* dynamicCast(const native_handle* in) {
if (validate(in) == 0) {
return (private_handle_t*) in;
}
return NULL;
}
#endif
};
#endif /* GRALLOC_PRIV_H_ */

386
libgralloc-qsd8k/mapper.cpp Executable file
View File

@ -0,0 +1,386 @@
/*
* 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.
*/
#include <limits.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <linux/ashmem.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <cutils/ashmem.h>
#include <hardware/hardware.h>
#include <hardware/gralloc.h>
#include <linux/android_pmem.h>
#include "gralloc_priv.h"
#include "gr.h"
// we need this for now because pmem cannot mmap at an offset
#define PMEM_HACK 1
/* desktop Linux needs a little help with gettid() */
#if defined(ARCH_X86) && !defined(HAVE_ANDROID_OS)
#define __KERNEL__
# include <linux/unistd.h>
pid_t gettid() { return syscall(__NR_gettid);}
#undef __KERNEL__
#endif
/*****************************************************************************/
static int gralloc_map(gralloc_module_t const* module,
buffer_handle_t handle,
void** vaddr)
{
private_handle_t* hnd = (private_handle_t*)handle;
void *mappedAddress;
if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
size_t size = hnd->size;
#if PMEM_HACK
size += hnd->offset;
#endif
if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_ASHMEM) {
mappedAddress = mmap(0, size,
PROT_READ|PROT_WRITE, MAP_SHARED | MAP_POPULATE, hnd->fd, 0);
} else {
mappedAddress = mmap(0, size,
PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0);
}
if (mappedAddress == MAP_FAILED) {
LOGE("Could not mmap handle %p, fd=%d (%s)",
handle, hnd->fd, strerror(errno));
hnd->base = 0;
return -errno;
}
hnd->base = intptr_t(mappedAddress) + hnd->offset;
//LOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p",
// hnd->fd, hnd->offset, hnd->size, mappedAddress);
}
*vaddr = (void*)hnd->base;
return 0;
}
static int gralloc_unmap(gralloc_module_t const* module,
buffer_handle_t handle)
{
private_handle_t* hnd = (private_handle_t*)handle;
if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
void* base = (void*)hnd->base;
size_t size = hnd->size;
#if PMEM_HACK
base = (void*)(intptr_t(base) - hnd->offset);
size += hnd->offset;
#endif
//LOGD("unmapping from %p, size=%d", base, size);
if (munmap(base, size) < 0) {
LOGE("Could not unmap %s", strerror(errno));
}
}
hnd->base = 0;
return 0;
}
/*****************************************************************************/
static pthread_mutex_t sMapLock = PTHREAD_MUTEX_INITIALIZER;
/*****************************************************************************/
int gralloc_register_buffer(gralloc_module_t const* module,
buffer_handle_t handle)
{
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
// In this implementation, we don't need to do anything here
/* NOTE: we need to initialize the buffer as not mapped/not locked
* because it shouldn't when this function is called the first time
* in a new process. Ideally these flags shouldn't be part of the
* handle, but instead maintained in the kernel or at least
* out-of-line
*/
// if this handle was created in this process, then we keep it as is.
private_handle_t* hnd = (private_handle_t*)handle;
if (hnd->pid != getpid()) {
hnd->base = 0;
hnd->lockState = 0;
hnd->writeOwner = 0;
}
return 0;
}
int gralloc_unregister_buffer(gralloc_module_t const* module,
buffer_handle_t handle)
{
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
/*
* If the buffer has been mapped during a lock operation, it's time
* to un-map it. It's an error to be here with a locked buffer.
* NOTE: the framebuffer is handled differently and is never unmapped.
*/
private_handle_t* hnd = (private_handle_t*)handle;
LOGE_IF(hnd->lockState & private_handle_t::LOCK_STATE_READ_MASK,
"[unregister] handle %p still locked (state=%08x)",
hnd, hnd->lockState);
// never unmap buffers that were created in this process
if (hnd->pid != getpid()) {
if (hnd->lockState & private_handle_t::LOCK_STATE_MAPPED) {
gralloc_unmap(module, handle);
}
hnd->base = 0;
hnd->lockState = 0;
hnd->writeOwner = 0;
}
return 0;
}
int terminateBuffer(gralloc_module_t const* module,
private_handle_t* hnd)
{
/*
* If the buffer has been mapped during a lock operation, it's time
* to un-map it. It's an error to be here with a locked buffer.
*/
LOGE_IF(hnd->lockState & private_handle_t::LOCK_STATE_READ_MASK,
"[terminate] handle %p still locked (state=%08x)",
hnd, hnd->lockState);
if (hnd->lockState & private_handle_t::LOCK_STATE_MAPPED) {
// this buffer was mapped, unmap it now
if (hnd->flags & (private_handle_t::PRIV_FLAGS_USES_PMEM |
private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP |
private_handle_t::PRIV_FLAGS_USES_ASHMEM)) {
if (hnd->pid != getpid()) {
// ... unless it's a "master" pmem buffer, that is a buffer
// mapped in the process it's been allocated.
// (see gralloc_alloc_buffer())
gralloc_unmap(module, hnd);
}
} else {
LOGE("terminateBuffer: unmapping a non pmem/ashmem buffer flags = 0x%x", hnd->flags);
gralloc_unmap(module, hnd);
}
}
return 0;
}
int gralloc_lock(gralloc_module_t const* module,
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;
int err = 0;
private_handle_t* hnd = (private_handle_t*)handle;
int32_t current_value, new_value;
int retry;
do {
current_value = hnd->lockState;
new_value = current_value;
if (current_value & private_handle_t::LOCK_STATE_WRITE) {
// already locked for write
LOGE("handle %p already locked for write", handle);
return -EBUSY;
} else if (current_value & private_handle_t::LOCK_STATE_READ_MASK) {
// already locked for read
if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) {
LOGE("handle %p already locked for read", handle);
return -EBUSY;
} else {
// this is not an error
//LOGD("%p already locked for read... count = %d",
// handle, (current_value & ~(1<<31)));
}
}
// not currently locked
if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) {
// locking for write
new_value |= private_handle_t::LOCK_STATE_WRITE;
}
new_value++;
retry = android_atomic_cmpxchg(current_value, new_value,
(volatile int32_t*)&hnd->lockState);
} while (retry);
if (new_value & private_handle_t::LOCK_STATE_WRITE) {
// locking for write, store the tid
hnd->writeOwner = gettid();
}
// if requesting sw write for non-framebuffer handles, flag for
// flushing at unlock
if ((usage & GRALLOC_USAGE_SW_WRITE_MASK) &&
!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
hnd->flags |= private_handle_t::PRIV_FLAGS_NEEDS_FLUSH;
}
if (usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) {
if (!(current_value & private_handle_t::LOCK_STATE_MAPPED)) {
// we need to map for real
pthread_mutex_t* const lock = &sMapLock;
pthread_mutex_lock(lock);
if (!(hnd->lockState & private_handle_t::LOCK_STATE_MAPPED)) {
err = gralloc_map(module, handle, vaddr);
if (err == 0) {
android_atomic_or(private_handle_t::LOCK_STATE_MAPPED,
(volatile int32_t*)&(hnd->lockState));
}
}
pthread_mutex_unlock(lock);
}
*vaddr = (void*)hnd->base;
}
return err;
}
int gralloc_unlock(gralloc_module_t const* module,
buffer_handle_t handle)
{
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
private_handle_t* hnd = (private_handle_t*)handle;
int32_t current_value, new_value;
if (hnd->flags & private_handle_t::PRIV_FLAGS_NEEDS_FLUSH) {
int err;
if (hnd->flags & (private_handle_t::PRIV_FLAGS_USES_PMEM |
private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP)) {
struct pmem_addr pmem_addr;
pmem_addr.vaddr = hnd->base;
pmem_addr.offset = hnd->offset;
pmem_addr.length = hnd->size;
err = ioctl( hnd->fd, PMEM_CLEAN_CACHES, &pmem_addr);
} else if ((hnd->flags & private_handle_t::PRIV_FLAGS_USES_ASHMEM)) {
unsigned long addr = hnd->base + hnd->offset;
err = ioctl(hnd->fd, ASHMEM_CACHE_FLUSH_RANGE, NULL);
}
LOGE_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->flags &= ~private_handle_t::PRIV_FLAGS_NEEDS_FLUSH;
}
do {
current_value = hnd->lockState;
new_value = current_value;
if (current_value & private_handle_t::LOCK_STATE_WRITE) {
// locked for write
if (hnd->writeOwner == gettid()) {
hnd->writeOwner = 0;
new_value &= ~private_handle_t::LOCK_STATE_WRITE;
}
}
if ((new_value & private_handle_t::LOCK_STATE_READ_MASK) == 0) {
LOGE("handle %p not locked", handle);
return -EINVAL;
}
new_value--;
} while (android_atomic_cmpxchg(current_value, new_value,
(volatile int32_t*)&hnd->lockState));
return 0;
}
/*****************************************************************************/
int gralloc_perform(struct gralloc_module_t const* module,
int operation, ... )
{
int res = -EINVAL;
va_list args;
va_start(args, operation);
switch (operation) {
case GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER: {
int fd = va_arg(args, int);
size_t size = va_arg(args, size_t);
size_t offset = va_arg(args, size_t);
void* base = va_arg(args, void*);
// validate that it's indeed a pmem buffer
pmem_region region;
if (ioctl(fd, PMEM_GET_SIZE, &region) < 0) {
break;
}
native_handle_t** handle = va_arg(args, native_handle_t**);
private_handle_t* hnd = (private_handle_t*)native_handle_create(
private_handle_t::sNumFds, private_handle_t::sNumInts);
hnd->magic = private_handle_t::sMagic;
hnd->fd = fd;
hnd->flags = private_handle_t::PRIV_FLAGS_USES_PMEM;
hnd->size = size;
hnd->offset = offset;
hnd->base = intptr_t(base) + offset;
hnd->lockState = private_handle_t::LOCK_STATE_MAPPED;
hnd->gpuaddr = 0;
*handle = (native_handle_t *)hnd;
res = 0;
break;
}
case GRALLOC_MODULE_PERFORM_UPDATE_BUFFER_HANDLE: {
native_handle_t* handle = va_arg(args, native_handle_t*);
int w = va_arg(args, int);
int h = va_arg(args, int);
int f = va_arg(args, int);
private_handle_t* hnd = (private_handle_t*)handle;
hnd->width = w;
hnd->height = h;
if (hnd->format != f) {
hnd->format = f;
}
break;
}
default:
break;
}
va_end(args);
return res;
}

360
libgralloc-qsd8k/pmemalloc.cpp Executable file
View File

@ -0,0 +1,360 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//#define LOG_NDEBUG 0
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <cutils/log.h>
#include <cutils/ashmem.h>
#include "gralloc_priv.h"
#include "pmemalloc.h"
#define BEGIN_FUNC LOGV("%s begin", __PRETTY_FUNCTION__)
#define END_FUNC LOGV("%s end", __PRETTY_FUNCTION__)
static int get_open_flags(int usage) {
int openFlags = O_RDWR | O_SYNC;
uint32_t uread = usage & GRALLOC_USAGE_SW_READ_MASK;
uint32_t uwrite = usage & GRALLOC_USAGE_SW_WRITE_MASK;
if (uread == GRALLOC_USAGE_SW_READ_OFTEN ||
uwrite == GRALLOC_USAGE_SW_WRITE_OFTEN) {
openFlags &= ~O_SYNC;
}
return openFlags;
}
PmemAllocator::~PmemAllocator()
{
BEGIN_FUNC;
END_FUNC;
}
PmemUserspaceAllocator::PmemUserspaceAllocator(Deps& deps, Deps::Allocator& allocator, const char* pmemdev):
deps(deps),
allocator(allocator),
pmemdev(pmemdev),
master_fd(MASTER_FD_INIT)
{
BEGIN_FUNC;
pthread_mutex_init(&lock, NULL);
END_FUNC;
}
PmemUserspaceAllocator::~PmemUserspaceAllocator()
{
BEGIN_FUNC;
END_FUNC;
}
void* PmemUserspaceAllocator::get_base_address() {
BEGIN_FUNC;
END_FUNC;
return master_base;
}
int PmemUserspaceAllocator::init_pmem_area_locked()
{
BEGIN_FUNC;
int err = 0;
int fd = deps.open(pmemdev, O_RDWR, 0);
if (fd >= 0) {
size_t size = 0;
err = deps.getPmemTotalSize(fd, &size);
if (err < 0) {
LOGE("%s: PMEM_GET_TOTAL_SIZE failed (%d), limp mode", pmemdev,
err);
size = 8<<20; // 8 MiB
}
allocator.setSize(size);
void* base = deps.mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd,
0);
if (base == MAP_FAILED) {
LOGE("%s: failed to map pmem master fd: %s", pmemdev,
strerror(deps.getErrno()));
err = -deps.getErrno();
base = 0;
deps.close(fd);
fd = -1;
} else {
master_fd = fd;
master_base = base;
}
} else {
LOGE("%s: failed to open pmem device: %s", pmemdev,
strerror(deps.getErrno()));
err = -deps.getErrno();
}
END_FUNC;
return err;
}
int PmemUserspaceAllocator::init_pmem_area()
{
BEGIN_FUNC;
pthread_mutex_lock(&lock);
int err = master_fd;
if (err == MASTER_FD_INIT) {
// first time, try to initialize pmem
err = init_pmem_area_locked();
if (err) {
LOGE("%s: failed to initialize pmem area", pmemdev);
master_fd = err;
}
} else if (err < 0) {
// pmem couldn't be initialized, never use it
} else {
// pmem OK
err = 0;
}
pthread_mutex_unlock(&lock);
END_FUNC;
return err;
}
int PmemUserspaceAllocator::alloc_pmem_buffer(size_t size, int usage,
void** pBase, int* pOffset, int* pFd, int format)
{
BEGIN_FUNC;
int err = init_pmem_area();
if (err == 0) {
void* base = master_base;
int offset = allocator.allocate(size);
if (offset < 0) {
// no more pmem memory
LOGE("%s: no more pmem available", pmemdev);
err = -ENOMEM;
} else {
int openFlags = get_open_flags(usage);
//LOGD("%s: allocating pmem at offset 0x%p", pmemdev, offset);
// now create the "sub-heap"
int fd = deps.open(pmemdev, openFlags, 0);
err = fd < 0 ? fd : 0;
// and connect to it
if (err == 0)
err = deps.connectPmem(fd, master_fd);
// and make it available to the client process
if (err == 0)
err = deps.mapPmem(fd, offset, size);
if (err < 0) {
LOGE("%s: failed to initialize pmem sub-heap: %d", pmemdev,
err);
err = -deps.getErrno();
deps.close(fd);
allocator.deallocate(offset);
fd = -1;
} else {
LOGV("%s: mapped fd %d at offset %d, size %d", pmemdev, fd, offset, size);
memset((char*)base + offset, 0, size);
//Clean cache before flushing to ensure pmem is properly flushed
err = deps.cleanPmem(fd, (unsigned long) base + offset, offset, size);
if (err < 0) {
LOGE("cleanPmem failed: (%s)", strerror(deps.getErrno()));
}
#ifdef HOST
cacheflush(intptr_t(base) + offset, intptr_t(base) + offset + size, 0);
#endif
*pBase = base;
*pOffset = offset;
*pFd = fd;
}
//LOGD_IF(!err, "%s: allocating pmem size=%d, offset=%d", pmemdev, size, offset);
}
}
END_FUNC;
return err;
}
int PmemUserspaceAllocator::free_pmem_buffer(size_t size, void* base, int offset, int fd)
{
BEGIN_FUNC;
int err = 0;
if (fd >= 0) {
int err = deps.unmapPmem(fd, offset, size);
LOGE_IF(err<0, "PMEM_UNMAP failed (%s), fd=%d, sub.offset=%u, "
"sub.size=%u", strerror(deps.getErrno()), 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
// surfaces, which would be a security breach.
allocator.deallocate(offset);
}
}
END_FUNC;
return err;
}
PmemUserspaceAllocator::Deps::Allocator::~Allocator()
{
BEGIN_FUNC;
END_FUNC;
}
PmemUserspaceAllocator::Deps::~Deps()
{
BEGIN_FUNC;
END_FUNC;
}
PmemKernelAllocator::PmemKernelAllocator(Deps& deps):
deps(deps)
{
BEGIN_FUNC;
END_FUNC;
}
PmemKernelAllocator::~PmemKernelAllocator()
{
BEGIN_FUNC;
END_FUNC;
}
void* PmemKernelAllocator::get_base_address() {
BEGIN_FUNC;
END_FUNC;
return 0;
}
static unsigned clp2(unsigned x) {
x = x - 1;
x = x | (x >> 1);
x = x | (x >> 2);
x = x | (x >> 4);
x = x | (x >> 8);
x = x | (x >>16);
return x + 1;
}
int PmemKernelAllocator::alloc_pmem_buffer(size_t size, int usage,
void** pBase,int* pOffset, int* pFd, int format)
{
BEGIN_FUNC;
*pBase = 0;
*pOffset = 0;
*pFd = -1;
int err, offset = 0;
int openFlags = get_open_flags(usage);
const char *device;
if (usage & GRALLOC_USAGE_PRIVATE_ADSP_HEAP) {
device = DEVICE_PMEM_ADSP;
} else if (usage & GRALLOC_USAGE_PRIVATE_SMI_HEAP) {
device = DEVICE_PMEM_SMIPOOL;
} else if ((usage & GRALLOC_USAGE_EXTERNAL_DISP) ||
(usage & GRALLOC_USAGE_PROTECTED)) {
int tempFd = deps.open(DEVICE_PMEM_SMIPOOL, openFlags, 0);
if (tempFd < 0) {
device = DEVICE_PMEM_ADSP;
} else {
close(tempFd);
device = DEVICE_PMEM_SMIPOOL;
}
} else {
LOGE("Invalid device");
return -EINVAL;
}
int fd = deps.open(device, openFlags, 0);
if (fd < 0) {
err = -deps.getErrno();
END_FUNC;
LOGE("Error opening %s", device);
return err;
}
// The size should already be page aligned, now round it up to a power of 2.
//size = clp2(size);
if (format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED) {
// Tile format buffers need physical alignment to 8K
err = deps.alignPmem(fd, size, 8192);
if (err < 0) {
LOGE("alignPmem failed");
}
}
void* base = deps.mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (base == MAP_FAILED) {
LOGE("%s: failed to map pmem fd: %s", device,
strerror(deps.getErrno()));
err = -deps.getErrno();
deps.close(fd);
END_FUNC;
return err;
}
memset(base, 0, size);
*pBase = base;
*pOffset = 0;
*pFd = fd;
END_FUNC;
return 0;
}
int PmemKernelAllocator::free_pmem_buffer(size_t size, void* base, int offset, int fd)
{
BEGIN_FUNC;
// The size should already be page aligned, now round it up to a power of 2
// like we did when allocating.
//size = clp2(size);
int err = deps.munmap(base, size);
if (err < 0) {
err = deps.getErrno();
LOGW("error unmapping pmem fd: %s", strerror(err));
return -err;
}
END_FUNC;
return 0;
}
PmemKernelAllocator::Deps::~Deps()
{
BEGIN_FUNC;
END_FUNC;
}

161
libgralloc-qsd8k/pmemalloc.h Executable file
View File

@ -0,0 +1,161 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef GRALLOC_QSD8K_PMEMALLOC_H
#define GRALLOC_QSD8K_PMEMALLOC_H
#include <limits.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
/**
* An interface to the PMEM allocators.
*/
class PmemAllocator {
public:
virtual ~PmemAllocator();
// Only valid after init_pmem_area() has completed successfully.
virtual void* get_base_address() = 0;
virtual int alloc_pmem_buffer(size_t size, int usage, void** pBase,
int* pOffset, int* pFd, int format) = 0;
virtual int free_pmem_buffer(size_t size, void* base, int offset, int fd) = 0;
};
/**
* A PMEM allocator that allocates the entire pmem memory from the kernel and
* then uses a user-space allocator to suballocate from that. This requires
* that the PMEM device driver have kernel allocation disabled.
*/
class PmemUserspaceAllocator: public PmemAllocator {
public:
class Deps {
public:
class Allocator {
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 ~Deps();
// pmem
virtual size_t getPmemTotalSize(int fd, size_t* size) = 0;
virtual int connectPmem(int fd, int master_fd) = 0;
virtual int mapPmem(int fd, int offset, size_t size) = 0;
virtual int unmapPmem(int fd, int offset, size_t size) = 0;
virtual int cleanPmem(int fd, unsigned long base, int offset, size_t size) = 0;
// C99
virtual int getErrno() = 0;
// POSIX
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
off_t offset) = 0;
virtual int open(const char* pathname, int flags, int mode) = 0;
virtual int close(int fd) = 0;
};
PmemUserspaceAllocator(Deps& deps, Deps::Allocator& allocator, const char* pmemdev);
virtual ~PmemUserspaceAllocator();
// Only valid after init_pmem_area() has completed successfully.
virtual void* get_base_address();
virtual int init_pmem_area_locked();
virtual int init_pmem_area();
virtual int alloc_pmem_buffer(size_t size, int usage, void** pBase,
int* pOffset, int* pFd, int format);
virtual int free_pmem_buffer(size_t size, void* base, int offset, int fd);
#ifndef ANDROID_OS
// DO NOT USE: For testing purposes only.
void set_master_values(int fd, void* base) {
master_fd = fd;
master_base = base;
}
#endif // ANDROID_OS
private:
enum {
MASTER_FD_INIT = -1,
};
Deps& deps;
Deps::Allocator& allocator;
pthread_mutex_t lock;
const char* pmemdev;
int master_fd;
void* master_base;
};
/**
* A PMEM allocator that allocates each individual allocation from the kernel
* (using the kernel's allocator). This requires the kernel driver for the
* particular PMEM device being allocated from to support kernel allocation.
*/
class PmemKernelAllocator: public PmemAllocator {
public:
class Deps {
public:
virtual ~Deps();
// C99
virtual int getErrno() = 0;
// POSIX
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
off_t offset) = 0;
virtual int munmap(void* start, size_t length) = 0;
virtual int open(const char* pathname, int flags, int mode) = 0;
virtual int close(int fd) = 0;
virtual int alignPmem(int fd, size_t size, int align) = 0;
};
PmemKernelAllocator(Deps& deps);
virtual ~PmemKernelAllocator();
// Only valid after init_pmem_area() has completed successfully.
virtual void* get_base_address();
virtual int alloc_pmem_buffer(size_t size, int usage, void** pBase,
int* pOffset, int* pFd, int format);
virtual int free_pmem_buffer(size_t size, void* base, int offset, int fd);
private:
Deps& deps;
};
#endif // GRALLOC_QSD8K_PMEMALLOC_H

View File

@ -0,0 +1,55 @@
# 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)
# you can use EXTRA_CFLAGS to indicate additional CFLAGS to use
# in the build. The variables will be cleaned on exit
#
#
libgralloc_test_includes:= \
bionic/libstdc++/include \
external/astl/include \
external/gtest/include \
$(LOCAL_PATH)/..
libgralloc_test_static_libs := \
libgralloc_qsd8k_host \
libgtest_main_host \
libgtest_host \
libastl_host \
liblog
define host-test
$(foreach file,$(1), \
$(eval include $(CLEAR_VARS)) \
$(eval LOCAL_CPP_EXTENSION := .cpp) \
$(eval LOCAL_SRC_FILES := $(file)) \
$(eval LOCAL_C_INCLUDES := $(libgralloc_test_includes)) \
$(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
$(eval LOCAL_CFLAGS += $(EXTRA_CFLAGS)) \
$(eval LOCAL_LDLIBS += $(EXTRA_LDLIBS)) \
$(eval LOCAL_STATIC_LIBRARIES := $(libgralloc_test_static_libs)) \
$(eval LOCAL_MODULE_TAGS := eng tests) \
$(eval include $(BUILD_HOST_EXECUTABLE)) \
) \
$(eval EXTRA_CFLAGS :=) \
$(eval EXTRA_LDLIBS :=)
endef
TEST_SRC_FILES := \
pmemalloc_test.cpp
$(call host-test, $(TEST_SRC_FILES))

View File

@ -0,0 +1,601 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "pmemalloc.h"
class DepsStub : public PmemUserspaceAllocator::Deps, public PmemKernelAllocator::Deps {
public:
virtual size_t getPmemTotalSize(int fd, size_t* size) {
return 0;
}
virtual int connectPmem(int fd, int master_fd) {
return 0;
}
virtual int mapPmem(int fd, int offset, size_t size) {
return 0;
}
virtual int unmapPmem(int fd, int offset, size_t size) {
return 0;
}
virtual int getErrno() {
return 0;
}
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
off_t offset) {
return 0;
}
virtual int munmap(void* start, size_t length) {
return 0;
}
virtual int open(const char* pathname, int flags, int mode) {
return 0;
}
virtual int close(int fd) {
return 0;
}
};
/******************************************************************************/
class AllocatorStub : public PmemUserspaceAllocator::Deps::Allocator {
virtual ssize_t setSize(size_t size) {
return 0;
}
virtual size_t size() const {
return 0;
}
virtual ssize_t allocate(size_t size, uint32_t flags = 0) {
return 0;
}
virtual ssize_t deallocate(size_t offset) {
return 0;
}
};
/******************************************************************************/
static const char* fakePmemDev = "/foo/bar";
/******************************************************************************/
struct Deps_InitPmemAreaLockedWithSuccessfulCompletion : public DepsStub {
virtual int open(const char* pathname, int flags, int mode) {
EXPECT_EQ(fakePmemDev, pathname);
EXPECT_EQ(O_RDWR, flags);
EXPECT_EQ(0, mode);
return 1234;
}
virtual size_t getPmemTotalSize(int fd, size_t* size) {
EXPECT_EQ(1234, fd);
*size = 16 << 20;
return 0;
}
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
off_t offset) {
EXPECT_EQ(1234, fd);
return (void*)0x87654321;
}
};
struct Allocator_InitPmemAreaLockedWithSuccessfulCompletion : public AllocatorStub {
virtual ssize_t setSize(size_t size) {
EXPECT_EQ(size_t(16 << 20), size);
return 0;
}
};
TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWithSuccessfulCompletion) {
Deps_InitPmemAreaLockedWithSuccessfulCompletion depsMock;
Allocator_InitPmemAreaLockedWithSuccessfulCompletion allocMock;
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
int result = pma.init_pmem_area_locked();
ASSERT_EQ(0, result);
}
/******************************************************************************/
struct Deps_InitPmemAreaLockedWithEnomemOnMmap : public DepsStub {
virtual int open(const char* pathname, int flags, int mode) {
EXPECT_EQ(fakePmemDev, pathname);
EXPECT_EQ(O_RDWR, flags);
EXPECT_EQ(0, mode);
return 1234;
}
virtual size_t getPmemTotalSize(int fd, size_t* size) {
EXPECT_EQ(1234, fd);
*size = 16 << 20;
return 0;
}
virtual int getErrno() {
return ENOMEM;
}
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
off_t offset) {
return (void*)MAP_FAILED;
}
};
struct Allocator_InitPmemAreaLockedWithEnomemOnMmap : public AllocatorStub {
virtual ssize_t setSize(size_t size) {
EXPECT_EQ(size_t(16 << 20), size);
return 0;
}
};
TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWthEnomemOnMmap) {
Deps_InitPmemAreaLockedWithEnomemOnMmap depsMock;
Allocator_InitPmemAreaLockedWithEnomemOnMmap allocMock;
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
int result = pma.init_pmem_area_locked();
ASSERT_EQ(-ENOMEM, result);
}
/******************************************************************************/
struct Deps_InitPmemAreaLockedWithEaccesOnGetPmemTotalSize : public DepsStub {
virtual int open(const char* pathname, int flags, int mode) {
EXPECT_EQ(fakePmemDev, pathname);
EXPECT_EQ(O_RDWR, flags);
EXPECT_EQ(0, mode);
return 1234;
}
virtual size_t getPmemTotalSize(int fd, size_t* size) {
EXPECT_EQ(1234, fd);
return -EACCES;
}
};
TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWthEaccesOnGetPmemTotalSize) {
Deps_InitPmemAreaLockedWithEaccesOnGetPmemTotalSize depsMock;
AllocatorStub allocStub;
PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
int result = pma.init_pmem_area_locked();
ASSERT_EQ(-EACCES, result);
}
/******************************************************************************/
struct Deps_InitPmemAreaLockedWithEaccesOnOpen : public DepsStub {
virtual int getErrno() {
return EACCES;
}
virtual int open(const char* pathname, int flags, int mode) {
EXPECT_EQ(fakePmemDev, pathname);
EXPECT_EQ(O_RDWR, flags);
EXPECT_EQ(0, mode);
return -1;
}
};
TEST(test_pmem_userspace_allocator, testInitPmemAreaLockedWithEaccesOnOpenMaster) {
Deps_InitPmemAreaLockedWithEaccesOnOpen depsMock;
AllocatorStub allocStub;
PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
int result = pma.init_pmem_area_locked();
ASSERT_EQ(-EACCES, result);
}
/******************************************************************************/
typedef Deps_InitPmemAreaLockedWithSuccessfulCompletion Deps_InitPmemAreaWithSuccessfulInitialCompletion;
TEST(test_pmem_userspace_allocator, testInitPmemAreaWithSuccessfulInitialCompletion) {
Deps_InitPmemAreaWithSuccessfulInitialCompletion depsMock;
AllocatorStub allocStub;
PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
int result = pma.init_pmem_area();
ASSERT_EQ(0, result);
}
/******************************************************************************/
typedef Deps_InitPmemAreaLockedWithEaccesOnOpen Deps_InitPmemAreaWithEaccesOnInitLocked;
TEST(test_pmem_userspace_allocator, testInitPmemAreaWithEaccesOnInitLocked) {
Deps_InitPmemAreaWithEaccesOnInitLocked depsMock;
AllocatorStub allocStub;
PmemUserspaceAllocator pma(depsMock, allocStub, fakePmemDev);
int result = pma.init_pmem_area();
ASSERT_EQ(-EACCES, result);
}
/******************************************************************************/
TEST(test_pmem_userspace_allocator, testInitPmemAreaAfterSuccessfulInitialCompletion) {
DepsStub depsStub;
AllocatorStub allocStub;
PmemUserspaceAllocator pma(depsStub, allocStub, fakePmemDev);
pma.set_master_values(1234, 0); // Indicate that the pma has been successfully init'd
int result = pma.init_pmem_area();
ASSERT_EQ(0, result);
//XXX JMG: Add this back in maybe? ASSERT_EQ(1234, pmi.master); // Make sure the master fd wasn't changed
}
/******************************************************************************/
TEST(test_pmem_userspace_allocator, testInitPmemAreaAfterFailedInit) {
DepsStub depsStub;
AllocatorStub allocStub;
PmemUserspaceAllocator pma(depsStub, allocStub, fakePmemDev);
pma.set_master_values(-EACCES, 0); // Indicate that the pma has failed init
int result = pma.init_pmem_area();
ASSERT_EQ(-EACCES, result);
}
/******************************************************************************/
struct Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags : public DepsStub {
virtual int open(const char* pathname, int flags, int mode) {
EXPECT_EQ(fakePmemDev, pathname);
EXPECT_EQ(O_RDWR, flags & O_RDWR);
EXPECT_EQ(0, mode);
return 5678;
}
virtual int connectPmem(int fd, int master_fd) {
EXPECT_EQ(5678, fd);
EXPECT_EQ(1234, master_fd);
return 0;
}
virtual int mapPmem(int fd, int offset, size_t size) {
EXPECT_EQ(5678, fd);
EXPECT_EQ(0x300, offset);
EXPECT_EQ(size_t(0x100), size);
return 0;
}
};
struct Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags : public AllocatorStub {
virtual ssize_t allocate(size_t size, uint32_t flags = 0) {
EXPECT_EQ(size_t(0x100), size);
EXPECT_EQ(uint32_t(0x0), flags);
return 0x300;
}
};
TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithNoFlags) {
Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags depsMock;
Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags allocMock;
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
void* base = 0;
int offset = -9182, fd = -9182;
int size = 0x100;
int flags = 0;
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
ASSERT_EQ(0, result);
ASSERT_EQ(0x300, offset);
ASSERT_EQ(5678, fd);
for (int i = 0x300; i < 0x400; ++i) {
ASSERT_EQ(uint8_t(0), buf[i]);
}
}
/******************************************************************************/
typedef Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags Deps_InitPmemAreaLockedWithSuccessfulCompletionWithAllFlags;
typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithSuccessfulCompletionWithAllFlags;
TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithAllFlags) {
Deps_InitPmemAreaLockedWithSuccessfulCompletionWithAllFlags depsMock;
Allocator_AllocPmemBufferWithSuccessfulCompletionWithAllFlags allocMock;
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
void* base = 0;
int offset = -9182, fd = -9182;
int size = 0x100;
int flags = ~0;
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
ASSERT_EQ(0, result);
ASSERT_EQ(0x300, offset);
ASSERT_EQ(5678, fd);
for (int i = 0x300; i < 0x400; ++i) {
ASSERT_EQ(0, buf[i]);
}
}
/******************************************************************************/
struct Deps_InitPmemAreaLockedWithEnodevOnOpen : public Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags {
virtual int getErrno() {
return ENODEV;
}
virtual int open(const char* pathname, int flags, int mode) {
EXPECT_EQ(fakePmemDev, pathname);
EXPECT_EQ(O_RDWR, flags & O_RDWR);
EXPECT_EQ(0, mode);
return -1;
}
};
typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithEnodevOnOpen;
TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithEnodevOnOpen) {
Deps_InitPmemAreaLockedWithEnodevOnOpen depsMock;
Allocator_AllocPmemBufferWithEnodevOnOpen allocMock;
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
void* base = 0;
int offset = -9182, fd = -9182;
int size = 0x100;
int flags = ~0;
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
ASSERT_EQ(-ENODEV, result);
}
/******************************************************************************/
struct Deps_InitPmemAreaLockedWithEnomemOnConnectPmem : public Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags {
virtual int getErrno() {
return ENOMEM;
}
virtual int connectPmem(int fd, int master_fd) {
EXPECT_EQ(5678, fd);
EXPECT_EQ(1234, master_fd);
return -1;
}
};
typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithEnomemOnConnectPmem;
TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithSuccessfulCompletionWithEnomemOnConnectPmem) {
Deps_InitPmemAreaLockedWithEnomemOnConnectPmem depsMock;
Allocator_AllocPmemBufferWithEnomemOnConnectPmem allocMock;
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
void* base = 0;
int offset = -9182, fd = -9182;
int size = 0x100;
int flags = ~0;
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
ASSERT_EQ(-ENOMEM, result);
}
/******************************************************************************/
struct Deps_InitPmemAreaLockedWithEnomemOnMapPmem : public Deps_InitPmemAreaLockedWithSuccessfulCompletionWithNoFlags {
virtual int getErrno() {
return ENOMEM;
}
virtual int mapPmem(int fd, int offset, size_t size) {
EXPECT_EQ(5678, fd);
EXPECT_EQ(0x300, offset);
EXPECT_EQ(size_t(0x100), size);
return -1;
}
};
typedef Allocator_AllocPmemBufferWithSuccessfulCompletionWithNoFlags Allocator_AllocPmemBufferWithEnomemOnMapPmem;
TEST(test_pmem_userspace_allocator, testAllocPmemBufferWithEnomemOnMapPmem) {
Deps_InitPmemAreaLockedWithEnomemOnMapPmem depsMock;
Allocator_AllocPmemBufferWithEnomemOnMapPmem allocMock;
PmemUserspaceAllocator pma(depsMock, allocMock, fakePmemDev);
uint8_t buf[0x300 + 0x100]; // Create a buffer to get memzero'd
pma.set_master_values(1234, buf); // Indicate that the pma has been successfully init'd
void* base = 0;
int offset = -9182, fd = -9182;
int size = 0x100;
int flags = ~0;
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
ASSERT_EQ(-ENOMEM, result);
}
/******************************************************************************/
struct Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags : public DepsStub {
void* mmapResult;
Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags(void* mmapResult) :
mmapResult(mmapResult) {}
virtual int open(const char* pathname, int flags, int mode) {
EXPECT_EQ(fakePmemDev, pathname);
EXPECT_EQ(O_RDWR, flags & O_RDWR);
EXPECT_EQ(0, mode);
return 5678;
}
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
off_t offset) {
EXPECT_EQ(5678, fd);
return mmapResult;
}
};
TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithSuccessfulCompletionWithNoFlags) {
uint8_t buf[0x100]; // Create a buffer to get memzero'd
Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags depsMock(buf);
PmemKernelAllocator pma(depsMock, fakePmemDev);
void* base = 0;
int offset = -9182, fd = -9182;
int size = 0x100;
int flags = 0;
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
ASSERT_EQ(0, result);
ASSERT_EQ(buf, base);
ASSERT_EQ(0, offset);
ASSERT_EQ(5678, fd);
for (int i = 0; i < 0x100; ++i) {
ASSERT_EQ(0, buf[i]);
}
}
/******************************************************************************/
typedef Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithNoFlags Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithAllFlags;
TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithSuccessfulCompletionWithAllFlags) {
uint8_t buf[0x100]; // Create a buffer to get memzero'd
Deps_KernelAllocPmemBufferWithSuccessfulCompletionWithAllFlags depsMock(buf);
PmemKernelAllocator pma(depsMock, fakePmemDev);
void* base = 0;
int offset = -9182, fd = -9182;
int size = 0x100;
int flags = ~0;
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
ASSERT_EQ(0, result);
ASSERT_EQ(buf, base);
ASSERT_EQ(0, offset);
ASSERT_EQ(5678, fd);
for (int i = 0; i < 0x100; ++i) {
ASSERT_EQ(0, buf[i]);
}
}
/******************************************************************************/
struct Deps_KernelAllocPmemBufferWithEpermOnOpen : public DepsStub {
virtual int getErrno() {
return EPERM;
}
virtual int open(const char* pathname, int flags, int mode) {
EXPECT_EQ(fakePmemDev, pathname);
EXPECT_EQ(O_RDWR, flags & O_RDWR);
EXPECT_EQ(0, mode);
return -1;
}
};
TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithEpermOnOpen) {
Deps_KernelAllocPmemBufferWithEpermOnOpen depsMock;
PmemKernelAllocator pma(depsMock, fakePmemDev);
void* base = 0;
int offset = -9182, fd = -9182;
int size = 0x100;
int flags = ~0;
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
ASSERT_EQ(-EPERM, result);
ASSERT_EQ(0, base);
ASSERT_EQ(0, offset);
ASSERT_EQ(-1, fd);
}
/******************************************************************************/
struct Deps_KernelAllocPmemBufferWithEnomemOnMmap : DepsStub {
virtual int open(const char* pathname, int flags, int mode) {
EXPECT_EQ(fakePmemDev, pathname);
EXPECT_EQ(O_RDWR, flags & O_RDWR);
EXPECT_EQ(0, mode);
return 5678;
}
virtual void* mmap(void* start, size_t length, int prot, int flags, int fd,
off_t offset) {
return (void*)MAP_FAILED;
}
virtual int getErrno() {
return ENOMEM;
}
};
TEST(test_pmem_kernel_allocator, testAllocPmemBufferWithEnomemOnMmap) {
Deps_KernelAllocPmemBufferWithEnomemOnMmap depsMock;
PmemKernelAllocator pma(depsMock, fakePmemDev);
void* base = 0;
int offset = -9182, fd = -9182;
int size = 0x100;
int flags = ~0;
int result = pma.alloc_pmem_buffer(size, flags, &base, &offset, &fd);
ASSERT_EQ(-ENOMEM, result);
ASSERT_EQ(0, base);
ASSERT_EQ(0, offset);
ASSERT_EQ(-1, fd);
}
/******************************************************************************/

28
libhwcomposer/Android.mk Normal file
View File

@ -0,0 +1,28 @@
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_SRC_FILES := \
hwcomposer.cpp
LOCAL_MODULE := hwcomposer.$(TARGET_BOARD_PLATFORM)
LOCAL_CFLAGS:= -DLOG_TAG=\"$(TARGET_BOARD_PLATFORM).hwcomposer\"
LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc
LOCAL_C_INCLUDES += hardware/msm7k/liboverlay
LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
ifeq ($(TARGET_HAVE_HDMI_OUT),true)
LOCAL_CFLAGS += -DHDMI_DUAL_DISPLAY
endif
ifeq ($(TARGET_HAVE_BYPASS),true)
LOCAL_CFLAGS += -DCOMPOSITION_BYPASS
endif
ifeq ($(TARGET_USE_HDMI_AS_PRIMARY),true)
LOCAL_CFLAGS += -DHDMI_AS_PRIMARY
endif
include $(BUILD_SHARED_LIBRARY)

1162
libhwcomposer/hwcomposer.cpp Normal file

File diff suppressed because it is too large Load Diff

53
liboverlay/Android.mk Normal file
View File

@ -0,0 +1,53 @@
# 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
#
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
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_SRC_FILES := \
overlayLib.cpp \
overlayLibUI.cpp \
LOCAL_CFLAGS:= -DLOG_TAG=\"OverlayLib\"
ifeq ($(TARGET_USES_ION),true)
LOCAL_CFLAGS += -DUSE_ION
LOCAL_SHARED_LIBRARIES += libmemalloc
endif
ifeq ($(TARGET_USE_HDMI_AS_PRIMARY),true)
LOCAL_CFLAGS += -DHDMI_AS_PRIMARY
endif
LOCAL_MODULE := liboverlay
include $(BUILD_SHARED_LIBRARY)
# 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 liboverlay libcutils
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_SRC_FILES := overlay.cpp
LOCAL_MODULE := overlay.default
include $(BUILD_SHARED_LIBRARY)

1197
liboverlay/overlay.cpp Normal file

File diff suppressed because it is too large Load Diff

1799
liboverlay/overlayLib.cpp Normal file

File diff suppressed because it is too large Load Diff

306
liboverlay/overlayLib.h Normal file
View File

@ -0,0 +1,306 @@
/*
* 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.
*/
#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 <hardware/overlay.h>
#include <utils/RefBase.h>
#include <alloc_controller.h>
#include <memalloc.h>
#define HW_OVERLAY_MAGNIFICATION_LIMIT 8
#define HW_OVERLAY_MINIFICATION_LIMIT HW_OVERLAY_MAGNIFICATION_LIMIT
#define EVEN_OUT(x) if (x & 0x0001) {x--;}
#define VG0_PIPE 0
#define VG1_PIPE 1
#define NUM_CHANNELS 2
#define FRAMEBUFFER_0 0
#define FRAMEBUFFER_1 1
enum {
HDMI_OFF,
HDMI_ON
};
enum {
OVERLAY_CHANNEL_DOWN,
OVERLAY_CHANNEL_UP
};
enum {
NEW_REQUEST,
UPDATE_REQUEST
};
/* ------------------------------- 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;
};
namespace overlay {
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);
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);
/* 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);
const int max_num_buffers = 3;
typedef struct mdp_rect overlay_rect;
class OverlayControlChannel {
bool mNoRot;
int mFBWidth;
int mFBHeight;
int mFBbpp;
int mFBystride;
int mFormat;
int mFD;
int mRotFD;
int mSize;
int mOrientation;
unsigned int mFormat3D;
bool mUIChannel;
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 flags, int orientation, int zorder = 0, bool ignoreFB = false,
int requestType = NEW_REQUEST);
bool startOVRotatorSessions(const overlay_buffer_info& info, int orientation, int requestType);
void swapOVRotWidthHeight();
public:
OverlayControlChannel();
~OverlayControlChannel();
bool startControlChannel(int w, int h, int format,
int fbnum, bool norot = false,
bool uichannel = false,
unsigned int format3D = 0, int zorder = 0,
bool ignoreFB = false);
bool closeControlChannel();
bool setPosition(int x, int y, uint32_t w, uint32_t h);
bool setParameter(int param, 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 updateWaitForVsyncFlags(bool waitForVsync);
bool getAspectRatioPosition(int w, int h, overlay_rect *rect);
bool getPositionS3D(int channel, int format, overlay_rect *rect);
bool updateOverlaySource(const overlay_buffer_info& info, int orientation, bool waitForVsync);
bool getFormat() const { return mFormat; }
bool useVirtualFB ();
int getOverlayFlags() const { return mOVInfo.flags; }
};
class OverlayDataChannel {
bool mNoRot;
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;
int 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 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 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 updateStatus, int size);
};
/*
* Overlay class for single thread application
* A multiple thread/process application need to use Overlay HAL
*/
class Overlay {
bool mChannelUP;
bool mHDMIConnected;
unsigned int mS3DFormat;
//Actual cropped source width and height of overlay
int mCroppedSrcWidth;
int mCroppedSrcHeight;
overlay_buffer_info mOVBufferInfo;
int mState;
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, bool ignoreFB = false,
int num_buffers = 2);
bool closeChannel();
bool setPosition(int x, int y, uint32_t w, uint32_t h);
bool setParameter(int param, 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, bool hdmiConnected,
bool ignoreFB = false, int numBuffers = 2);
bool setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h);
int getChannelStatus() const { return (mChannelUP ? OVERLAY_CHANNEL_UP: OVERLAY_CHANNEL_DOWN); }
void setHDMIStatus (bool isHDMIConnected) { mHDMIConnected = isHDMIConnected; mState = -1; }
int getHDMIStatus() const {return (mHDMIConnected ? HDMI_ON : HDMI_OFF); }
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, bool waitForVsync);
int getS3DFormat(int format);
};
struct overlay_shared_data {
volatile bool isControlSetup;
unsigned int state;
int rotid[2];
int ovid[2];
};
};
#endif

524
liboverlay/overlayLibUI.cpp Normal file
View File

@ -0,0 +1,524 @@
/*
* 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.
*/
#include "overlayLibUI.h"
#include "gralloc_priv.h"
#define LOG_TAG "OverlayUI"
using android::sp;
using gralloc::IMemAlloc;
using gralloc::alloc_data;
namespace {
/* helper functions */
bool checkOVState(int w, int h, int format, int orientation,
int zorder, const mdp_overlay& ov) {
switch(orientation) {
case OVERLAY_TRANSFORM_ROT_90:
case OVERLAY_TRANSFORM_ROT_270: {
int tmp = w;
w = h;
h = tmp;
break;
}
default:
break;
}
int srcw = (w + 31) & ~31;
int srch = (h + 31) & ~31;
bool displayAttrsCheck = ((srcw == ov.src.width) && (srch == ov.src.height) &&
(format == ov.src.format));
bool zOrderCheck = (ov.z_order == zorder);
if (displayAttrsCheck && zorder == overlay::NO_INIT)
return true;
if (displayAttrsCheck && zorder != overlay::NO_INIT
&& ov.z_order == zorder)
return true;
return false;
}
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;
}
void setupOvRotInfo(int w, int h, int format, int orientation,
mdp_overlay& ovInfo, msm_rotator_img_info& rotInfo) {
memset(&ovInfo, 0, sizeof(ovInfo));
memset(&rotInfo, 0, sizeof(rotInfo));
ovInfo.id = MSMFB_NEW_REQUEST;
int srcw = (w + 31) & ~31;
int srch = (h + 31) & ~31;
ovInfo.src.width = srcw;
ovInfo.src.height = srch;
ovInfo.src.format = format;
ovInfo.src_rect.w = w;
ovInfo.src_rect.h = h;
ovInfo.alpha = 0xff;
ovInfo.transp_mask = 0xffffffff;
rotInfo.src.format = format;
rotInfo.dst.format = format;
rotInfo.src.width = srcw;
rotInfo.src.height = srch;
rotInfo.src_rect.w = srcw;
rotInfo.src_rect.h = srch;
rotInfo.dst.width = srcw;
rotInfo.dst.height = srch;
int rot = orientation;
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 = ovInfo.src_rect.x;
ovInfo.src_rect.x = ovInfo.src.height -
(ovInfo.src_rect.y + ovInfo.src_rect.h);
ovInfo.src_rect.y = tmp;
swapOVRotWidthHeight(rotInfo, ovInfo);
rot = HAL_TRANSFORM_ROT_90;
break;
}
case HAL_TRANSFORM_ROT_180:
break;
case HAL_TRANSFORM_ROT_270: {
int tmp = ovInfo.src_rect.y;
ovInfo.src_rect.y = ovInfo.src.width -
(ovInfo.src_rect.x + ovInfo.src_rect.w);
ovInfo.src_rect.x = tmp;
swapOVRotWidthHeight(rotInfo, ovInfo);
break;
}
default:
break;
}
int mdp_rotation = overlay::get_mdp_orientation(rot);
if (mdp_rotation < 0)
mdp_rotation = 0;
ovInfo.user_data[0] = mdp_rotation;
rotInfo.rotations = ovInfo.user_data[0];
if (mdp_rotation)
rotInfo.enable = 1;
ovInfo.dst_rect.w = ovInfo.src_rect.w;
ovInfo.dst_rect.h = ovInfo.src_rect.h;
}
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 ALREADY_EXISTS;
status_t ret = NO_INIT;
char const * const device_template =
"/dev/graphics/fb%u";
char dev_name[64];
snprintf(dev_name, 64, 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;
}
status_t OVHelper::startOVSession(mdp_overlay& ovInfo, int fbnum) {
status_t ret = NO_INIT;
if (mSessionID == NO_INIT) {
ret = mobjDisplay.openDisplay(fbnum);
if (ret != NO_ERROR)
return ret;
if (ioctl(mobjDisplay.getFD(), MSMFB_OVERLAY_SET, &ovInfo)) {
LOGE("OVerlay set failed..");
mobjDisplay.closeDisplay();
ret = BAD_VALUE;
}
else {
mSessionID = ovInfo.id;
mOVInfo = ovInfo;
ret = NO_ERROR;
}
}
else
ret = ALREADY_EXISTS;
return ret;
}
status_t OVHelper::queueBuffer(msmfb_overlay_data ovData) {
if (mSessionID == NO_INIT)
return NO_INIT;
ovData.id = mSessionID;
if (ioctl(mobjDisplay.getFD(), MSMFB_OVERLAY_PLAY, &ovData))
return BAD_VALUE;
return NO_ERROR;
}
status_t OVHelper::closeOVSession() {
if (mSessionID != NO_INIT) {
ioctl(mobjDisplay.getFD(), MSMFB_OVERLAY_UNSET, &mSessionID);
mobjDisplay.closeDisplay();
}
mSessionID = NO_INIT;
return NO_ERROR;
}
status_t OVHelper::setPosition(int x, int y, int w, int h) {
status_t ret = BAD_VALUE;
if (mSessionID != NO_INIT) {
int fd = mobjDisplay.getFD();
if (x < 0 || y < 0 || ((x + w) > getFBWidth())) {
LOGE("set position failed, invalid argument");
return ret;
}
mdp_overlay ov;
ov.id = mSessionID;
if (!ioctl(fd, MSMFB_OVERLAY_GET, &ov)) {
if (x != ov.dst_rect.x || y != ov.dst_rect.y ||
w != ov.dst_rect.w || h != ov.dst_rect.h) {
ov.dst_rect.x = x;
ov.dst_rect.y = y;
ov.dst_rect.w = w;
ov.dst_rect.h = h;
if (ioctl(fd, MSMFB_OVERLAY_SET, &ov)) {
LOGE("set position failed");
return ret;
}
}
mOVInfo = ov;
return NO_ERROR;
}
return ret;
}
return NO_INIT;
}
status_t OVHelper::getOVInfo(mdp_overlay& ovInfo) {
if (mSessionID == NO_INIT)
return NO_INIT;
ovInfo = mOVInfo;
return NO_ERROR;
}
status_t Rotator::startRotSession(msm_rotator_img_info& rotInfo,
int size, int numBuffers) {
status_t ret = ALREADY_EXISTS;
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 (int check = ioctl(mFD, MSM_ROTATOR_IOCTL_START, &rotInfo)) {
close(mFD);
mFD = NO_INIT;
return NO_INIT;
}
#ifdef USE_ION
alloc_data data;
data.base = 0;
data.fd = -1;
data.offset = 0;
data.size = mSize * mNumBuffers;
data.align = getpagesize();
data.uncached = true;
int err = mAlloc->allocate(data, GRALLOC_USAGE_PRIVATE_ADSP_HEAP|
GRALLOC_USAGE_PRIVATE_SMI_HEAP, 0);
if(err) {
LOGE("Cant allocate from ION");
closeRotSession();
return NO_INIT;
}
mPmemFD = data.fd;
mPmemAddr = data.base;
mBufferType = data.allocType;
#else
mSessionID = rotInfo.session_id;
mPmemFD = open("/dev/pmem_adsp", O_RDWR | O_SYNC);
if (mPmemFD < 0) {
closeRotSession();
return NO_INIT;
}
mSize = size;
mPmemAddr = (void *) mmap(NULL, mSize* mNumBuffers, PROT_READ | PROT_WRITE,
MAP_SHARED, mPmemFD, 0);
if (mPmemAddr == MAP_FAILED) {
closeRotSession();
return NO_INIT;
}
#endif
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);
#ifdef USE_ION
sp<IMemAlloc> memalloc = mAlloc->getAllocator(mBufferType);
memalloc->free_buffer(mPmemAddr, mSize * mNumBuffers, 0, mPmemFD);
#else
munmap(mPmemAddr, mSize * mNumBuffers);
close(mPmemFD);
#endif
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;
}
status_t OverlayUI::closeChannel() {
mobjOVHelper.closeOVSession();
mobjRotator.closeRotSession();
mChannelState = CLOSED;
return NO_ERROR;
}
status_t OverlayUI::setSource(const overlay_buffer_info& info, int orientation,
bool useVGPipe, bool ignoreFB,
int fbnum, int zorder) {
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))
return ret;
if (mChannelState == PENDING_CLOSE)
closeChannel();
if (mChannelState == UP) {
mdp_overlay ov;
if (mobjOVHelper.getOVInfo(ov) == NO_ERROR) {
if (mOrientation == orientation &&
mFBNum == fbnum &&
checkOVState(info.width, info.height, format, orientation, zorder, ov))
return NO_ERROR;
else
mChannelState = PENDING_CLOSE;
}
else
mChannelState = PENDING_CLOSE;
return ret;
}
mOrientation = orientation;
mdp_overlay ovInfo;
msm_rotator_img_info rotInfo;
setupOvRotInfo(info.width, info.height, format, orientation, ovInfo, rotInfo);
int flags = 0;
if (ignoreFB)
ovInfo.is_fg = 1;
else
flags |= MDP_OV_PLAY_NOWAIT;
if (turnOFFVSync())
flags |= MDP_OV_PLAY_NOWAIT;
if (useVGPipe ||
(fbnum == FB0 && getRGBBpp(format) != mobjOVHelper.getFBBpp()))
flags |= MDP_OV_PIPE_SHARE;
ovInfo.flags = flags;
if (zorder != NO_INIT)
ovInfo.z_order = zorder;
ret = startChannel(fbnum, ovInfo, rotInfo, info.size);
return ret;
}
status_t OverlayUI::startChannel(int fbnum, mdp_overlay& ovInfo,
msm_rotator_img_info& rotInfo, int size) {
status_t ret = BAD_VALUE;
if (mChannelState == UP)
return ret;
ret = mobjOVHelper.startOVSession(ovInfo, fbnum);
if (ret == NO_ERROR && mOrientation) {
ret = mobjRotator.startRotSession(rotInfo, size);
}
if (ret == NO_ERROR) {
mChannelState = UP;
mFBNum = fbnum;
}
else
LOGE("start channel failed.");
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;
}
ret = mobjOVHelper.queueBuffer(ovData);
if (ret != NO_ERROR)
LOGE("Queuebuffer failed ");
return ret;
}
};

160
liboverlay/overlayLibUI.h Normal file
View File

@ -0,0 +1,160 @@
/*
* 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() { close(mFD); mFD = NO_INIT; };
};
/*
* OVHelper class, provides apis related to Overlay
* It communicates with MDP driver, provides following services
* Start overlay session
* Set position of the destination on to display
*/
class OVHelper {
int mSessionID;
Display mobjDisplay;
mdp_overlay mOVInfo;
OVHelper(const OVHelper& objOVHelper);
OVHelper& operator=(const OVHelper& objOVHelper);
public:
explicit OVHelper() : mSessionID(NO_INIT) { };
~OVHelper() { closeOVSession(); };
status_t startOVSession(mdp_overlay& ovInfo, int fbnum);
status_t closeOVSession();
status_t queueBuffer(msmfb_overlay_data ovData);
int getFBWidth() const { return mobjDisplay.getFBWidth(); };
int getFBHeight() const { return mobjDisplay.getFBHeight(); };
int getFBBpp() const { return mobjDisplay.getFBBpp(); };
status_t setPosition(int x, int y, int w, int h);
status_t getOVInfo(mdp_overlay& ovInfo);
};
/*
* 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() : mFD(NO_INIT), mSessionID(NO_INIT), mPmemFD(-1)
{
#ifdef USE_ION
mAlloc = gralloc::IAllocController::getInstance();
#endif
}
~Rotator() { closeRotSession(); }
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;
int mOrientation;
int mFBNum;
OVHelper mobjOVHelper;
Rotator mobjRotator;
OverlayUI(const OverlayUI& objOverlay);
OverlayUI& operator=(const OverlayUI& objOverlay);
status_t startChannel(int fbnum, mdp_overlay& ovInfo,
msm_rotator_img_info& rotInfo, int size);
public:
enum fbnum_t { FB0, FB1 };
explicit OverlayUI() : mChannelState(CLOSED), mOrientation(NO_INIT), mFBNum(NO_INIT) { };
~OverlayUI() { closeChannel(); };
status_t setSource(const overlay_buffer_info& info, int orientation,
bool useVGPipe = false, bool ignoreFB = true,
int fbnum = FB0, int zorder = NO_INIT);
status_t setPosition(int x, int y, int w, int h) {
return mobjOVHelper.setPosition(x, y, w, h);
};
status_t closeChannel();
channel_state_t isChannelUP() const { return mChannelState; };
int getFBWidth() const { return mobjOVHelper.getFBWidth(); };
int getFBHeight() const { return mobjOVHelper.getFBHeight(); };
status_t queueBuffer(buffer_handle_t buffer);
};
};
#endif

1109
liboverlay/overlayState.cpp Normal file

File diff suppressed because it is too large Load Diff