sdm: Remove unused libraries, files and functions

1. Remove unused libraries libhdmi, liboverlay and libhwcomposer.
2. Remove unused functions and files from libqdutils.
2. Add querySDEInfo() function in qdutisl to query SDE capability.

Change-Id: Ibea2dd2d22fecb420079e3b7cbbcc57d10f75d49
This commit is contained in:
Ramkumar Radhakrishnan
2015-06-16 20:22:42 -07:00
committed by Gerrit - the friendly Code Review server
parent c4afb5dfa0
commit 29a36a54bc
64 changed files with 96 additions and 22596 deletions

View File

@@ -1,18 +1,8 @@
ifeq ($(call is-board-platform-in-list, msm8996),true)
TARGET_USES_SDM = true
else
TARGET_USES_SDM = false
endif
display-hals := libgralloc libcopybit liblight libmemtrack libqservice libqdutils
display-hals += hdmi_cec
ifeq ($(TARGET_USES_SDM), true)
sdm-libs := sdm/libs
display-hals += $(sdm-libs)/utils $(sdm-libs)/core $(sdm-libs)/hwc
else
display-hals += libgenlock libhwcomposer liboverlay libhdmi
endif
ifeq ($(call is-vendor-board-platform,QCOM),true)
include $(call all-named-subdir-makefiles,$(display-hals))

View File

@@ -1,10 +1,7 @@
#Common headers
common_includes := $(LOCAL_PATH)/../libgralloc
common_includes += $(LOCAL_PATH)/../liboverlay
common_includes += $(LOCAL_PATH)/../libcopybit
common_includes += $(LOCAL_PATH)/../libqdutils
common_includes += $(LOCAL_PATH)/../libhwcomposer
common_includes += $(LOCAL_PATH)/../libhdmi
common_includes += $(LOCAL_PATH)/../libqservice
common_header_export_path := qcom/display

View File

@@ -35,9 +35,11 @@
#include "memalloc.h"
#include "ionalloc.h"
#include "gr.h"
#include "comptype.h"
#include "mdp_version.h"
#include "qd_utils.h"
#include <qdMetaData.h>
#include <utils/Singleton.h>
#include <utils/Mutex.h>
#ifdef VENUS_COLOR_FORMAT
#include <media/msm_media_info.h>
@@ -73,6 +75,7 @@
using namespace gralloc;
using namespace qdutils;
using namespace android;
ANDROID_SINGLETON_STATIC_INSTANCE(AdrenoMemInfo);
@@ -445,10 +448,13 @@ IMemAlloc* IonController::getAllocator(int flags)
bool isMacroTileEnabled(int format, int usage)
{
bool tileEnabled = false;
int isMacroTileSupportedByMDP = 0;
qdutils::querySDEInfo(HAS_MACRO_TILE, &isMacroTileSupportedByMDP);
// Check whether GPU & MDSS supports MacroTiling feature
if(AdrenoMemInfo::getInstance().isMacroTilingSupportedByGPU() &&
qdutils::MDPVersion::getInstance().supportsMacroTile())
isMacroTileSupportedByMDP)
{
// check the format
switch(format)

View File

@@ -1,13 +0,0 @@
LOCAL_PATH := $(call my-dir)
include $(LOCAL_PATH)/../common.mk
include $(CLEAR_VARS)
LOCAL_MODULE := libhdmi
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
LOCAL_SHARED_LIBRARIES := $(common_libs) liboverlay libqdutils
LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdhdmi\"
LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
LOCAL_SRC_FILES := hdmi.cpp
include $(BUILD_SHARED_LIBRARY)

View File

@@ -1,910 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 2012-2015, The Linux Foundation. All rights reserved.
*
* Not a Contribution, Apache license notifications and license are
* retained for attribution purposes only.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define DEBUG 0
#include <fcntl.h>
#include <linux/msm_mdp.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <cutils/properties.h>
#include "hwc_utils.h"
#include "hdmi.h"
#include "overlayUtils.h"
#include "overlay.h"
#include "qd_utils.h"
using namespace android;
using namespace qdutils;
namespace qhwc {
#define UNKNOWN_STRING "unknown"
#define SPD_NAME_LENGTH 16
int HDMIDisplay::configure() {
if(!openFrameBuffer()) {
ALOGE("%s: Failed to open FB: %d", __FUNCTION__, mFbNum);
return -1;
}
readCEUnderscanInfo();
readResolution();
/* Used for changing the resolution
* getUserConfig will get the preferred
* config index set thru adb shell */
mActiveConfig = getUserConfig();
if (mActiveConfig == -1) {
//Get the best mode and set
mActiveConfig = getBestConfig();
}
// Read the system property to determine if downscale feature is enabled.
char value[PROPERTY_VALUE_MAX];
mMDPDownscaleEnabled = false;
if(property_get("sys.hwc.mdp_downscale_enabled", value, "false")
&& !strcmp(value, "true")) {
mMDPDownscaleEnabled = true;
}
// Set the mode corresponding to the active index
mCurrentMode = mEDIDModes[mActiveConfig];
setAttributes();
// set system property
property_set("hw.hdmiON", "1");
// XXX: A debug property can be used to enable resolution change for
// testing purposes: debug.hwc.enable_resolution_change
mEnableResolutionChange = false;
if(property_get("debug.hwc.enable_resolution_change", value, "false")
&& !strcmp(value, "true")) {
mEnableResolutionChange = true;
}
return 0;
}
void HDMIDisplay::getAttributes(uint32_t& width, uint32_t& height) {
uint32_t refresh = 0, fps = 0;
getAttrForConfig(mActiveConfig, width, height, refresh, fps);
}
int HDMIDisplay::teardown() {
closeFrameBuffer();
resetInfo();
// unset system property
property_set("hw.hdmiON", "0");
return 0;
}
HDMIDisplay::HDMIDisplay():mFd(-1),
mCurrentMode(-1), mModeCount(0), mPrimaryWidth(0), mPrimaryHeight(0),
mUnderscanSupported(false), mMDPDownscaleEnabled(false)
{
memset(&mVInfo, 0, sizeof(mVInfo));
mFbNum = qdutils::getHDMINode();
mDisplayId = HWC_DISPLAY_EXTERNAL;
// Update the display if HDMI is connected as primary
if (isHDMIPrimaryDisplay()) {
mDisplayId = HWC_DISPLAY_PRIMARY;
}
// Disable HPD at start if HDMI is external, it will be enabled later
// when the display powers on
// This helps for framework reboot or adb shell stop/start
if (mDisplayId) {
writeHPDOption(0);
}
if(mFbNum != -1) {
// Update the Source Product Information
// Vendor Name
setSPDInfo("vendor_name", "ro.product.manufacturer");
// Product Description
setSPDInfo("product_description", "ro.product.name");
}
ALOGD_IF(DEBUG, "%s mDisplayId(%d) mFbNum(%d)",
__FUNCTION__, mDisplayId, mFbNum);
}
/* gets the product manufacturer and product name and writes it
* to the sysfs node, so that the driver can get that information
* Used to show QCOM 8974 instead of Input 1 for example
*/
void HDMIDisplay::setSPDInfo(const char* node, const char* property) {
char info[PROPERTY_VALUE_MAX];
ssize_t err = -1;
int spdFile = openDeviceNode(node, O_RDWR);
if (spdFile >= 0) {
memset(info, 0, sizeof(info));
property_get(property, info, UNKNOWN_STRING);
ALOGD_IF(DEBUG, "In %s: %s = %s",
__FUNCTION__, property, info);
if (strncmp(info, UNKNOWN_STRING, SPD_NAME_LENGTH)) {
err = write(spdFile, info, strlen(info));
if (err <= 0) {
ALOGE("%s: file write failed for '%s'"
"err no = %d", __FUNCTION__, node, errno);
}
} else {
ALOGD_IF(DEBUG, "%s: property_get failed for SPD %s",
__FUNCTION__, node);
}
close(spdFile);
}
}
void HDMIDisplay::setHPD(uint32_t value) {
ALOGD_IF(DEBUG,"HPD enabled=%d", value);
writeHPDOption(value);
}
void HDMIDisplay::setActionSafeDimension(int w, int h) {
ALOGD_IF(DEBUG,"ActionSafe w=%d h=%d", w, h);
char actionsafeWidth[PROPERTY_VALUE_MAX];
char actionsafeHeight[PROPERTY_VALUE_MAX];
snprintf(actionsafeWidth, sizeof(actionsafeWidth), "%d", w);
property_set("persist.sys.actionsafe.width", actionsafeWidth);
snprintf(actionsafeHeight, sizeof(actionsafeHeight), "%d", h);
property_set("persist.sys.actionsafe.height", actionsafeHeight);
}
int HDMIDisplay::getModeCount() const {
ALOGD_IF(DEBUG,"HPD mModeCount=%d", mModeCount);
return mModeCount;
}
void HDMIDisplay::readCEUnderscanInfo()
{
int hdmiScanInfoFile = -1;
ssize_t len = -1;
char scanInfo[17];
char *ce_info_str = NULL;
char *save_ptr;
const char token[] = ", \n";
int ce_info = -1;
memset(scanInfo, 0, sizeof(scanInfo));
hdmiScanInfoFile = openDeviceNode("scan_info", O_RDONLY);
if (hdmiScanInfoFile < 0) {
return;
} else {
len = read(hdmiScanInfoFile, scanInfo, sizeof(scanInfo)-1);
ALOGD("%s: Scan Info string: %s length = %zu",
__FUNCTION__, scanInfo, len);
if (len <= 0) {
close(hdmiScanInfoFile);
ALOGE("%s: Scan Info file empty", __FUNCTION__);
return;
}
scanInfo[len] = '\0'; /* null terminate the string */
close(hdmiScanInfoFile);
}
/*
* The scan_info contains the three fields
* PT - preferred video format
* IT - video format
* CE video format - containing the underscan support information
*/
/* PT */
ce_info_str = strtok_r(scanInfo, token, &save_ptr);
if (ce_info_str) {
/* IT */
ce_info_str = strtok_r(NULL, token, &save_ptr);
if (ce_info_str) {
/* CE */
ce_info_str = strtok_r(NULL, token, &save_ptr);
if (ce_info_str)
ce_info = atoi(ce_info_str);
}
}
if (ce_info_str) {
// ce_info contains the underscan information
if (ce_info == HDMI_SCAN_ALWAYS_UNDERSCANED ||
ce_info == HDMI_SCAN_BOTH_SUPPORTED)
// if TV supported underscan, then driver will always underscan
// hence no need to apply action safe rectangle
mUnderscanSupported = true;
} else {
ALOGE("%s: scan_info string error", __FUNCTION__);
}
// Store underscan support info in a system property
const char* prop = (mUnderscanSupported) ? "1" : "0";
property_set("hw.underscan_supported", prop);
return;
}
HDMIDisplay::~HDMIDisplay()
{
closeFrameBuffer();
}
/*
* sets the fb_var_screeninfo from the hdmi_mode_timing_info
*/
void setDisplayTiming(struct fb_var_screeninfo &info,
const msm_hdmi_mode_timing_info* mode)
{
info.reserved[0] = 0;
info.reserved[1] = 0;
info.reserved[2] = 0;
#ifndef FB_METADATA_VIDEO_INFO_CODE_SUPPORT
info.reserved[3] = (info.reserved[3] & 0xFFFF) |
(mode->video_format << 16);
#endif
info.xoffset = 0;
info.yoffset = 0;
info.xres = mode->active_h;
info.yres = mode->active_v;
info.pixclock = (mode->pixel_freq)*1000;
info.vmode = mode->interlaced ?
FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED;
info.right_margin = mode->front_porch_h;
info.hsync_len = mode->pulse_width_h;
info.left_margin = mode->back_porch_h;
info.lower_margin = mode->front_porch_v;
info.vsync_len = mode->pulse_width_v;
info.upper_margin = mode->back_porch_v;
}
int HDMIDisplay::parseResolution(char* edidStr)
{
char delim = ',';
int count = 0;
char *start, *end;
// EDIDs are string delimited by ','
// Ex: 16,4,5,3,32,34,1
// Parse this string to get mode(int)
start = (char*) edidStr;
end = &delim;
while(*end == delim) {
mEDIDModes[count] = (int) strtol(start, &end, 10);
start = end+1;
count++;
}
ALOGD_IF(DEBUG, "In %s: count = %d", __FUNCTION__, count);
for (int i = 0; i < count; i++)
ALOGD_IF(DEBUG, "Mode[%d] = %d", i, mEDIDModes[i]);
return count;
}
bool HDMIDisplay::readResolution()
{
ssize_t len = -1;
char edidStr[PAGE_SIZE] = {'\0'};
int hdmiEDIDFile = openDeviceNode("edid_modes", O_RDONLY);
if (hdmiEDIDFile < 0) {
return false;
} else {
len = read(hdmiEDIDFile, edidStr, sizeof(edidStr)-1);
ALOGD_IF(DEBUG, "%s: EDID string: %s length = %zu",
__FUNCTION__, edidStr, len);
if (len <= 0) {
ALOGE("%s: edid_modes file empty", __FUNCTION__);
edidStr[0] = '\0';
}
else {
while (len > 1 && isspace(edidStr[len-1])) {
--len;
}
edidStr[len] = '\0';
}
close(hdmiEDIDFile);
}
if(len > 0) {
// Get EDID modes from the EDID strings
mModeCount = parseResolution(edidStr);
ALOGD_IF(DEBUG, "%s: mModeCount = %d", __FUNCTION__,
mModeCount);
}
// Populate the internal data structure with the timing information
// for each edid mode read from the driver
if (mModeCount > 0) {
mDisplayConfigs = new msm_hdmi_mode_timing_info[mModeCount];
readConfigs();
} else {
// If we fail to read from EDID when HDMI is connected, then
// mModeCount will be 0 and bestConfigIndex will be invalid.
// In this case, we populate the mEDIDModes structure with
// a default mode at config index 0.
uint32_t defaultConfigIndex = 0;
mModeCount = 1;
mEDIDModes[defaultConfigIndex] = HDMI_VFRMT_640x480p60_4_3;
struct msm_hdmi_mode_timing_info defaultMode =
HDMI_VFRMT_640x480p60_4_3_TIMING;
mDisplayConfigs = new msm_hdmi_mode_timing_info[mModeCount];
mDisplayConfigs[defaultConfigIndex] = defaultMode;
ALOGD("%s Defaulting to HDMI_VFRMT_640x480p60_4_3", __FUNCTION__);
}
return (len > 0);
}
bool HDMIDisplay::openFrameBuffer()
{
if (mFd == -1) {
char strDevPath[MAX_SYSFS_FILE_PATH];
snprintf(strDevPath, MAX_SYSFS_FILE_PATH, "/dev/graphics/fb%d", mFbNum);
mFd = open(strDevPath, O_RDWR);
if (mFd < 0)
ALOGE("%s: %s is not available", __FUNCTION__, strDevPath);
}
return (mFd > 0);
}
bool HDMIDisplay::closeFrameBuffer()
{
int ret = 0;
if(mFd >= 0) {
ret = close(mFd);
mFd = -1;
}
return (ret == 0);
}
// clears the vinfo, edid, best modes
void HDMIDisplay::resetInfo()
{
memset(&mVInfo, 0, sizeof(mVInfo));
memset(mEDIDModes, 0, sizeof(mEDIDModes));
mModeCount = 0;
mCurrentMode = -1;
mUnderscanSupported = false;
mXres = 0;
mYres = 0;
mVsyncPeriod = 0;
mMDPScalingMode = false;
if (mDisplayConfigs) {
delete [] mDisplayConfigs;
mDisplayConfigs = 0;
}
// Reset the underscan supported system property
const char* prop = "0";
property_set("hw.underscan_supported", prop);
}
/// Returns the index of the user mode set(if any) using adb shell
int HDMIDisplay::getUserConfig() {
/* Based on the property set the resolution */
char property_value[PROPERTY_VALUE_MAX];
property_get("hw.hdmi.resolution", property_value, "-1");
int mode = atoi(property_value);
if(isValidMode(mode)) {
ALOGD_IF(DEBUG, "%s: setting the HDMI mode = %d", __FUNCTION__, mode);
return getModeIndex(mode);
}
return -1;
}
// Get the index of the best mode for the current HD TV
int HDMIDisplay::getBestConfig() {
int bestConfigIndex = 0;
int edidMode = -1;
struct msm_hdmi_mode_timing_info currentModeInfo = {0};
struct msm_hdmi_mode_timing_info bestModeInfo = {0};
bestModeInfo.video_format = 0;
bestModeInfo.active_v = 0;
bestModeInfo.active_h = 0;
bestModeInfo.refresh_rate = 0;
bestModeInfo.ar = HDMI_RES_AR_INVALID;
// for all the timing info read, get the best config
for (int configIndex = 0; configIndex < mModeCount; configIndex++) {
currentModeInfo = mDisplayConfigs[configIndex];
edidMode = mEDIDModes[configIndex];
if (!isValidMode(edidMode)) {
ALOGD("%s EDID Mode %d is not supported", __FUNCTION__, edidMode);
continue;
}
ALOGD_IF(DEBUG, "%s Best (%d) : (%dx%d) @ %d;"
" Current (%d) (%dx%d) @ %d",
__FUNCTION__, bestConfigIndex, bestModeInfo.active_h,
bestModeInfo.active_v, bestModeInfo.refresh_rate, configIndex,
currentModeInfo.active_h, currentModeInfo.active_v,
currentModeInfo.refresh_rate);
// Compare two HDMI modes in order of height, width, refresh rate and
// aspect ratio.
if (currentModeInfo.active_v > bestModeInfo.active_v) {
bestConfigIndex = configIndex;
} else if (currentModeInfo.active_v == bestModeInfo.active_v) {
if (currentModeInfo.active_h > bestModeInfo.active_h) {
bestConfigIndex = configIndex;
} else if (currentModeInfo.active_h == bestModeInfo.active_h) {
if (currentModeInfo.refresh_rate > bestModeInfo.refresh_rate) {
bestConfigIndex = configIndex;
} else if (currentModeInfo.refresh_rate ==
bestModeInfo.refresh_rate) {
if (currentModeInfo.ar > bestModeInfo.ar) {
bestConfigIndex = configIndex;
}
}
}
}
if (bestConfigIndex == configIndex) {
bestModeInfo = mDisplayConfigs[bestConfigIndex];
}
}
return bestConfigIndex;
}
// Utility function used to request HDMI driver to write a new page of timing
// info into res_info node
void HDMIDisplay::requestNewPage(int pageNumber) {
char pageString[PAGE_SIZE];
int fd = openDeviceNode("res_info", O_WRONLY);
if (fd >= 0) {
snprintf(pageString, sizeof(pageString), "%d", pageNumber);
ALOGD_IF(DEBUG, "%s: page=%s", __FUNCTION__, pageString);
ssize_t err = write(fd, pageString, sizeof(pageString));
if (err <= 0) {
ALOGE("%s: Write to res_info failed (%d)", __FUNCTION__, errno);
}
close(fd);
}
}
// Reads the contents of res_info node into a buffer if the file is not empty
bool HDMIDisplay::readResFile(char * configBuffer) {
bool fileRead = false;
size_t bytesRead = 0;
int fd = openDeviceNode("res_info", O_RDONLY);
if (fd >= 0 && (bytesRead = read(fd, configBuffer, PAGE_SIZE)) != 0) {
fileRead = true;
}
close(fd);
ALOGD_IF(DEBUG, "%s: bytesRead=%d fileRead=%d",
__FUNCTION__, bytesRead, fileRead);
return fileRead;
}
// Populates the internal timing info structure with the timing info obtained
// from the HDMI driver
void HDMIDisplay::readConfigs() {
int configIndex = 0;
int pageNumber = MSM_HDMI_INIT_RES_PAGE;
long unsigned int size = sizeof(msm_hdmi_mode_timing_info);
while (true) {
char configBuffer[PAGE_SIZE] = {0};
msm_hdmi_mode_timing_info *info =
(msm_hdmi_mode_timing_info*) configBuffer;
if (!readResFile(configBuffer))
break;
while (info->video_format && size < PAGE_SIZE) {
mDisplayConfigs[configIndex] = *info;
size += sizeof(msm_hdmi_mode_timing_info);
info++;
ALOGD_IF(DEBUG, "%s: Config=%d Mode %d: (%dx%d) @ %d",
__FUNCTION__, configIndex,
mDisplayConfigs[configIndex].video_format,
mDisplayConfigs[configIndex].active_h,
mDisplayConfigs[configIndex].active_v,
mDisplayConfigs[configIndex].refresh_rate);
configIndex++;
}
size = sizeof(msm_hdmi_mode_timing_info);
// Request HDMI driver to populate res_info with more
// timing information
pageNumber++;
requestNewPage(pageNumber);
}
}
inline bool HDMIDisplay::isValidMode(int ID)
{
bool valid = false;
int modeIndex = getModeIndex(ID);
if (ID <= 0 || modeIndex < 0 || modeIndex > mModeCount) {
return false;
}
struct msm_hdmi_mode_timing_info* mode = &mDisplayConfigs[modeIndex];
// We dont support interlaced modes
if (mode->supported && !mode->interlaced) {
valid = true;
}
return valid;
}
// Does a put_vscreen info on the HDMI interface which will update
// the configuration (resolution, timing info) to match mCurrentMode
void HDMIDisplay::activateDisplay()
{
int ret = 0;
ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo);
if(ret < 0) {
ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__,
strerror(errno));
}
ALOGD_IF(DEBUG, "%s: GET Info<ID=%d %dx%d (%d,%d,%d),"
"(%d,%d,%d) %dMHz>", __FUNCTION__,
mVInfo.reserved[3], mVInfo.xres, mVInfo.yres,
mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin,
mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin,
mVInfo.pixclock/1000/1000);
struct msm_hdmi_mode_timing_info *mode = &mDisplayConfigs[mActiveConfig];
setDisplayTiming(mVInfo, mode);
ALOGD_IF(DEBUG, "%s: SET Info<ID=%d => Info<ID=%d %dx %d"
"(%d,%d,%d), (%d,%d,%d) %dMHz>", __FUNCTION__, mCurrentMode,
mode->video_format, mVInfo.xres, mVInfo.yres,
mVInfo.right_margin, mVInfo.hsync_len, mVInfo.left_margin,
mVInfo.lower_margin, mVInfo.vsync_len, mVInfo.upper_margin,
mVInfo.pixclock/1000/1000);
#ifdef FB_METADATA_VIDEO_INFO_CODE_SUPPORT
struct msmfb_metadata metadata;
memset(&metadata, 0 , sizeof(metadata));
metadata.op = metadata_op_vic;
metadata.data.video_info_code = mode->video_format;
if (ioctl(mFd, MSMFB_METADATA_SET, &metadata) == -1) {
ALOGD("In %s: MSMFB_METADATA_SET failed Err Str = %s",
__FUNCTION__, strerror(errno));
}
#endif
mVInfo.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE;
ret = ioctl(mFd, FBIOPUT_VSCREENINFO, &mVInfo);
if(ret < 0) {
ALOGD("In %s: FBIOPUT_VSCREENINFO failed Err Str = %s",
__FUNCTION__, strerror(errno));
}
}
bool HDMIDisplay::writeHPDOption(int userOption) const
{
bool ret = true;
if(mFbNum != -1) {
int hdmiHPDFile = openDeviceNode("hpd", O_RDWR);
if (hdmiHPDFile >= 0) {
ssize_t err = -1;
ALOGD_IF(DEBUG, "%s: option = %d",
__FUNCTION__, userOption);
if(userOption)
err = write(hdmiHPDFile, "1", 2);
else
err = write(hdmiHPDFile, "0" , 2);
if (err <= 0) {
ALOGE("%s: file write failed 'hpd'", __FUNCTION__);
ret = false;
}
close(hdmiHPDFile);
}
}
return ret;
}
void HDMIDisplay::setAttributes() {
uint32_t refresh = 0, fps = 0;
// Always set dpyAttr res to mVInfo res
getAttrForConfig(mActiveConfig, mXres, mYres, refresh, fps);
mMDPScalingMode = false;
if(overlay::Overlay::getInstance()->isUIScalingOnExternalSupported()
&& mMDPDownscaleEnabled) {
// if primary resolution is more than the hdmi resolution
// configure dpy attr to primary resolution and set MDP
// scaling mode
// Restrict this upto 1080p resolution max, if target does not
// support source split feature.
uint32_t primaryArea = mPrimaryWidth * mPrimaryHeight;
if(((primaryArea) > (mXres * mYres)) &&
(((primaryArea) <= SUPPORTED_DOWNSCALE_AREA) ||
qdutils::MDPVersion::getInstance().isSrcSplit())) {
// tmpW and tmpH will hold the primary dimensions before we
// update the aspect ratio if necessary.
int tmpW = mPrimaryWidth;
int tmpH = mPrimaryHeight;
// HDMI is always in landscape, so always assign the higher
// dimension to hdmi's xres
if(mPrimaryHeight > mPrimaryWidth) {
tmpW = mPrimaryHeight;
tmpH = mPrimaryWidth;
}
// The aspect ratios of the external and primary displays
// can be different. As a result, directly assigning primary
// resolution could lead to an incorrect final image.
// We get around this by calculating a new resolution by
// keeping aspect ratio intact.
hwc_rect r = {0, 0, 0, 0};
qdutils::getAspectRatioPosition(tmpW, tmpH, mXres, mYres, r);
uint32_t newExtW = r.right - r.left;
uint32_t newExtH = r.bottom - r.top;
uint32_t alignedExtW;
uint32_t alignedExtH;
// On 8994 and below targets MDP supports only 4X downscaling,
// Restricting selected external resolution to be exactly 4X
// greater resolution than actual external resolution
uint32_t maxMDPDownScale =
qdutils::MDPVersion::getInstance().getMaxMDPDownscale();
if((mXres * mYres * maxMDPDownScale) < (newExtW * newExtH)) {
float upScaleFactor = (float)maxMDPDownScale / 2.0f;
newExtW = (int)((float)mXres * upScaleFactor);
newExtH = (int)((float)mYres * upScaleFactor);
}
// Align it down so that the new aligned resolution does not
// exceed the maxMDPDownscale factor
alignedExtW = overlay::utils::aligndown(newExtW, 4);
alignedExtH = overlay::utils::aligndown(newExtH, 4);
mXres = alignedExtW;
mYres = alignedExtH;
// Set External Display MDP Downscale mode indicator
mMDPScalingMode = true;
}
}
ALOGD_IF(DEBUG_MDPDOWNSCALE, "Selected external resolution [%d X %d] "
"maxMDPDownScale %d mMDPScalingMode %d srcSplitEnabled %d "
"MDPDownscale feature %d",
mXres, mYres,
qdutils::MDPVersion::getInstance().getMaxMDPDownscale(),
mMDPScalingMode, qdutils::MDPVersion::getInstance().isSrcSplit(),
mMDPDownscaleEnabled);
mVsyncPeriod = (int) 1000000000l / fps;
ALOGD_IF(DEBUG, "%s xres=%d, yres=%d", __FUNCTION__, mXres, mYres);
}
/* returns the fd related to the node specified*/
int HDMIDisplay::openDeviceNode(const char* node, int fileMode) const {
char sysFsFilePath[MAX_SYSFS_FILE_PATH];
memset(sysFsFilePath, 0, sizeof(sysFsFilePath));
snprintf(sysFsFilePath , sizeof(sysFsFilePath),
"/sys/devices/virtual/graphics/fb%d/%s",
mFbNum, node);
int fd = open(sysFsFilePath, fileMode, 0);
if (fd < 0) {
ALOGE("%s: file '%s' not found : ret = %d err str: %s",
__FUNCTION__, sysFsFilePath, fd, strerror(errno));
}
return fd;
}
bool HDMIDisplay::isHDMIPrimaryDisplay() {
return (mFbNum == HWC_DISPLAY_PRIMARY);
}
int HDMIDisplay::getConnectedState() {
int ret = -1;
int mFbNum = qdutils::getHDMINode();
int connectedNode = openDeviceNode("connected", O_RDONLY);
if(connectedNode >= 0) {
char opStr[4];
ssize_t bytesRead = read(connectedNode, opStr, sizeof(opStr) - 1);
if(bytesRead > 0) {
opStr[bytesRead] = '\0';
ret = atoi(opStr);
ALOGD_IF(DEBUG, "%s: Read %d from connected", __FUNCTION__, ret);
} else if(bytesRead == 0) {
ALOGE("%s: HDMI connected node empty", __FUNCTION__);
} else {
ALOGE("%s: Read from HDMI connected node failed with error %s",
__FUNCTION__, strerror(errno));
}
close(connectedNode);
} else {
ALOGD("%s: /sys/class/graphics/fb%d/connected could not be opened : %s",
__FUNCTION__, mFbNum, strerror(errno));
}
return ret;
}
void HDMIDisplay::setPrimaryAttributes(uint32_t primaryWidth,
uint32_t primaryHeight) {
mPrimaryHeight = primaryHeight;
mPrimaryWidth = primaryWidth;
}
int HDMIDisplay::setActiveConfig(int newConfig) {
if(newConfig < 0 || newConfig > mModeCount) {
ALOGE("%s Invalid configuration %d", __FUNCTION__, newConfig);
return -EINVAL;
}
// XXX: Currently, we only support a change in frame rate.
// We need to validate the new config before proceeding.
if (!isValidConfigChange(newConfig)) {
ALOGE("%s Invalid configuration %d", __FUNCTION__, newConfig);
return -EINVAL;
}
mCurrentMode = mEDIDModes[newConfig];
mActiveConfig = newConfig;
activateDisplay();
ALOGD("%s config(%d) mode(%d)", __FUNCTION__, mActiveConfig, mCurrentMode);
return 0;
}
static const char* getS3DStringFromMode(int s3dMode) {
const char* ret ;
switch(s3dMode) {
case HDMI_S3D_NONE:
ret = "None";
break;
case HDMI_S3D_SIDE_BY_SIDE:
ret = "SSH";
break;
case HDMI_S3D_TOP_AND_BOTTOM:
ret = "TAB";
break;
//FP (FramePacked) mode is not supported in the HAL
default:
ALOGD("%s: Unsupported s3d mode: %d", __FUNCTION__, s3dMode);
ret = NULL;
}
return ret;
}
bool HDMIDisplay::isS3DModeSupported(int s3dMode) {
if(s3dMode == HDMI_S3D_NONE)
return true;
char s3dEdidStr[PAGE_SIZE] = {'\0'};
const char *s3dModeString = getS3DStringFromMode(s3dMode);
if(s3dModeString == NULL)
return false;
int s3dEdidNode = openDeviceNode("edid_3d_modes", O_RDONLY);
if(s3dEdidNode >= 0) {
ssize_t len = read(s3dEdidNode, s3dEdidStr, sizeof(s3dEdidStr)-1);
if (len > 0) {
ALOGI("%s: s3dEdidStr: %s mCurrentMode:%d", __FUNCTION__,
s3dEdidStr, mCurrentMode);
//Three level inception!
//The string looks like 16=SSH,4=FP:TAB:SSH,5=FP:SSH,32=FP:TAB:SSH
char *saveptr_l1, *saveptr_l2, *saveptr_l3;
char *l1, *l2, *l3;
int mode = 0;
l1 = strtok_r(s3dEdidStr,",", &saveptr_l1);
while (l1 != NULL) {
l2 = strtok_r(l1, "=", &saveptr_l2);
if (l2 != NULL)
mode = atoi(l2);
while (l2 != NULL) {
if (mode != mCurrentMode) {
break;
}
l3 = strtok_r(l2, ":", &saveptr_l3);
while (l3 != NULL) {
if (strncmp(l3, s3dModeString,
strlen(s3dModeString)) == 0) {
close(s3dEdidNode);
return true;
}
l3 = strtok_r(NULL, ":", &saveptr_l3);
}
l2 = strtok_r(NULL, "=", &saveptr_l2);
}
l1 = strtok_r(NULL, ",", &saveptr_l1);
}
}
} else {
ALOGI("%s: /sys/class/graphics/fb%d/edid_3d_modes could not be opened : %s",
__FUNCTION__, mFbNum, strerror(errno));
}
close(s3dEdidNode);
return false;
}
bool HDMIDisplay::writeS3DMode(int s3dMode) {
bool ret = true;
if(mFbNum != -1) {
int hdmiS3DModeFile = openDeviceNode("s3d_mode", O_RDWR);
if(hdmiS3DModeFile >=0 ) {
char curModeStr[PROPERTY_VALUE_MAX];
int currentS3DMode = -1;
size_t len = read(hdmiS3DModeFile, curModeStr, sizeof(curModeStr) - 1);
if(len > 0) {
currentS3DMode = atoi(curModeStr);
} else {
ret = false;
ALOGE("%s: Failed to read s3d_mode", __FUNCTION__);
}
if (currentS3DMode >=0 && currentS3DMode != s3dMode) {
ssize_t err = -1;
ALOGD_IF(DEBUG, "%s: mode = %d",
__FUNCTION__, s3dMode);
char mode[PROPERTY_VALUE_MAX];
snprintf(mode,sizeof(mode),"%d",s3dMode);
err = write(hdmiS3DModeFile, mode, sizeof(mode));
if (err <= 0) {
ALOGE("%s: file write failed 's3d_mode'", __FUNCTION__);
ret = false;
}
}
close(hdmiS3DModeFile);
}
}
return ret;
}
bool HDMIDisplay::configure3D(int s3dMode) {
if(isS3DModeSupported(s3dMode)) {
if(!writeS3DMode(s3dMode))
return false;
} else {
ALOGE("%s: 3D mode: %d is not supported", __FUNCTION__, s3dMode);
return false;
}
return true;
}
// returns false if the xres or yres of the new config do
// not match the current config
bool HDMIDisplay::isValidConfigChange(int newConfig) {
int newMode = mEDIDModes[newConfig];
uint32_t width = 0, height = 0, refresh = 0, fps = 0;
getAttrForConfig(newConfig, width, height, refresh, fps);
return ((mXres == width) && (mYres == height)) || mEnableResolutionChange;
}
int HDMIDisplay::getModeIndex(int mode) {
int modeIndex = -1;
for(int i = 0; i < mModeCount; i++) {
if(mode == mEDIDModes[i]) {
modeIndex = i;
break;
}
}
return modeIndex;
}
int HDMIDisplay::getAttrForConfig(int config, uint32_t& xres,
uint32_t& yres, uint32_t& refresh, uint32_t& fps) const {
if(config < 0 || config > mModeCount) {
ALOGE("%s Invalid configuration %d", __FUNCTION__, config);
return -EINVAL;
}
xres = mDisplayConfigs[config].active_h;
yres = mDisplayConfigs[config].active_v;
fps = (mDisplayConfigs[config].refresh_rate / 1000);
refresh = (uint32_t) 1000000000l / fps;
ALOGD_IF(DEBUG, "%s xres(%d) yres(%d) fps(%d) refresh(%d)", __FUNCTION__,
xres, yres, fps, refresh);
return 0;
}
int HDMIDisplay::getDisplayConfigs(uint32_t* configs,
size_t* numConfigs) const {
if (*numConfigs <= 0) {
ALOGE("%s Invalid number of configs (%d)", __FUNCTION__, *numConfigs);
return -EINVAL;
}
*numConfigs = mModeCount;
for (int configIndex = 0; configIndex < mModeCount; configIndex++) {
configs[configIndex] = (uint32_t)configIndex;
}
return 0;
}
};

View File

@@ -1,121 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 2012-2015, The Linux Foundation. All rights reserved.
*
* Not a Contribution, Apache license notifications and license are
* retained for attribution purposes only.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef HWC_HDMI_DISPLAY_H
#define HWC_HDMI_DISPLAY_H
#include <linux/fb.h>
#include <video/msm_hdmi_modes.h>
struct msm_hdmi_mode_timing_info;
namespace qhwc {
//Type of scanning of EDID(Video Capability Data Block)
enum hdmi_scansupport_type {
HDMI_SCAN_NOT_SUPPORTED = 0,
HDMI_SCAN_ALWAYS_OVERSCANED = 1,
HDMI_SCAN_ALWAYS_UNDERSCANED = 2,
HDMI_SCAN_BOTH_SUPPORTED = 3
};
class HDMIDisplay
{
public:
HDMIDisplay();
~HDMIDisplay();
void setHPD(uint32_t startEnd);
void setActionSafeDimension(int w, int h);
bool isCEUnderscanSupported() { return mUnderscanSupported; }
int configure();
void getAttributes(uint32_t& width, uint32_t& height);
int teardown();
uint32_t getWidth() const { return mXres; };
uint32_t getHeight() const { return mYres; };
uint32_t getVsyncPeriod() const { return mVsyncPeriod; };
int getFd() const { return mFd; };
bool getMDPScalingMode() const { return mMDPScalingMode; }
void activateDisplay();
/* Returns true if HDMI is the PRIMARY display device*/
bool isHDMIPrimaryDisplay();
int getConnectedState();
/* when HDMI is an EXTERNAL display, PRIMARY display attributes are needed
for scaling mode */
void setPrimaryAttributes(uint32_t primaryWidth, uint32_t primaryHeight);
int getActiveConfig() const { return mActiveConfig; };
int setActiveConfig(int newConfig);
int getAttrForConfig(int config, uint32_t& xres,
uint32_t& yres, uint32_t& refresh, uint32_t& fps) const;
int getDisplayConfigs(uint32_t* configs, size_t* numConfigs) const;
bool configure3D(int s3dMode);
bool isS3DModeSupported(int s3dMode);
private:
int getModeCount() const;
void setSPDInfo(const char* node, const char* property);
void readCEUnderscanInfo();
bool readResolution();
int parseResolution(char* edidMode);
bool openFrameBuffer();
bool closeFrameBuffer();
bool writeHPDOption(int userOption) const;
bool isValidMode(int mode);
int getModeOrder(int mode);
int getUserConfig();
int getBestConfig();
bool isInterlacedMode(int mode);
void resetInfo();
void setAttributes();
int openDeviceNode(const char* node, int fileMode) const;
int getModeIndex(int mode);
bool isValidConfigChange(int newConfig);
void requestNewPage(int pageNumber);
void readConfigs();
bool readResFile(char* configBuffer);
bool writeS3DMode(int s3dMode);
int mFd;
int mFbNum;
// mCurrentMode is the HDMI video format that corresponds to the mEDIDMode
// entry referenced by mActiveConfig
int mCurrentMode;
// mActiveConfig is the index correponding to the currently active mode for
// the HDMI display. It basically indexes the mEDIDMode array
int mActiveConfig;
// mEDIDModes contains a list of HDMI video formats (modes) supported by the
// HDMI display
int mEDIDModes[HDMI_VFRMT_MAX];
int mModeCount;
fb_var_screeninfo mVInfo;
// Holds all the HDMI modes and timing info supported by driver
msm_hdmi_mode_timing_info *mDisplayConfigs;
uint32_t mXres, mYres, mVsyncPeriod, mPrimaryWidth, mPrimaryHeight;
bool mMDPScalingMode;
bool mUnderscanSupported;
// Downscale feature switch, set via system property
// sys.hwc.mdp_downscale_enabled
bool mMDPDownscaleEnabled;
bool mEnableResolutionChange;
int mDisplayId;
};
}; //qhwc
// ---------------------------------------------------------------------------
#endif //HWC_HDMI_DISPLAY_H

View File

@@ -1,62 +0,0 @@
LOCAL_PATH := $(call my-dir)
include $(LOCAL_PATH)/../common.mk
include $(CLEAR_VARS)
LOCAL_MODULE := hwcomposer.$(TARGET_BOARD_PLATFORM)
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes) \
$(TOP)/external/skia/include/core \
$(TOP)/external/skia/include/images
ifeq ($(strip $(TARGET_USES_QCOM_DISPLAY_PP)),true)
LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/qdcm/inc \
$(TARGET_OUT_HEADERS)/common/inc \
$(TARGET_OUT_HEADERS)/pp/inc
endif
LOCAL_SHARED_LIBRARIES := $(common_libs) libEGL liboverlay \
libhdmi libqdutils libhardware_legacy \
libdl libmemalloc libqservice libsync \
libbinder libmedia
LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdhwcomposer\"
ifeq ($(TARGET_USES_QCOM_BSP),true)
LOCAL_SHARED_LIBRARIES += libskia
ifeq ($(GET_FRAMEBUFFER_FORMAT_FROM_HWC),true)
LOCAL_CFLAGS += -DGET_FRAMEBUFFER_FORMAT_FROM_HWC
endif
endif #TARGET_USES_QCOM_BSP
#Enable Dynamic FPS if PHASE_OFFSET is not set
ifeq ($(VSYNC_EVENT_PHASE_OFFSET_NS),)
LOCAL_CFLAGS += -DDYNAMIC_FPS
endif
LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
LOCAL_SRC_FILES := hwc.cpp \
hwc_utils.cpp \
hwc_uevents.cpp \
hwc_vsync.cpp \
hwc_fbupdate.cpp \
hwc_mdpcomp.cpp \
hwc_copybit.cpp \
hwc_qclient.cpp \
hwc_dump_layers.cpp \
hwc_ad.cpp \
hwc_virtual.cpp
TARGET_MIGRATE_QDCM_LIST := msm8909
TARGET_MIGRATE_QDCM := $(call is-board-platform-in-list,$(TARGET_MIGRATE_QDCM_LIST))
ifeq ($(TARGET_MIGRATE_QDCM), true)
ifeq ($(strip $(TARGET_USES_QCOM_DISPLAY_PP)),true)
LOCAL_SRC_FILES += hwc_qdcm.cpp
else
LOCAL_SRC_FILES += hwc_qdcm_legacy.cpp
endif
else
LOCAL_SRC_FILES += hwc_qdcm_legacy.cpp
endif
include $(BUILD_SHARED_LIBRARY)

File diff suppressed because it is too large Load Diff

View File

@@ -1,278 +0,0 @@
/*
* Copyright (c) 2013-2014 The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <unistd.h>
#include <overlay.h>
#include <overlayUtils.h>
#include <overlayWriteback.h>
#include <mdp_version.h>
#include "hwc_ad.h"
#include "hwc_utils.h"
#define DEBUG 0
using namespace overlay;
using namespace overlay::utils;
namespace qhwc {
//Helper to write data to ad node
static void adWrite(const int& value) {
const int wbFbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
char wbFbPath[256];
snprintf (wbFbPath, sizeof(wbFbPath),
"/sys/class/graphics/fb%d/ad", wbFbNum);
int adFd = open(wbFbPath, O_WRONLY);
if(adFd >= 0) {
char opStr[4] = "";
snprintf(opStr, sizeof(opStr), "%d", value);
ssize_t ret = write(adFd, opStr, strlen(opStr));
if(ret < 0) {
ALOGE("%s: Failed to write %d with error %s",
__func__, value, strerror(errno));
} else if (ret == 0){
ALOGE("%s Nothing written to ad", __func__);
} else {
ALOGD_IF(DEBUG, "%s: Wrote %d to ad", __func__, value);
}
close(adFd);
} else {
ALOGE("%s: Failed to open /sys/class/graphics/fb%d/ad with error %s",
__func__, wbFbNum, strerror(errno));
}
}
//Helper to read data from ad node
static int adRead() {
const int wbFbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
int ret = -1;
char wbFbPath[256];
snprintf (wbFbPath, sizeof(wbFbPath),
"/sys/class/graphics/fb%d/ad", wbFbNum);
int adFd = open(wbFbPath, O_RDONLY);
if(adFd >= 0) {
char opStr[4];
ssize_t bytesRead = read(adFd, opStr, sizeof(opStr) - 1);
if(bytesRead > 0) {
opStr[bytesRead] = '\0';
//Should return -1, 0 or 1
ret = atoi(opStr);
ALOGD_IF(DEBUG, "%s: Read %d from ad", __func__, ret);
} else if(bytesRead == 0) {
ALOGE("%s: ad node empty", __func__);
} else {
ALOGE("%s: Read from ad node failed with error %s", __func__,
strerror(errno));
}
close(adFd);
} else {
ALOGD("%s: /sys/class/graphics/fb%d/ad could not be opened : %s",
__func__, wbFbNum, strerror(errno));
}
return ret;
}
AssertiveDisplay::AssertiveDisplay(hwc_context_t *ctx) :
mTurnedOff(true), mFeatureEnabled(false),
mDest(overlay::utils::OV_INVALID)
{
//Values in ad node:
//-1 means feature is disabled on device
// 0 means feature exists but turned off, will be turned on by hwc
// 1 means feature is turned on by hwc
// Plus, we do this feature only on split primary displays.
// Plus, we do this feature only if ro.qcom.ad=2
char property[PROPERTY_VALUE_MAX];
const int ENABLED = 2;
int val = 0;
if(property_get("ro.qcom.ad", property, "0") > 0) {
val = atoi(property);
}
if(adRead() >= 0 && isDisplaySplit(ctx, HWC_DISPLAY_PRIMARY) &&
val == ENABLED) {
ALOGD_IF(DEBUG, "Assertive display feature supported");
mFeatureEnabled = true;
// If feature exists but is turned off, set mTurnedOff to true
mTurnedOff = adRead() > 0 ? false : true;
}
}
void AssertiveDisplay::markDoable(hwc_context_t *ctx,
const hwc_display_contents_1_t* list) {
mDoable = false;
if(mFeatureEnabled &&
!isSecondaryConnected(ctx) &&
ctx->listStats[HWC_DISPLAY_PRIMARY].yuvCount == 1) {
int nYuvIndex = ctx->listStats[HWC_DISPLAY_PRIMARY].yuvIndices[0];
const hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex];
private_handle_t *hnd = (private_handle_t *)layer->handle;
qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance();
if(hnd && hnd->width <= (int) mdpHw.getMaxPipeWidth()) {
mDoable = true;
}
}
}
void AssertiveDisplay::turnOffAD() {
if(mFeatureEnabled) {
if(!mTurnedOff) {
const int off = 0;
adWrite(off);
mTurnedOff = true;
}
}
mDoable = false;
}
bool AssertiveDisplay::prepare(hwc_context_t *ctx,
const hwc_rect_t& crop,
const Whf& whf,
const private_handle_t *hnd) {
if(!isDoable()) {
//Cleanup one time during this switch
turnOffAD();
return false;
}
Overlay::PipeSpecs pipeSpecs;
pipeSpecs.formatClass = Overlay::FORMAT_YUV;
pipeSpecs.dpy = overlay::Overlay::DPY_WRITEBACK;
pipeSpecs.fb = false;
ovutils::eDest dest = ctx->mOverlay->getPipe(pipeSpecs);
if(dest == OV_INVALID) {
ALOGE("%s failed: No VG pipe available", __func__);
mDoable = false;
return false;
}
overlay::Writeback *wb = overlay::Writeback::getInstance();
//Set Security flag on writeback
if(isSecureBuffer(hnd)) {
if(!wb->setSecure(isSecureBuffer(hnd))) {
ALOGE("Failure in setting WB secure flag for ad");
return false;
}
}
if(!wb->configureDpyInfo(hnd->width, hnd->height)) {
ALOGE("%s: config display failed", __func__);
mDoable = false;
return false;
}
int tmpW, tmpH;
size_t size;
int format = ovutils::getHALFormat(wb->getOutputFormat());
if(format < 0) {
ALOGE("%s invalid format %d", __func__, format);
mDoable = false;
return false;
}
size = getBufferSizeAndDimensions(hnd->width, hnd->height,
format, tmpW, tmpH);
if(!wb->configureMemory((uint32_t)size)) {
ALOGE("%s: config memory failed", __func__);
mDoable = false;
return false;
}
eMdpFlags mdpFlags = OV_MDP_FLAGS_NONE;
if(isSecureBuffer(hnd)) {
ovutils::setMdpFlags(mdpFlags,
ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
}
PipeArgs parg(mdpFlags, whf, ZORDER_0,
ROT_FLAGS_NONE);
hwc_rect_t dst = crop; //input same as output
if(configMdp(ctx->mOverlay, parg, OVERLAY_TRANSFORM_0, crop, dst, NULL,
dest) < 0) {
ALOGE("%s: configMdp failed", __func__);
mDoable = false;
return false;
}
mDest = dest;
int wbFd = wb->getFbFd();
if(mFeatureEnabled && wbFd >= 0 &&
!ctx->mOverlay->validateAndSet(overlay::Overlay::DPY_WRITEBACK, wbFd))
{
ALOGE("%s: Failed to validate and set overlay for dpy %d"
,__FUNCTION__, overlay::Overlay::DPY_WRITEBACK);
turnOffAD();
return false;
}
// Only turn on AD if there are no errors during configuration stage
// and if it was previously in OFF state.
if(mFeatureEnabled && mTurnedOff) {
//write to sysfs, one time during this switch
const int on = 1;
adWrite(on);
mTurnedOff = false;
}
return true;
}
bool AssertiveDisplay::draw(hwc_context_t *ctx, int fd, uint32_t offset) {
if(!isDoable()) {
return false;
}
if (!ctx->mOverlay->queueBuffer(fd, offset, mDest)) {
ALOGE("%s: queueBuffer failed", __func__);
return false;
}
overlay::Writeback *wb = overlay::Writeback::getInstance();
if(!wb->writeSync()) {
return false;
}
return true;
}
int AssertiveDisplay::getDstFd() const {
overlay::Writeback *wb = overlay::Writeback::getInstance();
return wb->getDstFd();
}
uint32_t AssertiveDisplay::getDstOffset() const {
overlay::Writeback *wb = overlay::Writeback::getInstance();
return wb->getOffset();
}
}

View File

@@ -1,66 +0,0 @@
/*
* Copyright (c) 2013 The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef HWC_AD_H
#define HWC_AD_H
#include <overlayUtils.h>
#include <hwc_utils.h>
struct hwc_context_t;
namespace qhwc {
class AssertiveDisplay {
public:
AssertiveDisplay(hwc_context_t *ctx);
void markDoable(hwc_context_t *ctx, const hwc_display_contents_1_t* list);
bool prepare(hwc_context_t *ctx, const hwc_rect_t& crop,
const overlay::utils::Whf& whf,
const private_handle_t *hnd);
bool draw(hwc_context_t *ctx, int fd, uint32_t offset);
//Resets a few members on each draw round
void reset() { mDoable = false;
mDest = overlay::utils::OV_INVALID;
}
bool isDoable() const { return mDoable; }
int getDstFd() const;
uint32_t getDstOffset() const;
private:
bool mDoable;
bool mTurnedOff;
//State of feature existence on certain devices and configs.
bool mFeatureEnabled;
overlay::utils::eDest mDest;
void turnOffAD();
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,147 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
*
* Not a Contribution, Apache license notifications and license are retained
* for attribution purposes only.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef HWC_COPYBIT_H
#define HWC_COPYBIT_H
#include "hwc_utils.h"
#define NUM_RENDER_BUFFERS 3
//These scaling factors are specific for MDP3. Normally scaling factor
//is only 4, but copybit will create temp buffer to let it run through
//twice
#define MAX_SCALE_FACTOR 16
#define MIN_SCALE_FACTOR 0.0625
#define MAX_LAYERS_FOR_ABC 2
#define INVALID_DIMENSION -1
#define NO_UPDATING_LAYER -2
namespace qhwc {
class CopyBit {
public:
CopyBit(hwc_context_t *ctx, const int& dpy);
~CopyBit();
// API to get copybit engine(non static)
struct copybit_device_t *getCopyBitDevice();
//Sets up members and prepares copybit if conditions are met
bool prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list,
int dpy);
//Draws layer if the layer is set for copybit in prepare
bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list,
int dpy, int* fd);
// resets the values
void reset();
private_handle_t * getCurrentRenderBuffer();
void setReleaseFd(int fd);
bool prepareOverlap(hwc_context_t *ctx, hwc_display_contents_1_t *list);
int drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t *list);
private:
/* cached data */
struct LayerCache {
int layerCount;
buffer_handle_t hnd[MAX_NUM_APP_LAYERS];
hwc_rect_t displayFrame[MAX_NUM_APP_LAYERS];
bool drop[MAX_NUM_APP_LAYERS];
/* c'tor */
LayerCache();
/* clear caching info*/
void reset();
void updateCounts(hwc_context_t *ctx, hwc_display_contents_1_t *list,
int dpy);
};
/* framebuffer cache*/
struct FbCache {
hwc_rect_t FbdirtyRect[NUM_RENDER_BUFFERS];
hwc_rect_t FbdisplayRect[NUM_RENDER_BUFFERS];
int FbIndex;
FbCache();
void reset();
void insertAndUpdateFbCache(hwc_rect_t dirtyRect,
hwc_rect_t displayRect);
int getUnchangedFbDRCount(hwc_rect_t dirtyRect,
hwc_rect_t displayRect);
};
// holds the copybit device
struct copybit_device_t *mEngine;
bool drawUsingAppBufferComposition(hwc_context_t *ctx,
hwc_display_contents_1_t *list,
int dpy, int *fd);
// Helper functions for copybit composition
int drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer,
private_handle_t *renderBuffer, bool isFG);
// Helper function to draw copybit layer for PTOR comp
int drawRectUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer,
private_handle_t *renderBuffer, hwc_rect_t overlap,
hwc_rect_t destRect);
int fillColorUsingCopybit(hwc_layer_1_t *layer,
private_handle_t *renderBuffer);
bool canUseCopybitForYUV (hwc_context_t *ctx);
bool canUseCopybitForRGB (hwc_context_t *ctx,
hwc_display_contents_1_t *list, int dpy);
bool validateParams (hwc_context_t *ctx,
const hwc_display_contents_1_t *list);
//Flags if this feature is on.
bool mIsModeOn;
// flag that indicates whether CopyBit composition is enabled for this cycle
bool mCopyBitDraw;
unsigned int getRGBRenderingArea (const hwc_context_t *ctx,
const hwc_display_contents_1_t *list);
void getLayerResolution(const hwc_layer_1_t* layer,
unsigned int &width, unsigned int& height);
int allocRenderBuffers(int w, int h, int f);
void freeRenderBuffers();
int clear (private_handle_t* hnd, hwc_rect_t& rect);
private_handle_t* mRenderBuffer[NUM_RENDER_BUFFERS];
// Index of the current intermediate render buffer
int mCurRenderBufferIndex;
// Release FDs of the intermediate render buffer
int mRelFd[NUM_RENDER_BUFFERS];
//Dynamic composition threshold for deciding copybit usage.
double mDynThreshold;
bool mSwapRectEnable;
int mAlignedWidth;
int mAlignedHeight;
int mSwapRect;
LayerCache mLayerCache;
FbCache mFbCache;
hwc_rect_t mDirtyRect;
bool prepareSwapRect(hwc_context_t *ctx, hwc_display_contents_1_t *list,
int dpy);
bool isLayerChanging(hwc_context_t *ctx,
hwc_display_contents_1_t *list, int k);
bool isSmartBlitPossible(const hwc_display_contents_1_t *list);
};
}; //namespace qhwc
#endif //HWC_COPYBIT_H

View File

@@ -1,462 +0,0 @@
/*
* Copyright (c) 2012-2014, Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LOG_TAG
#define LOG_TAG "qsfdump"
#endif
#define LOG_NDEBUG 0
#include <hwc_utils.h>
#include <hwc_dump_layers.h>
#include <cutils/log.h>
#include <sys/stat.h>
#include <comptype.h>
#ifdef QCOM_BSP
// Ignore Wconversion errors for external headers
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
#include <SkBitmap.h>
#include <SkImageEncoder.h>
#pragma GCC diagnostic pop
#endif
#ifdef STDC_FORMAT_MACROS
#include <inttypes.h>
#endif
namespace qhwc {
// MAX_ALLOWED_FRAMEDUMPS must be capped to (LONG_MAX - 1)
// 60fps => 216000 frames per hour
// Below setting of 216000 * 24 * 7 => 1 week or 168 hours of capture.
enum {
MAX_ALLOWED_FRAMEDUMPS = (216000 * 24 * 7)
};
bool HwcDebug::sDumpEnable = false;
HwcDebug::HwcDebug(uint32_t dpy):
mDumpCntLimRaw(0),
mDumpCntrRaw(1),
mDumpCntLimPng(0),
mDumpCntrPng(1),
mDpy(dpy) {
char dumpPropStr[PROPERTY_VALUE_MAX];
if(mDpy) {
strlcpy(mDisplayName, "external", sizeof(mDisplayName));
} else {
strlcpy(mDisplayName, "primary", sizeof(mDisplayName));
}
snprintf(mDumpPropKeyDisplayType, sizeof(mDumpPropKeyDisplayType),
"debug.sf.dump.%s", (char *)mDisplayName);
if ((property_get("debug.sf.dump.enable", dumpPropStr, NULL) > 0)) {
if(!strncmp(dumpPropStr, "true", strlen("true"))) {
sDumpEnable = true;
}
}
}
void HwcDebug::dumpLayers(hwc_display_contents_1_t* list)
{
// Check need for dumping layers for debugging.
if (UNLIKELY(sDumpEnable) && UNLIKELY(needToDumpLayers()) && LIKELY(list)) {
logHwcProps(list->flags);
for (size_t i = 0; i < list->numHwLayers; i++) {
logLayer(i, list->hwLayers);
dumpLayer(i, list->hwLayers);
}
}
}
bool HwcDebug::needToDumpLayers()
{
bool bDumpLayer = false;
char dumpPropStr[PROPERTY_VALUE_MAX];
// Enable primary dump and disable external dump by default.
bool bDumpEnable = !mDpy;
time_t timeNow;
tm dumpTime;
// Override the bDumpEnable based on the property value, if the property
// is present in the build.prop file.
if ((property_get(mDumpPropKeyDisplayType, dumpPropStr, NULL) > 0)) {
if(!strncmp(dumpPropStr, "true", strlen("true")))
bDumpEnable = true;
else
bDumpEnable = false;
}
if (false == bDumpEnable)
return false;
time(&timeNow);
localtime_r(&timeNow, &dumpTime);
if ((property_get("debug.sf.dump.png", dumpPropStr, NULL) > 0) &&
(strncmp(dumpPropStr, mDumpPropStrPng, PROPERTY_VALUE_MAX - 1))) {
// Strings exist & not equal implies it has changed, so trigger a dump
strlcpy(mDumpPropStrPng, dumpPropStr, sizeof(mDumpPropStrPng));
mDumpCntLimPng = atoi(dumpPropStr);
if (mDumpCntLimPng > MAX_ALLOWED_FRAMEDUMPS) {
ALOGW("Warning: Using debug.sf.dump.png %d (= max)",
MAX_ALLOWED_FRAMEDUMPS);
mDumpCntLimPng = MAX_ALLOWED_FRAMEDUMPS;
}
mDumpCntLimPng = (mDumpCntLimPng < 0) ? 0: mDumpCntLimPng;
if (mDumpCntLimPng) {
snprintf(mDumpDirPng, sizeof(mDumpDirPng),
"/data/misc/display/sfdump.png.%04d.%02d.%02d.%02d.%02d.%02d",
dumpTime.tm_year + 1900, dumpTime.tm_mon + 1,
dumpTime.tm_mday, dumpTime.tm_hour,
dumpTime.tm_min, dumpTime.tm_sec);
if (0 == mkdir(mDumpDirPng, 0777))
mDumpCntrPng = 0;
else {
ALOGE("Error: %s. Failed to create sfdump directory: %s",
strerror(errno), mDumpDirPng);
mDumpCntrPng = mDumpCntLimPng + 1;
}
}
}
if (mDumpCntrPng <= mDumpCntLimPng)
mDumpCntrPng++;
if ((property_get("debug.sf.dump", dumpPropStr, NULL) > 0) &&
(strncmp(dumpPropStr, mDumpPropStrRaw, PROPERTY_VALUE_MAX - 1))) {
// Strings exist & not equal implies it has changed, so trigger a dump
strlcpy(mDumpPropStrRaw, dumpPropStr, sizeof(mDumpPropStrRaw));
mDumpCntLimRaw = atoi(dumpPropStr);
if (mDumpCntLimRaw > MAX_ALLOWED_FRAMEDUMPS) {
ALOGW("Warning: Using debug.sf.dump %d (= max)",
MAX_ALLOWED_FRAMEDUMPS);
mDumpCntLimRaw = MAX_ALLOWED_FRAMEDUMPS;
}
mDumpCntLimRaw = (mDumpCntLimRaw < 0) ? 0: mDumpCntLimRaw;
if (mDumpCntLimRaw) {
snprintf(mDumpDirRaw, sizeof(mDumpDirRaw),
"/data/misc/display/sfdump.raw.%04d.%02d.%02d.%02d.%02d.%02d",
dumpTime.tm_year + 1900, dumpTime.tm_mon + 1,
dumpTime.tm_mday, dumpTime.tm_hour,
dumpTime.tm_min, dumpTime.tm_sec);
if (0 == mkdir(mDumpDirRaw, 0777))
mDumpCntrRaw = 0;
else {
ALOGE("Error: %s. Failed to create sfdump directory: %s",
strerror(errno), mDumpDirRaw);
mDumpCntrRaw = mDumpCntLimRaw + 1;
}
}
}
if (mDumpCntrRaw <= mDumpCntLimRaw)
mDumpCntrRaw++;
bDumpLayer = (mDumpCntLimPng || mDumpCntLimRaw)? true : false;
return bDumpLayer;
}
void HwcDebug::logHwcProps(uint32_t listFlags)
{
static int hwcModuleCompType = -1;
static int sMdpCompMaxLayers = 0;
static String8 hwcModuleCompTypeLog("");
if (-1 == hwcModuleCompType) {
// One time stuff
char mdpCompPropStr[PROPERTY_VALUE_MAX];
if (property_get("debug.mdpcomp.maxlayer", mdpCompPropStr, NULL) > 0) {
sMdpCompMaxLayers = atoi(mdpCompPropStr);
}
hwcModuleCompType =
qdutils::QCCompositionType::getInstance().getCompositionType();
hwcModuleCompTypeLog.appendFormat("%s%s%s%s%s%s",
// Is hwc module composition type now a bit-field?!
(hwcModuleCompType == qdutils::COMPOSITION_TYPE_GPU)?
"[GPU]": "",
(hwcModuleCompType & qdutils::COMPOSITION_TYPE_MDP)?
"[MDP]": "",
(hwcModuleCompType & qdutils::COMPOSITION_TYPE_C2D)?
"[C2D]": "",
(hwcModuleCompType & qdutils::COMPOSITION_TYPE_CPU)?
"[CPU]": "",
(hwcModuleCompType & qdutils::COMPOSITION_TYPE_DYN)?
"[DYN]": "",
(hwcModuleCompType >= (qdutils::COMPOSITION_TYPE_DYN << 1))?
"[???]": "");
}
ALOGI("Display[%s] Layer[*] %s-HwcModuleCompType, %d-layer MdpComp %s",
mDisplayName, hwcModuleCompTypeLog.string(), sMdpCompMaxLayers,
(listFlags & HWC_GEOMETRY_CHANGED)? "[HwcList Geometry Changed]": "");
}
void HwcDebug::logLayer(size_t layerIndex, hwc_layer_1_t hwLayers[])
{
if (NULL == hwLayers) {
ALOGE("Display[%s] Layer[%zu] Error. No hwc layers to log.",
mDisplayName, layerIndex);
return;
}
hwc_layer_1_t *layer = &hwLayers[layerIndex];
hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
hwc_rect_t displayFrame = layer->displayFrame;
size_t numHwcRects = layer->visibleRegionScreen.numRects;
hwc_rect_t const *hwcRects = layer->visibleRegionScreen.rects;
private_handle_t *hnd = (private_handle_t *)layer->handle;
char pixFormatStr[32] = "None";
String8 hwcVisRegsScrLog("[None]");
for (size_t i = 0 ; (hwcRects && (i < numHwcRects)); i++) {
if (0 == i)
hwcVisRegsScrLog.clear();
hwcVisRegsScrLog.appendFormat("[%dl, %dt, %dr, %db]",
hwcRects[i].left, hwcRects[i].top,
hwcRects[i].right, hwcRects[i].bottom);
}
if (hnd)
getHalPixelFormatStr(hnd->format, pixFormatStr);
// Log Line 1
ALOGI("Display[%s] Layer[%zu] SrcBuff[%dx%d] SrcCrop[%dl, %dt, %dr, %db] "
"DispFrame[%dl, %dt, %dr, %db] VisRegsScr%s", mDisplayName, layerIndex,
(hnd)? getWidth(hnd) : -1, (hnd)? getHeight(hnd) : -1,
sourceCrop.left, sourceCrop.top,
sourceCrop.right, sourceCrop.bottom,
displayFrame.left, displayFrame.top,
displayFrame.right, displayFrame.bottom,
hwcVisRegsScrLog.string());
// Log Line 2
ALOGI("Display[%s] Layer[%zu] LayerCompType = %s, Format = %s, "
"Orientation = %s, Flags = %s%s%s, Hints = %s%s%s, "
"Blending = %s%s%s", mDisplayName, layerIndex,
(layer->compositionType == HWC_FRAMEBUFFER)? "Framebuffer(GPU)":
(layer->compositionType == HWC_OVERLAY)? "Overlay":
(layer->compositionType == HWC_BACKGROUND)? "Background":"???",
pixFormatStr,
(layer->transform == 0)? "ROT_0":
(layer->transform == HWC_TRANSFORM_FLIP_H)? "FLIP_H":
(layer->transform == HWC_TRANSFORM_FLIP_V)? "FLIP_V":
(layer->transform == HWC_TRANSFORM_ROT_90)? "ROT_90":
"ROT_INVALID",
(layer->flags)? "": "[None]",
(layer->flags & HWC_SKIP_LAYER)? "[Skip layer]":"",
(layer->flags & qhwc::HWC_MDPCOMP)? "[MDP Comp]":"",
(layer->hints)? "":"[None]",
(layer->hints & HWC_HINT_TRIPLE_BUFFER)? "[Triple Buffer]":"",
(layer->hints & HWC_HINT_CLEAR_FB)? "[Clear FB]":"",
(layer->blending == HWC_BLENDING_NONE)? "[None]":"",
(layer->blending == HWC_BLENDING_PREMULT)? "[PreMult]":"",
(layer->blending == HWC_BLENDING_COVERAGE)? "[Coverage]":"");
}
void HwcDebug::dumpLayer(size_t layerIndex, hwc_layer_1_t hwLayers[])
{
char dumpLogStrPng[128] = "";
char dumpLogStrRaw[128] = "";
bool needDumpPng = (mDumpCntrPng <= mDumpCntLimPng)? true:false;
bool needDumpRaw = (mDumpCntrRaw <= mDumpCntLimRaw)? true:false;
if (needDumpPng) {
snprintf(dumpLogStrPng, sizeof(dumpLogStrPng),
"[png-dump-frame: %03d of %03d]", mDumpCntrPng,
mDumpCntLimPng);
}
if (needDumpRaw) {
snprintf(dumpLogStrRaw, sizeof(dumpLogStrRaw),
"[raw-dump-frame: %03d of %03d]", mDumpCntrRaw,
mDumpCntLimRaw);
}
if (!(needDumpPng || needDumpRaw))
return;
if (NULL == hwLayers) {
ALOGE("Display[%s] Layer[%zu] %s%s Error: No hwc layers to dump.",
mDisplayName, layerIndex, dumpLogStrRaw, dumpLogStrPng);
return;
}
hwc_layer_1_t *layer = &hwLayers[layerIndex];
private_handle_t *hnd = (private_handle_t *)layer->handle;
char pixFormatStr[32] = "None";
if (NULL == hnd) {
ALOGI("Display[%s] Layer[%zu] %s%s Skipping dump: Bufferless layer.",
mDisplayName, layerIndex, dumpLogStrRaw, dumpLogStrPng);
return;
}
getHalPixelFormatStr(hnd->format, pixFormatStr);
#ifdef QCOM_BSP
if (needDumpPng && hnd->base) {
bool bResult = false;
char dumpFilename[PATH_MAX];
SkBitmap *tempSkBmp = new SkBitmap();
SkColorType tempSkBmpColor = kUnknown_SkColorType;
snprintf(dumpFilename, sizeof(dumpFilename),
"%s/sfdump%03d.layer%zu.%s.png", mDumpDirPng,
mDumpCntrPng, layerIndex, mDisplayName);
switch (hnd->format) {
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_RGBX_8888:
tempSkBmpColor = kRGBA_8888_SkColorType;
break;
case HAL_PIXEL_FORMAT_BGRA_8888:
tempSkBmpColor = kBGRA_8888_SkColorType;
break;
case HAL_PIXEL_FORMAT_RGB_565:
tempSkBmpColor = kRGB_565_SkColorType;
break;
case HAL_PIXEL_FORMAT_RGBA_5551:
case HAL_PIXEL_FORMAT_RGBA_4444:
case HAL_PIXEL_FORMAT_RGB_888:
default:
tempSkBmpColor = kUnknown_SkColorType;
break;
}
if (kUnknown_SkColorType != tempSkBmpColor) {
tempSkBmp->setInfo(SkImageInfo::Make(getWidth(hnd), getHeight(hnd),
tempSkBmpColor, kIgnore_SkAlphaType), 0);
tempSkBmp->setPixels((void*)hnd->base);
bResult = SkImageEncoder::EncodeFile(dumpFilename,
*tempSkBmp, SkImageEncoder::kPNG_Type, 100);
ALOGI("Display[%s] Layer[%zu] %s Dump to %s: %s",
mDisplayName, layerIndex, dumpLogStrPng,
dumpFilename, bResult ? "Success" : "Fail");
} else {
ALOGI("Display[%s] Layer[%zu] %s Skipping dump: Unsupported layer"
" format %s for png encoder",
mDisplayName, layerIndex, dumpLogStrPng, pixFormatStr);
}
delete tempSkBmp; // Calls SkBitmap::freePixels() internally.
}
#endif
if (needDumpRaw && hnd->base) {
char dumpFilename[PATH_MAX];
bool bResult = false;
snprintf(dumpFilename, sizeof(dumpFilename),
"%s/sfdump%03d.layer%zu.%dx%d.%s.%s.raw",
mDumpDirRaw, mDumpCntrRaw,
layerIndex, getWidth(hnd), getHeight(hnd),
pixFormatStr, mDisplayName);
FILE* fp = fopen(dumpFilename, "w+");
if (NULL != fp) {
bResult = (bool) fwrite((void*)hnd->base, hnd->size, 1, fp);
fclose(fp);
}
ALOGI("Display[%s] Layer[%zu] %s Dump to %s: %s",
mDisplayName, layerIndex, dumpLogStrRaw,
dumpFilename, bResult ? "Success" : "Fail");
}
}
void HwcDebug::getHalPixelFormatStr(int format, char pixFormatStr[])
{
if (!pixFormatStr)
return;
switch(format) {
case HAL_PIXEL_FORMAT_RGBA_8888:
strlcpy(pixFormatStr, "RGBA_8888", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_RGBX_8888:
strlcpy(pixFormatStr, "RGBX_8888", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_RGB_888:
strlcpy(pixFormatStr, "RGB_888", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_RGB_565:
strlcpy(pixFormatStr, "RGB_565", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_BGRA_8888:
strlcpy(pixFormatStr, "BGRA_8888", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_RGBA_5551:
strlcpy(pixFormatStr, "RGBA_5551", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_RGBA_4444:
strlcpy(pixFormatStr, "RGBA_4444", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_YV12:
strlcpy(pixFormatStr, "YV12", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
strlcpy(pixFormatStr, "YCbCr_422_SP_NV16", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
strlcpy(pixFormatStr, "YCrCb_420_SP_NV21", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_YCbCr_422_I:
strlcpy(pixFormatStr, "YCbCr_422_I_YUY2", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_YCrCb_422_I:
strlcpy(pixFormatStr, "YCrCb_422_I_YVYU", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
strlcpy(pixFormatStr, "NV12_ENCODEABLE", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
strlcpy(pixFormatStr, "YCbCr_420_SP_TILED_TILE_4x2",
sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_YCbCr_420_SP:
strlcpy(pixFormatStr, "YCbCr_420_SP", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
strlcpy(pixFormatStr, "YCrCb_420_SP_ADRENO", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_YCrCb_422_SP:
strlcpy(pixFormatStr, "YCrCb_422_SP", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_R_8:
strlcpy(pixFormatStr, "R_8", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_RG_88:
strlcpy(pixFormatStr, "RG_88", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_INTERLACE:
strlcpy(pixFormatStr, "INTERLACE", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
strlcpy(pixFormatStr, "YCbCr_420_SP_VENUS", sizeof(pixFormatStr));
break;
case HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS:
strlcpy(pixFormatStr, "YCrCb_420_SP_VENUS", sizeof(pixFormatStr));
break;
default:
size_t len = sizeof(pixFormatStr);
snprintf(pixFormatStr, len, "Unknown0x%X", format);
break;
}
}
} // namespace qhwc

View File

@@ -1,138 +0,0 @@
/*
* Copyright (c) 2012-2013, Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef HWC_DUMP_LAYERS_H
#define HWC_DUMP_LAYERS_H
#include <gralloc_priv.h>
#include <comptype.h>
#include <ui/Region.h>
#include <hardware/hwcomposer.h>
#include <utils/String8.h>
namespace qhwc {
class HwcDebug {
private:
// Using static variables for layer dumping since "property_set("debug.sf.dump",
// property)" does not work.
int mDumpCntLimRaw;
int mDumpCntrRaw;
char mDumpPropStrRaw[PROPERTY_VALUE_MAX];
char mDumpDirRaw[PATH_MAX];
int mDumpCntLimPng;
int mDumpCntrPng;
char mDumpPropStrPng[PROPERTY_VALUE_MAX];
char mDumpDirPng[PATH_MAX];
uint32_t mDpy;
char mDisplayName[PROPERTY_VALUE_MAX];
char mDumpPropKeyDisplayType[PROPERTY_KEY_MAX];
static bool sDumpEnable;
public:
HwcDebug(uint32_t dpy);
~HwcDebug() {};
/*
* Dump layers for debugging based on "debug.sf.dump*" system property.
* See needToDumpLayers() for usage.
*
* @param: list - The HWC layer-list to dump.
*
*/
void dumpLayers(hwc_display_contents_1_t* list);
/*
* Checks if layers need to be dumped based on system property "debug.sf.dump"
* for raw dumps and "debug.sf.dump.png" for png dumps.
*
* Note: Set "debug.sf.dump.primary" or "debug.sf.dump.external" as true
* in the device's /system/build.prop file to enable layer logging/capturing
* feature for primary or external respectively. The feature is disabled by
* default to avoid per-frame property_get() calls.
*
* To turn on layer dump, set "debug.sf.dump.enable" to true in build.prop.
* By default debug.sf.dump.primary will be set to true for user convenience.
*
* To turn on layer dump for primary, do,
* adb shell setprop debug.sf.dump.primary true
*
* To turn on layer dump for external, do,
* adb shell setprop debug.sf.dump.external true
*
* For example, to dump 25 frames in raw format, do,
* adb shell setprop debug.sf.dump 25
* Layers are dumped in a time-stamped location: /data/sfdump*.
*
* To dump 10 frames in png format, do,
* adb shell setprop debug.sf.dump.png 10
* To dump another 25 or so frames in raw format, do,
* adb shell setprop debug.sf.dump 26
*
* To turn off logcat logging of layer-info, set both properties to 0,
* adb shell setprop debug.sf.dump.png 0
* adb shell setprop debug.sf.dump 0
*
* @return: true if layers need to be dumped (or logcat-ed).
*/
bool needToDumpLayers();
/*
* Log a few per-frame hwc properties into logcat.
*
* @param: listFlags - Flags used in hwcomposer's list.
*
*/
void logHwcProps(uint32_t listFlags);
/*
* Log a layer's info into logcat.
*
* @param: layerIndex - Index of layer being dumped.
* @param: hwLayers - Address of hwc_layer_1_t to log and dump.
*
*/
void logLayer(size_t layerIndex, hwc_layer_1_t hwLayers[]);
/*
* Dumps a layer buffer into raw/png files.
*
* @param: layerIndex - Index of layer being dumped.
* @param: hwLayers - Address of hwc_layer_1_t to log and dump.
*
*/
void dumpLayer(size_t layerIndex, hwc_layer_1_t hwLayers[]);
void getHalPixelFormatStr(int format, char pixelformatstr[]);
};
} // namespace qhwc
#endif /* HWC_DUMP_LAYERS_H */

View File

@@ -1,604 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
*
* Not a Contribution, Apache license notifications and license are
* retained for attribution purposes only.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define DEBUG_FBUPDATE 0
#include <cutils/properties.h>
#include <gralloc_priv.h>
#include <overlay.h>
#include <overlayRotator.h>
#include "hwc_fbupdate.h"
#include "mdp_version.h"
#include <video/msm_hdmi_modes.h>
using namespace qdutils;
using namespace overlay;
using overlay::Rotator;
using namespace overlay::utils;
namespace qhwc {
namespace ovutils = overlay::utils;
IFBUpdate* IFBUpdate::getObject(hwc_context_t *ctx, const int& dpy) {
if(qdutils::MDPVersion::getInstance().isSrcSplit()) {
return new FBSrcSplit(ctx, dpy);
} else if(isDisplaySplit(ctx, dpy)) {
return new FBUpdateSplit(ctx, dpy);
}
return new FBUpdateNonSplit(ctx, dpy);
}
IFBUpdate::IFBUpdate(hwc_context_t *ctx, const int& dpy) : mDpy(dpy) {
unsigned int size = 0;
uint32_t xres = ctx->dpyAttr[mDpy].xres;
uint32_t yres = ctx->dpyAttr[mDpy].yres;
if (ctx->dpyAttr[dpy].fbScaling) {
xres = ctx->dpyAttr[mDpy].xresFB;
yres = ctx->dpyAttr[mDpy].yresFB;
}
getBufferAttributes((int)xres, (int)yres,
ctx->dpyAttr[mDpy].fbformat,
0,
mAlignedFBWidth,
mAlignedFBHeight,
mTileEnabled, size);
}
void IFBUpdate::reset() {
mModeOn = false;
mRot = NULL;
}
bool IFBUpdate::prepareAndValidate(hwc_context_t *ctx,
hwc_display_contents_1 *list, int fbZorder) {
hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
mModeOn = prepare(ctx, list, layer->displayFrame, fbZorder) &&
ctx->mOverlay->validateAndSet(mDpy, ctx->dpyAttr[mDpy].fd);
return mModeOn;
}
//================= Low res====================================
FBUpdateNonSplit::FBUpdateNonSplit(hwc_context_t *ctx, const int& dpy):
IFBUpdate(ctx, dpy) {}
void FBUpdateNonSplit::reset() {
IFBUpdate::reset();
mDest = ovutils::OV_INVALID;
}
bool FBUpdateNonSplit::preRotateExtDisplay(hwc_context_t *ctx,
hwc_layer_1_t *layer,
ovutils::Whf &info,
hwc_rect_t& sourceCrop,
ovutils::eMdpFlags& mdpFlags,
int& rotFlags)
{
int extOrient = getExtOrientation(ctx);
ovutils::eTransform orient = static_cast<ovutils::eTransform >(extOrient);
if(mDpy && (extOrient & HWC_TRANSFORM_ROT_90)) {
mRot = ctx->mRotMgr->getNext();
if(mRot == NULL) return false;
ctx->mLayerRotMap[mDpy]->add(layer, mRot);
// Composed FB content will have black bars, if the viewFrame of the
// external is different from {0, 0, fbWidth, fbHeight}, so intersect
// viewFrame with sourceCrop to avoid those black bars
sourceCrop = getIntersection(sourceCrop, ctx->mViewFrame[mDpy]);
//Configure rotator for pre-rotation
if(configRotator(mRot, info, sourceCrop, mdpFlags, orient, 0,
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].refreshRate) < 0) {
ALOGE("%s: configRotator Failed!", __FUNCTION__);
mRot = NULL;
return false;
}
updateSource(orient, info, sourceCrop, mRot);
rotFlags |= ovutils::ROT_PREROTATED;
}
return true;
}
bool FBUpdateNonSplit::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
hwc_rect_t fbUpdatingRect, int fbZorder) {
if(!ctx->mMDP.hasOverlay) {
ALOGD_IF(DEBUG_FBUPDATE, "%s, this hw doesnt support overlays",
__FUNCTION__);
return false;
}
mModeOn = configure(ctx, list, fbUpdatingRect, fbZorder);
return mModeOn;
}
// Configure
bool FBUpdateNonSplit::configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
hwc_rect_t fbUpdatingRect, int fbZorder) {
bool ret = false;
hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
if (LIKELY(ctx->mOverlay)) {
overlay::Overlay& ov = *(ctx->mOverlay);
int flags = mTileEnabled ?
private_handle_t::PRIV_FLAGS_TILE_RENDERED : 0;
ovutils::Whf info(mAlignedFBWidth, mAlignedFBHeight,
ovutils::getMdpFormat(ctx->dpyAttr[mDpy].fbformat, flags));
Overlay::PipeSpecs pipeSpecs;
pipeSpecs.formatClass = Overlay::FORMAT_RGB;
pipeSpecs.needsScaling = qhwc::needsScaling(layer);
pipeSpecs.dpy = mDpy;
pipeSpecs.mixer = Overlay::MIXER_DEFAULT;
pipeSpecs.fb = true;
ovutils::eDest dest = ov.getPipe(pipeSpecs);
if(dest == ovutils::OV_INVALID) { //None available
ALOGE("%s: No pipes available to configure fb for dpy %d",
__FUNCTION__, mDpy);
return false;
}
mDest = dest;
if((mDpy && ctx->deviceOrientation) &&
ctx->listStats[mDpy].isDisplayAnimating) {
fbZorder = 0;
}
ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_BLEND_FG_PREMULT;
ovutils::setMdpFlags(mdpFlags,
ovutils::OV_MDP_SMP_FORCE_ALLOC);
ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
hwc_rect_t displayFrame = layer->displayFrame;
// No FB update optimization on (1) Custom FB resolution,
// (2) External Mirror mode, (3) External orientation
if(!ctx->dpyAttr[mDpy].fbScaling && !ctx->mBufferMirrorMode
&& !ctx->mExtOrientation) {
sourceCrop = fbUpdatingRect;
displayFrame = fbUpdatingRect;
}
int transform = layer->transform;
int rotFlags = ovutils::ROT_FLAGS_NONE;
ovutils::eTransform orient =
static_cast<ovutils::eTransform>(transform);
// use ext orientation if any
int extOrient = getExtOrientation(ctx);
// Do not use getNonWormholeRegion() function to calculate the
// sourceCrop during animation on external display and
// Dont do wormhole calculation when extorientation is set on External
// Dont do wormhole calculation when scaling mode is set on External
if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
sourceCrop = layer->displayFrame;
} else if((mDpy && !extOrient
&& !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
if(ctx->mOverlay->isUIScalingOnExternalSupported() &&
!ctx->dpyAttr[mDpy].fbScaling) {
getNonWormholeRegion(list, sourceCrop);
displayFrame = sourceCrop;
}
}
calcExtDisplayPosition(ctx, NULL, mDpy, sourceCrop, displayFrame,
transform, orient);
//Store the displayFrame, will be used in getDisplayViewFrame
ctx->dpyAttr[mDpy].mDstRect = displayFrame;
setMdpFlags(ctx, layer, mdpFlags, 0, transform);
// For External use rotator if there is a rotation value set
ret = preRotateExtDisplay(ctx, layer, info,
sourceCrop, mdpFlags, rotFlags);
if(!ret) {
ALOGE("%s: preRotate for external Failed!", __FUNCTION__);
return false;
}
//For the mdp, since either we are pre-rotating or MDP does flips
orient = ovutils::OVERLAY_TRANSFORM_0;
transform = 0;
ovutils::PipeArgs parg(mdpFlags, info, zOrder,
static_cast<ovutils::eRotFlags>(rotFlags),
ovutils::DEFAULT_PLANE_ALPHA,
(ovutils::eBlending)
getBlending(layer->blending));
ret = true;
if(configMdp(ctx->mOverlay, parg, orient, sourceCrop, displayFrame,
NULL, mDest) < 0) {
ALOGE("%s: configMdp failed for dpy %d", __FUNCTION__, mDpy);
ret = false;
}
}
return ret;
}
bool FBUpdateNonSplit::draw(hwc_context_t *ctx, private_handle_t *hnd)
{
if(!mModeOn) {
return true;
}
bool ret = true;
overlay::Overlay& ov = *(ctx->mOverlay);
ovutils::eDest dest = mDest;
int fd = hnd->fd;
uint32_t offset = (uint32_t)hnd->offset;
if(mRot) {
if(!mRot->queueBuffer(fd, offset))
return false;
fd = mRot->getDstMemId();
offset = mRot->getDstOffset();
}
if (!ov.queueBuffer(fd, offset, dest)) {
ALOGE("%s: queueBuffer failed for FBUpdate", __FUNCTION__);
ret = false;
}
return ret;
}
//================= High res====================================
FBUpdateSplit::FBUpdateSplit(hwc_context_t *ctx, const int& dpy):
IFBUpdate(ctx, dpy) {}
void FBUpdateSplit::reset() {
IFBUpdate::reset();
mDestLeft = ovutils::OV_INVALID;
mDestRight = ovutils::OV_INVALID;
mRot = NULL;
}
bool FBUpdateSplit::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
hwc_rect_t fbUpdatingRect, int fbZorder) {
if(!ctx->mMDP.hasOverlay) {
ALOGD_IF(DEBUG_FBUPDATE, "%s, this hw doesnt support overlays",
__FUNCTION__);
return false;
}
mModeOn = configure(ctx, list, fbUpdatingRect, fbZorder);
ALOGD_IF(DEBUG_FBUPDATE, "%s, mModeOn = %d", __FUNCTION__, mModeOn);
return mModeOn;
}
// Configure
bool FBUpdateSplit::configure(hwc_context_t *ctx,
hwc_display_contents_1 *list, hwc_rect_t fbUpdatingRect, int fbZorder) {
bool ret = false;
hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
if (LIKELY(ctx->mOverlay)) {
int flags = mTileEnabled ?
private_handle_t::PRIV_FLAGS_TILE_RENDERED : 0;
ovutils::Whf info(mAlignedFBWidth, mAlignedFBHeight,
ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888, flags));
overlay::Overlay& ov = *(ctx->mOverlay);
ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_BLEND_FG_PREMULT;
ovutils::setMdpFlags(mdpFlags,
ovutils::OV_MDP_SMP_FORCE_ALLOC);
ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
ovutils::eTransform orient =
static_cast<ovutils::eTransform>(layer->transform);
const int hw_w = ctx->dpyAttr[mDpy].xres;
const int hw_h = ctx->dpyAttr[mDpy].yres;
const int lSplit = getLeftSplit(ctx, mDpy);
mDestLeft = ovutils::OV_INVALID;
mDestRight = ovutils::OV_INVALID;
hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
hwc_rect_t displayFrame = layer->displayFrame;
// No FB update optimization on (1) Custom FB resolution,
// (2) External Mirror mode, (3) External orientation
if(!ctx->dpyAttr[mDpy].fbScaling && !ctx->mBufferMirrorMode
&& !ctx->mExtOrientation) {
sourceCrop = fbUpdatingRect;
displayFrame = fbUpdatingRect;
}
int transform = layer->transform;
// use ext orientation if any
int extOrient = getExtOrientation(ctx);
// Do not use getNonWormholeRegion() function to calculate the
// sourceCrop during animation on external display and
// Dont do wormhole calculation when extorientation is set on External
// Dont do wormhole calculation when scaling mode is set on External
if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
sourceCrop = layer->displayFrame;
} else if((mDpy && !extOrient
&& !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
if(!qdutils::MDPVersion::getInstance().is8x26() &&
!ctx->dpyAttr[mDpy].fbScaling) {
getNonWormholeRegion(list, sourceCrop);
displayFrame = sourceCrop;
}
}
calcExtDisplayPosition(ctx, NULL, mDpy, sourceCrop, displayFrame,
transform, orient);
ret = true;
Overlay::PipeSpecs pipeSpecs;
pipeSpecs.formatClass = Overlay::FORMAT_RGB;
pipeSpecs.needsScaling = qhwc::needsScaling(layer);
pipeSpecs.dpy = mDpy;
pipeSpecs.fb = true;
/* Configure left pipe */
if(displayFrame.left < lSplit) {
pipeSpecs.mixer = Overlay::MIXER_LEFT;
ovutils::eDest destL = ov.getPipe(pipeSpecs);
if(destL == ovutils::OV_INVALID) { //None available
ALOGE("%s: No pipes available to configure fb for dpy %d's left"
" mixer", __FUNCTION__, mDpy);
return false;
}
mDestLeft = destL;
//XXX: FB layer plane alpha is currently sent as zero from
//surfaceflinger
ovutils::PipeArgs pargL(mdpFlags,
info,
zOrder,
ovutils::ROT_FLAGS_NONE,
ovutils::DEFAULT_PLANE_ALPHA,
(ovutils::eBlending)
getBlending(layer->blending));
hwc_rect_t cropL = sourceCrop;
hwc_rect_t dstL = displayFrame;
hwc_rect_t scissorL = {0, 0, lSplit, hw_h };
qhwc::calculate_crop_rects(cropL, dstL, scissorL, 0);
if (configMdp(ctx->mOverlay, pargL, orient, cropL,
dstL, NULL, destL)< 0) {
ALOGE("%s: configMdp fails for left FB", __FUNCTION__);
ret = false;
}
}
/* Configure right pipe */
if(displayFrame.right > lSplit) {
pipeSpecs.mixer = Overlay::MIXER_RIGHT;
ovutils::eDest destR = ov.getPipe(pipeSpecs);
if(destR == ovutils::OV_INVALID) { //None available
ALOGE("%s: No pipes available to configure fb for dpy %d's"
" right mixer", __FUNCTION__, mDpy);
return false;
}
mDestRight = destR;
ovutils::eMdpFlags mdpFlagsR = mdpFlags;
ovutils::setMdpFlags(mdpFlagsR, ovutils::OV_MDSS_MDP_RIGHT_MIXER);
//XXX: FB layer plane alpha is currently sent as zero from
//surfaceflinger
ovutils::PipeArgs pargR(mdpFlagsR,
info,
zOrder,
ovutils::ROT_FLAGS_NONE,
ovutils::DEFAULT_PLANE_ALPHA,
(ovutils::eBlending)
getBlending(layer->blending));
hwc_rect_t cropR = sourceCrop;
hwc_rect_t dstR = displayFrame;
hwc_rect_t scissorR = {lSplit, 0, hw_w, hw_h };
qhwc::calculate_crop_rects(cropR, dstR, scissorR, 0);
dstR.left -= lSplit;
dstR.right -= lSplit;
if (configMdp(ctx->mOverlay, pargR, orient, cropR,
dstR, NULL, destR) < 0) {
ALOGE("%s: configMdp fails for right FB", __FUNCTION__);
ret = false;
}
}
}
return ret;
}
bool FBUpdateSplit::draw(hwc_context_t *ctx, private_handle_t *hnd)
{
if(!mModeOn) {
return true;
}
bool ret = true;
overlay::Overlay& ov = *(ctx->mOverlay);
if(mDestLeft != ovutils::OV_INVALID) {
if (!ov.queueBuffer(hnd->fd, (uint32_t)hnd->offset, mDestLeft)) {
ALOGE("%s: queue failed for left of dpy = %d",
__FUNCTION__, mDpy);
ret = false;
}
}
if(mDestRight != ovutils::OV_INVALID) {
if (!ov.queueBuffer(hnd->fd, (uint32_t)hnd->offset, mDestRight)) {
ALOGE("%s: queue failed for right of dpy = %d",
__FUNCTION__, mDpy);
ret = false;
}
}
return ret;
}
//=================FBSrcSplit====================================
FBSrcSplit::FBSrcSplit(hwc_context_t *ctx, const int& dpy):
FBUpdateSplit(ctx, dpy) {}
bool FBSrcSplit::configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
hwc_rect_t fbUpdatingRect, int fbZorder) {
hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
overlay::Overlay& ov = *(ctx->mOverlay);
int flags = mTileEnabled ? private_handle_t::PRIV_FLAGS_TILE_RENDERED : 0;
ovutils::Whf info(mAlignedFBWidth,
mAlignedFBHeight,
ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888, flags));
ovutils::eMdpFlags mdpFlags = OV_MDP_BLEND_FG_PREMULT;
ovutils::setMdpFlags(mdpFlags,
ovutils::OV_MDP_SMP_FORCE_ALLOC);
ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
ovutils::PipeArgs parg(mdpFlags,
info,
zOrder,
ovutils::ROT_FLAGS_NONE,
ovutils::DEFAULT_PLANE_ALPHA,
(ovutils::eBlending)
getBlending(layer->blending));
hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
hwc_rect_t displayFrame = layer->displayFrame;
// No FB update optimization on (1) Custom FB resolution,
// (2) External Mirror mode, (3) External orientation
if(!ctx->dpyAttr[mDpy].fbScaling && !ctx->mBufferMirrorMode
&& !ctx->mExtOrientation) {
sourceCrop = fbUpdatingRect;
displayFrame = fbUpdatingRect;
}
int transform = layer->transform;
ovutils::eTransform orient =
static_cast<ovutils::eTransform>(transform);
// use ext orientation if any
int extOrient = getExtOrientation(ctx);
// Do not use getNonWormholeRegion() function to calculate the
// sourceCrop during animation on external display and
// Dont do wormhole calculation when extorientation is set on External
// Dont do wormhole calculation when scaling mode is set on External
if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
sourceCrop = layer->displayFrame;
} else if((mDpy && !extOrient
&& !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
if(!qdutils::MDPVersion::getInstance().is8x26() &&
!ctx->dpyAttr[mDpy].fbScaling) {
getNonWormholeRegion(list, sourceCrop);
displayFrame = sourceCrop;
}
}
calcExtDisplayPosition(ctx, NULL, mDpy, sourceCrop, displayFrame,
transform, orient);
hwc_rect_t cropL = sourceCrop;
hwc_rect_t cropR = sourceCrop;
hwc_rect_t dstL = displayFrame;
hwc_rect_t dstR = displayFrame;
if(ctx->dpyAttr[mDpy].s3dMode == HDMI_S3D_SIDE_BY_SIDE) {
dstL.left = displayFrame.left/2;
dstL.right = displayFrame.right/2;
dstR.left = mAlignedFBWidth/2 + displayFrame.left/2;
dstR.right = mAlignedFBWidth/2 + displayFrame.right/2;
} else if(ctx->dpyAttr[mDpy].s3dMode == HDMI_S3D_TOP_AND_BOTTOM) {
dstL.top = displayFrame.top/2;
dstL.bottom = displayFrame.bottom/2;
dstR.top = mAlignedFBHeight/2 + displayFrame.top/2;
dstR.bottom = mAlignedFBHeight/2 + displayFrame.bottom/2;
}
//Request left pipe (or 1 by default)
Overlay::PipeSpecs pipeSpecs;
pipeSpecs.formatClass = Overlay::FORMAT_RGB;
pipeSpecs.needsScaling = (qhwc::needsScaling(layer) ||
needs3DComposition(ctx,mDpy));
pipeSpecs.dpy = mDpy;
pipeSpecs.mixer = Overlay::MIXER_DEFAULT;
pipeSpecs.fb = true;
ovutils::eDest destL = ov.getPipe(pipeSpecs);
if(destL == ovutils::OV_INVALID) {
ALOGE("%s: No pipes available to configure fb for dpy %d's left"
" mixer", __FUNCTION__, mDpy);
return false;
}
ovutils::eDest destR = ovutils::OV_INVALID;
/* Use 2 pipes IF
a) FB's width is > Mixer width or
b) On primary, driver has indicated with caps to split always. This is
based on an empirically derived value of panel height.
c) The composition is 3D
*/
const bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and
qdutils::MDPVersion::getInstance().isSrcSplitAlways();
const uint32_t lSplit = getLeftSplit(ctx, mDpy);
const uint32_t cropWidth = sourceCrop.right - sourceCrop.left;
const uint32_t cropHeight = sourceCrop.bottom - sourceCrop.top;
const uint32_t dstWidth = displayFrame.right - displayFrame.left;
const uint32_t dstHeight = displayFrame.bottom - displayFrame.top;
const uint32_t layerClock = getLayerClock(dstWidth, dstHeight, cropHeight);
const uint32_t mixerClock = lSplit;
if((cropWidth > qdutils::MDPVersion::getInstance().getMaxPipeWidth()) or
(primarySplitAlways and
(cropWidth > lSplit or layerClock > mixerClock)) or
needs3DComposition(ctx, mDpy)) {
destR = ov.getPipe(pipeSpecs);
if(destR == ovutils::OV_INVALID) {
ALOGE("%s: No pipes available to configure fb for dpy %d's right"
" mixer", __FUNCTION__, mDpy);
return false;
}
if(ctx->mOverlay->needsPrioritySwap(destL, destR)) {
qhwc::swap(destL, destR);
}
//Split crop equally when using 2 pipes
if(!needs3DComposition(ctx, mDpy)) {
cropL.right = (sourceCrop.right + sourceCrop.left) / 2;
cropR.left = cropL.right;
dstL.right = (displayFrame.right + displayFrame.left) / 2;
dstR.left = dstL.right;
}
}
mDestLeft = destL;
mDestRight = destR;
if(destL != OV_INVALID) {
if(configMdp(ctx->mOverlay, parg, orient,
cropL, dstL, NULL /*metadata*/, destL) < 0) {
ALOGE("%s: commit failed for left mixer config", __FUNCTION__);
return false;
}
}
// XXX: Figure out why we need this with source split
// Currently, the driver silently fails to configure the right pipe
// if we don't increment the zorder
if (needs3DComposition(ctx, mDpy))
parg.zorder = eZorder(parg.zorder + 1);
//configure right pipe
if(destR != OV_INVALID) {
if(configMdp(ctx->mOverlay, parg, orient,
cropR, dstR, NULL /*metadata*/, destR) < 0) {
ALOGE("%s: commit failed for right mixer config", __FUNCTION__);
return false;
}
}
return true;
}
//---------------------------------------------------------------------
}; //namespace qhwc

View File

@@ -1,111 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 2012, The Linux Foundation. All rights reserved.
*
* Not a Contribution, Apache license notifications and license are
* retained for attribution purposes only.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef HWC_FBUPDATE_H
#define HWC_FBUPDATE_H
#include "hwc_utils.h"
#include "overlay.h"
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
namespace overlay {
class Rotator;
}
namespace qhwc {
namespace ovutils = overlay::utils;
//Framebuffer update Interface
class IFBUpdate {
public:
explicit IFBUpdate(hwc_context_t *ctx, const int& dpy);
virtual ~IFBUpdate() {};
// Sets up members and prepares overlay if conditions are met
virtual bool prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
hwc_rect_t fbUpdatingRect, int fbZorder) = 0;
virtual bool prepareAndValidate(hwc_context_t *ctx,
hwc_display_contents_1 *list, int fbZorder);
// Draws layer
virtual bool draw(hwc_context_t *ctx, private_handle_t *hnd) = 0;
//Reset values
virtual void reset();
//Factory method that returns a low-res or high-res version
static IFBUpdate *getObject(hwc_context_t *ctx, const int& dpy);
protected:
const int mDpy; // display to update
bool mModeOn; // if prepare happened
overlay::Rotator *mRot;
int mAlignedFBWidth;
int mAlignedFBHeight;
int mTileEnabled;
};
//Non-Split panel handler.
class FBUpdateNonSplit : public IFBUpdate {
public:
explicit FBUpdateNonSplit(hwc_context_t *ctx, const int& dpy);
virtual ~FBUpdateNonSplit() {};
bool prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
hwc_rect_t fbUpdatingRect, int fbZorder);
bool draw(hwc_context_t *ctx, private_handle_t *hnd);
void reset();
private:
bool configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
hwc_rect_t fbUpdatingRect, int fbZorder);
bool preRotateExtDisplay(hwc_context_t *ctx,
hwc_layer_1_t *layer,
ovutils::Whf &info,
hwc_rect_t& sourceCrop,
ovutils::eMdpFlags& mdpFlags,
int& rotFlags);
ovutils::eDest mDest; //pipe to draw on
};
//Split panel handler.
class FBUpdateSplit : public IFBUpdate {
public:
explicit FBUpdateSplit(hwc_context_t *ctx, const int& dpy);
virtual ~FBUpdateSplit() {};
bool prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
hwc_rect_t fbUpdatingRect, int fbZorder);
bool draw(hwc_context_t *ctx, private_handle_t *hnd);
void reset();
protected:
virtual bool configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
hwc_rect_t fbUpdatingRect, int fbZorder);
ovutils::eDest mDestLeft; //left pipe to draw on
ovutils::eDest mDestRight; //right pipe to draw on
};
//Source Split Handler
class FBSrcSplit : public FBUpdateSplit {
public:
explicit FBSrcSplit(hwc_context_t *ctx, const int& dpy);
virtual ~FBSrcSplit() {};
private:
bool configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
hwc_rect_t fbUpdatingRect, int fbZorder);
};
}; //namespace qhwc
#endif //HWC_FBUPDATE_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,391 +0,0 @@
/*
* Copyright (C) 2012-2013, The Linux Foundation. All rights reserved.
*
* Not a Contribution, Apache license notifications and license are retained
* for attribution purposes only.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef HWC_MDP_COMP
#define HWC_MDP_COMP
#include <hwc_utils.h>
#include <idle_invalidator.h>
#include <cutils/properties.h>
#include <overlay.h>
namespace overlay {
class Rotator;
};
namespace qhwc {
namespace ovutils = overlay::utils;
class MDPComp {
public:
explicit MDPComp(int);
virtual ~MDPComp(){};
/*sets up mdp comp for the current frame */
int prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list);
/* draw */
virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list) = 0;
//Reset values
void reset();
/* dumpsys */
void dump(android::String8& buf, hwc_context_t *ctx);
bool isGLESOnlyComp() { return (mCurrentFrame.mdpCount == 0); }
bool isMDPComp() { return mModeOn; }
int drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t* list);
static MDPComp* getObject(hwc_context_t *ctx, const int& dpy);
/* Handler to invoke frame redraw on Idle Timer expiry */
static void timeout_handler(void *udata);
/* Initialize MDP comp*/
static bool init(hwc_context_t *ctx);
static void resetIdleFallBack() { sIdleFallBack = false; }
static bool isIdleFallback() { return sIdleFallBack; }
static void dynamicDebug(bool enable){ sDebugLogs = enable; }
static void setIdleTimeout(const uint32_t& timeout);
static void setMaxPipesPerMixer(const uint32_t value);
static int setPartialUpdatePref(hwc_context_t *ctx, bool enable);
static bool getPartialUpdatePref(hwc_context_t *ctx);
static void enablePartialUpdate(bool enable)
{ sIsPartialUpdateActive = enable; };
void setDynRefreshRate(hwc_context_t *ctx, hwc_display_contents_1_t* list);
protected:
enum ePipeType {
MDPCOMP_OV_RGB = ovutils::OV_MDP_PIPE_RGB,
MDPCOMP_OV_VG = ovutils::OV_MDP_PIPE_VG,
MDPCOMP_OV_DMA = ovutils::OV_MDP_PIPE_DMA,
MDPCOMP_OV_ANY,
};
//Simulation flags
enum {
MDPCOMP_AVOID_FULL_MDP = 0x001,
MDPCOMP_AVOID_CACHE_MDP = 0x002,
MDPCOMP_AVOID_LOAD_MDP = 0x004,
MDPCOMP_AVOID_VIDEO_ONLY = 0x008,
MDPCOMP_AVOID_MDP_ONLY_LAYERS = 0x010,
};
/* mdp pipe data */
struct MdpPipeInfo {
int zOrder;
virtual ~MdpPipeInfo(){};
};
struct MdpYUVPipeInfo : public MdpPipeInfo{
ovutils::eDest lIndex;
ovutils::eDest rIndex;
virtual ~MdpYUVPipeInfo(){};
};
/* per layer data */
struct PipeLayerPair {
MdpPipeInfo *pipeInfo;
overlay::Rotator* rot;
int listIndex;
};
/* per frame data */
struct FrameInfo {
/* maps layer list to mdp list */
int layerCount;
int layerToMDP[MAX_NUM_APP_LAYERS];
/* maps mdp list to layer list */
int mdpCount;
struct PipeLayerPair mdpToLayer[MAX_NUM_BLEND_STAGES];
/* layer composing on FB? */
int fbCount;
bool isFBComposed[MAX_NUM_APP_LAYERS];
/* layers lying outside ROI. Will
* be dropped off from the composition */
int dropCount;
bool drop[MAX_NUM_APP_LAYERS];
bool needsRedraw;
int fbZ;
int hwCursorIndex;
/* c'tor */
FrameInfo();
/* clear old frame data */
void reset(const int& numLayers);
void map();
};
/* cached data */
struct LayerCache {
int layerCount;
buffer_handle_t hnd[MAX_NUM_APP_LAYERS];
bool isFBComposed[MAX_NUM_APP_LAYERS];
bool drop[MAX_NUM_APP_LAYERS];
/* c'tor */
LayerCache();
/* clear caching info*/
void reset();
void cacheAll(hwc_display_contents_1_t* list);
void updateCounts(const FrameInfo&);
bool isSameFrame(const FrameInfo& curFrame,
hwc_display_contents_1_t* list);
bool isSameFrame(hwc_context_t *ctx, int dpy,
hwc_display_contents_1_t* list);
};
/* allocates pipe from pipe book */
virtual bool allocLayerPipes(hwc_context_t *ctx,
hwc_display_contents_1_t* list) = 0;
/* configures MPD pipes */
virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
PipeLayerPair& pipeLayerPair) = 0;
/* Increments mdpCount if 4k2k yuv layer split is enabled.
* updates framebuffer z order if fb lies above source-split layer */
virtual void adjustForSourceSplit(hwc_context_t *ctx,
hwc_display_contents_1_t* list) = 0;
/* configures 4kx2k yuv layer*/
virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
PipeLayerPair& PipeLayerPair) = 0;
/* generates ROI based on the modified area of the frame */
virtual void generateROI(hwc_context_t *ctx,
hwc_display_contents_1_t* list) = 0;
/* validates the ROI generated for fallback conditions */
virtual bool validateAndApplyROI(hwc_context_t *ctx,
hwc_display_contents_1_t* list) = 0;
/* Trims layer coordinates against ROI generated */
virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& crop,
hwc_rect& dst) = 0;
/* set/reset flags for MDPComp */
void setMDPCompLayerFlags(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
void setRedraw(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
/* checks for conditions where mdpcomp is not possible */
bool isFrameDoable(hwc_context_t *ctx);
/* checks for conditions where RGB layers cannot be bypassed */
bool tryFullFrame(hwc_context_t *ctx, hwc_display_contents_1_t* list);
/* checks if full MDP comp can be done */
bool fullMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list);
/* Full MDP Composition with Peripheral Tiny Overlap Removal */
bool fullMDPCompWithPTOR(hwc_context_t *ctx,hwc_display_contents_1_t* list);
/* check if we can use layer cache to do at least partial MDP comp */
bool partialMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list);
/* Partial MDP comp that uses caching to save power as primary goal */
bool cacheBasedComp(hwc_context_t *ctx, hwc_display_contents_1_t* list);
/* Partial MDP comp that balances the load between MDP and GPU such that
* MDP is loaded to the max of its capacity. The lower z order layers are
* fed to MDP, whereas the upper ones to GPU, because the upper ones have
* lower number of pixels and can reduce GPU processing time */
bool loadBasedComp(hwc_context_t *ctx, hwc_display_contents_1_t* list);
/* Checks if its worth doing load based partial comp */
bool isLoadBasedCompDoable(hwc_context_t *ctx);
/* checks for conditions where only video can be bypassed */
bool tryVideoOnly(hwc_context_t *ctx, hwc_display_contents_1_t* list);
bool videoOnlyComp(hwc_context_t *ctx, hwc_display_contents_1_t* list,
bool secureOnly);
/* checks for conditions where only secure RGB and video can be bypassed */
bool tryMDPOnlyLayers(hwc_context_t *ctx, hwc_display_contents_1_t* list);
bool mdpOnlyLayersComp(hwc_context_t *ctx, hwc_display_contents_1_t* list,
bool secureOnly);
/* checks for conditions where YUV layers cannot be bypassed */
bool isYUVDoable(hwc_context_t* ctx, hwc_layer_1_t* layer);
/* checks for conditions where Secure RGB layers cannot be bypassed */
bool isSecureRGBDoable(hwc_context_t* ctx, hwc_layer_1_t* layer);
/* checks if MDP/MDSS can process current list w.r.to HW limitations
* All peculiar HW limitations should go here */
bool hwLimitationsCheck(hwc_context_t* ctx, hwc_display_contents_1_t* list);
/* Is debug enabled */
static bool isDebug() { return sDebugLogs ? true : false; };
/* Is feature enabled */
static bool isEnabled() { return sEnabled; };
/* checks for mdp comp dimension limitation */
bool isValidDimension(hwc_context_t *ctx, hwc_layer_1_t *layer);
/* tracks non updating layers*/
void updateLayerCache(hwc_context_t* ctx, hwc_display_contents_1_t* list,
FrameInfo& frame);
/* optimize layers for mdp comp*/
bool markLayersForCaching(hwc_context_t* ctx,
hwc_display_contents_1_t* list);
int getBatch(hwc_display_contents_1_t* list,
int& maxBatchStart, int& maxBatchEnd,
int& maxBatchCount);
bool canPushBatchToTop(const hwc_display_contents_1_t* list,
int fromIndex, int toIndex);
bool intersectingUpdatingLayers(const hwc_display_contents_1_t* list,
int fromIndex, int toIndex, int targetLayerIndex);
/* drop other non-AIV layers from external display list.*/
void dropNonAIVLayers(hwc_context_t* ctx, hwc_display_contents_1_t* list);
/* updates cache map with YUV info */
void updateYUV(hwc_context_t* ctx, hwc_display_contents_1_t* list,
bool secureOnly, FrameInfo& frame);
/* updates cache map with secure RGB info */
void updateSecureRGB(hwc_context_t* ctx,
hwc_display_contents_1_t* list);
/* Validates if the GPU/MDP layer split chosen by a strategy is supported
* by MDP.
* Sets up MDP comp data structures to reflect covnversion from layers to
* overlay pipes.
* Configures overlay.
* Configures if GPU should redraw.
*/
bool postHeuristicsHandling(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
void reset(hwc_context_t *ctx);
bool isSupportedForMDPComp(hwc_context_t *ctx, hwc_layer_1_t* layer);
bool resourceCheck(hwc_context_t* ctx, hwc_display_contents_1_t* list);
hwc_rect_t getUpdatingFBRect(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
/* checks for conditions to enable partial udpate */
bool canPartialUpdate(hwc_context_t *ctx, hwc_display_contents_1_t* list);
// Checks if only videocontent is updating
bool onlyVideosUpdating(hwc_context_t *ctx, hwc_display_contents_1_t* list);
static bool loadPerfLib();
void setPerfHint(hwc_context_t *ctx, hwc_display_contents_1_t* list);
int mDpy;
static bool sEnabled;
static bool sEnableMixedMode;
static int sSimulationFlags;
static bool sDebugLogs;
static bool sIdleFallBack;
static int sMaxPipesPerMixer;
static bool sSrcSplitEnabled;
static IdleInvalidator *sIdleInvalidator;
static int sMaxSecLayers;
static bool sIsPartialUpdateActive;
struct FrameInfo mCurrentFrame;
struct LayerCache mCachedFrame;
//Enable 4kx2k yuv layer split
static bool sEnableYUVsplit;
bool mModeOn; // if prepare happened
bool allocSplitVGPipes(hwc_context_t *ctx, int index);
bool mPrevModeOn; //if previous prepare happened
//Enable Partial Update for MDP3 targets
static bool enablePartialUpdateForMDP3;
static void *sLibPerfHint;
static int sPerfLockHandle;
static int (*sPerfLockAcquire)(int, int, int*, int);
static int (*sPerfLockRelease)(int value);
static int sPerfHintWindow;
static float sDownscaleThreshold;
};
class MDPCompNonSplit : public MDPComp {
public:
explicit MDPCompNonSplit(int dpy):MDPComp(dpy){};
virtual ~MDPCompNonSplit(){};
virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list);
private:
struct MdpPipeInfoNonSplit : public MdpPipeInfo {
ovutils::eDest index;
virtual ~MdpPipeInfoNonSplit() {};
};
/* configure's overlay pipes for the frame */
virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
PipeLayerPair& pipeLayerPair);
/* allocates pipes to selected candidates */
virtual bool allocLayerPipes(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
/* Increments mdpCount if 4k2k yuv layer split is enabled.
* updates framebuffer z order if fb lies above source-split layer */
virtual void adjustForSourceSplit(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
/* configures 4kx2k yuv layer to 2 VG pipes*/
virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
PipeLayerPair& PipeLayerPair);
/* generates ROI based on the modified area of the frame */
virtual void generateROI(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
/* validates the ROI generated for fallback conditions */
virtual bool validateAndApplyROI(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
/* Trims layer coordinates against ROI generated */
virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& crop,
hwc_rect& dst);
};
class MDPCompSplit : public MDPComp {
public:
explicit MDPCompSplit(int dpy):MDPComp(dpy){};
virtual ~MDPCompSplit(){};
virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list);
protected:
struct MdpPipeInfoSplit : public MdpPipeInfo {
ovutils::eDest lIndex;
ovutils::eDest rIndex;
virtual ~MdpPipeInfoSplit() {};
};
virtual bool acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer,
MdpPipeInfoSplit& pipe_info);
/* configure's overlay pipes for the frame */
virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
PipeLayerPair& pipeLayerPair);
/* allocates pipes to selected candidates */
virtual bool allocLayerPipes(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
/* Trims layer coordinates against ROI generated */
virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& crop,
hwc_rect& dst);
private:
/* Increments mdpCount if 4k2k yuv layer split is enabled.
* updates framebuffer z order if fb lies above source-split layer */
virtual void adjustForSourceSplit(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
/* configures 4kx2k yuv layer*/
virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
PipeLayerPair& PipeLayerPair);
/* generates ROI based on the modified area of the frame */
virtual void generateROI(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
/* validates the ROI generated for fallback conditions */
virtual bool validateAndApplyROI(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
};
class MDPCompSrcSplit : public MDPCompSplit {
public:
explicit MDPCompSrcSplit(int dpy) : MDPCompSplit(dpy){};
virtual ~MDPCompSrcSplit(){};
private:
virtual bool acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer,
MdpPipeInfoSplit& pipe_info);
virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
PipeLayerPair& pipeLayerPair);
/* generates ROI based on the modified area of the frame */
virtual void generateROI(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
/* validates the ROI generated for fallback conditions */
virtual bool validateAndApplyROI(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
};
}; //namespace
#endif

View File

@@ -1,653 +0,0 @@
/*
* Copyright (c) 2013-14, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR CLIENTS; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <hwc_qclient.h>
#include <IQService.h>
#include <hwc_utils.h>
#include <mdp_version.h>
#include <hwc_mdpcomp.h>
#include <hwc_virtual.h>
#include <overlay.h>
#include <display_config.h>
#include <hdmi.h>
#include <video/msm_hdmi_modes.h>
#include <hwc_qdcm.h>
#define QCLIENT_DEBUG 0
#define FILE_MAX_MDSSBW_FLAG \
"/sys/devices/virtual/graphics/fb0/mdp/bw_mode_bitmap"
using namespace android;
using namespace qService;
using namespace qhwc;
using namespace overlay;
using namespace qdutils;
using namespace qQdcm;
namespace qClient {
// ----------------------------------------------------------------------------
QClient::QClient(hwc_context_t *ctx) : mHwcContext(ctx),
mMPDeathNotifier(new MPDeathNotifier(ctx)),
mCamDeathNotifier(new CamDeathNotifier())
{
ALOGD_IF(QCLIENT_DEBUG, "QClient Constructor invoked");
}
QClient::~QClient()
{
ALOGD_IF(QCLIENT_DEBUG,"QClient Destructor invoked");
}
static void securing(hwc_context_t *ctx, uint32_t startEnd) {
//The only way to make this class in this process subscribe to media
//player's death.
IMediaDeathNotifier::getMediaPlayerService();
ctx->mDrawLock.lock();
ctx->mSecuring = startEnd;
//We're done securing
if(startEnd == IQService::END)
ctx->mSecureMode = true;
ctx->mDrawLock.unlock();
if(ctx->proc)
ctx->proc->invalidate(ctx->proc);
}
static void unsecuring(hwc_context_t *ctx, uint32_t startEnd) {
ctx->mDrawLock.lock();
ctx->mSecuring = startEnd;
//We're done unsecuring
if(startEnd == IQService::END)
ctx->mSecureMode = false;
ctx->mDrawLock.unlock();
if(ctx->proc)
ctx->proc->invalidate(ctx->proc);
}
void QClient::MPDeathNotifier::died() {
mHwcContext->mDrawLock.lock();
ALOGD_IF(QCLIENT_DEBUG, "Media Player died");
mHwcContext->mSecuring = false;
mHwcContext->mSecureMode = false;
mHwcContext->mDrawLock.unlock();
if(mHwcContext->proc)
mHwcContext->proc->invalidate(mHwcContext->proc);
}
static android::status_t screenRefresh(hwc_context_t *ctx) {
status_t result = NO_INIT;
if(ctx->proc) {
ctx->proc->invalidate(ctx->proc);
result = NO_ERROR;
}
return result;
}
static void setExtOrientation(hwc_context_t *ctx, uint32_t orientation) {
ctx->mExtOrientation = orientation;
}
static void isExternalConnected(hwc_context_t* ctx, Parcel* outParcel) {
int connected;
connected = ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected ? 1 : 0;
outParcel->writeInt32(connected);
}
static void getDisplayAttributes(hwc_context_t* ctx, const Parcel* inParcel,
Parcel* outParcel) {
int dpy = inParcel->readInt32();
outParcel->writeInt32(ctx->dpyAttr[dpy].vsync_period);
outParcel->writeInt32(ctx->dpyAttr[dpy].xres);
outParcel->writeInt32(ctx->dpyAttr[dpy].yres);
outParcel->writeFloat(ctx->dpyAttr[dpy].xdpi);
outParcel->writeFloat(ctx->dpyAttr[dpy].ydpi);
//XXX: Need to check what to return for HDMI
outParcel->writeInt32(ctx->mMDP.panel);
}
static void setHSIC(const Parcel* inParcel) {
int dpy = inParcel->readInt32();
ALOGD_IF(0, "In %s: dpy = %d", __FUNCTION__, dpy);
HSICData_t hsic_data;
hsic_data.hue = inParcel->readInt32();
hsic_data.saturation = inParcel->readFloat();
hsic_data.intensity = inParcel->readInt32();
hsic_data.contrast = inParcel->readFloat();
//XXX: Actually set the HSIC data through ABL lib
}
static void setBufferMirrorMode(hwc_context_t *ctx, uint32_t enable) {
ctx->mBufferMirrorMode = enable;
}
static status_t getDisplayVisibleRegion(hwc_context_t* ctx, int dpy,
Parcel* outParcel) {
// Get the info only if the dpy is valid
if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) {
Locker::Autolock _sl(ctx->mDrawLock);
if(dpy && (ctx->mExtOrientation || ctx->mBufferMirrorMode)) {
// Return the destRect on external, if external orienation
// is enabled
outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.left);
outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.top);
outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.right);
outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.bottom);
} else {
outParcel->writeInt32(ctx->mViewFrame[dpy].left);
outParcel->writeInt32(ctx->mViewFrame[dpy].top);
outParcel->writeInt32(ctx->mViewFrame[dpy].right);
outParcel->writeInt32(ctx->mViewFrame[dpy].bottom);
}
return NO_ERROR;
} else {
ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy);
return BAD_VALUE;
}
}
// USed for setting the secondary(hdmi/wfd) status
static void setSecondaryDisplayStatus(hwc_context_t *ctx,
const Parcel* inParcel) {
uint32_t dpy = inParcel->readInt32();
uint32_t status = inParcel->readInt32();
ALOGD_IF(QCLIENT_DEBUG, "%s: dpy = %d status = %s", __FUNCTION__,
dpy, getExternalDisplayState(status));
if(dpy > HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) {
if(dpy == HWC_DISPLAY_VIRTUAL && status == qdutils::EXTERNAL_OFFLINE) {
ctx->mWfdSyncLock.lock();
ctx->mWfdSyncLock.signal();
ctx->mWfdSyncLock.unlock();
} else if(status == qdutils::EXTERNAL_PAUSE) {
handle_pause(ctx, dpy);
} else if(status == qdutils::EXTERNAL_RESUME) {
handle_resume(ctx, dpy);
}
} else {
ALOGE("%s: Invalid dpy %d", __FUNCTION__, dpy);
return;
}
}
static status_t setViewFrame(hwc_context_t* ctx, const Parcel* inParcel) {
int dpy = inParcel->readInt32();
if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) {
Locker::Autolock _sl(ctx->mDrawLock);
ctx->mViewFrame[dpy].left = inParcel->readInt32();
ctx->mViewFrame[dpy].top = inParcel->readInt32();
ctx->mViewFrame[dpy].right = inParcel->readInt32();
ctx->mViewFrame[dpy].bottom = inParcel->readInt32();
ALOGD_IF(QCLIENT_DEBUG, "%s: mViewFrame[%d] = [%d %d %d %d]",
__FUNCTION__, dpy,
ctx->mViewFrame[dpy].left, ctx->mViewFrame[dpy].top,
ctx->mViewFrame[dpy].right, ctx->mViewFrame[dpy].bottom);
return NO_ERROR;
} else {
ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy);
return BAD_VALUE;
}
}
static void toggleDynamicDebug(hwc_context_t* ctx, const Parcel* inParcel) {
int debug_type = inParcel->readInt32();
bool enable = !!inParcel->readInt32();
ALOGD("%s: debug_type: %d enable:%d",
__FUNCTION__, debug_type, enable);
Locker::Autolock _sl(ctx->mDrawLock);
switch (debug_type) {
//break is ignored for DEBUG_ALL to toggle all of them at once
case IQService::DEBUG_ALL:
case IQService::DEBUG_MDPCOMP:
qhwc::MDPComp::dynamicDebug(enable);
if (debug_type != IQService::DEBUG_ALL)
break;
case IQService::DEBUG_VSYNC:
ctx->vstate.debug = enable;
if (debug_type != IQService::DEBUG_ALL)
break;
case IQService::DEBUG_VD:
HWCVirtualVDS::dynamicDebug(enable);
if (debug_type != IQService::DEBUG_ALL)
break;
case IQService::DEBUG_PIPE_LIFECYCLE:
Overlay::debugPipeLifecycle(enable);
if (debug_type != IQService::DEBUG_ALL)
break;
}
}
static void setIdleTimeout(hwc_context_t* ctx, const Parcel* inParcel) {
uint32_t timeout = (uint32_t)inParcel->readInt32();
ALOGD("%s :%u ms", __FUNCTION__, timeout);
Locker::Autolock _sl(ctx->mDrawLock);
MDPComp::setIdleTimeout(timeout);
}
static void setMaxPipesPerMixer(hwc_context_t* ctx, const Parcel* inParcel) {
uint32_t value = (uint32_t)inParcel->readInt32();
ALOGD("%s : setting MaxPipesPerMixer: %d ", __FUNCTION__, value);
Locker::Autolock _sl(ctx->mDrawLock);
MDPComp::setMaxPipesPerMixer(value);
}
static void toggleBWC(hwc_context_t* ctx, const Parcel* inParcel) {
uint32_t enable = (uint32_t)inParcel->readInt32();
if(MDPVersion::getInstance().supportsBWC()) {
Locker::Autolock _sl(ctx->mDrawLock);
ctx->mBWCEnabled = (bool) enable;
ALOGI("%s: Set BWC to %d", __FUNCTION__, enable);
} else {
ALOGI("%s: Target doesn't support BWC", __FUNCTION__);
}
}
static void configureDynRefreshRate(hwc_context_t* ctx,
const Parcel* inParcel) {
uint32_t op = (uint32_t)inParcel->readInt32();
uint32_t refresh_rate = (uint32_t)inParcel->readInt32();
MDPVersion& mdpHw = MDPVersion::getInstance();
uint32_t dpy = HWC_DISPLAY_PRIMARY;
if(mdpHw.isDynFpsSupported()) {
Locker::Autolock _sl(ctx->mDrawLock);
switch (op) {
case DISABLE_METADATA_DYN_REFRESH_RATE:
ctx->mUseMetaDataRefreshRate = false;
setRefreshRate(ctx, dpy, ctx->dpyAttr[dpy].refreshRate);
break;
case ENABLE_METADATA_DYN_REFRESH_RATE:
ctx->mUseMetaDataRefreshRate = true;
setRefreshRate(ctx, dpy, ctx->dpyAttr[dpy].refreshRate);
break;
case SET_BINDER_DYN_REFRESH_RATE:
if(ctx->mUseMetaDataRefreshRate)
ALOGW("%s: Ignoring binder request to change refresh-rate",
__FUNCTION__);
else {
uint32_t rate = roundOff(refresh_rate);
if((rate >= mdpHw.getMinFpsSupported() &&
rate <= mdpHw.getMaxFpsSupported())) {
setRefreshRate(ctx, dpy, rate);
} else {
ALOGE("%s: Requested refresh-rate should be between \
(%d) and (%d). Given (%d)", __FUNCTION__,
mdpHw.getMinFpsSupported(),
mdpHw.getMaxFpsSupported(), rate);
}
}
break;
default:
ALOGE("%s: Invalid op %d",__FUNCTION__,op);
}
}
}
static status_t setPartialUpdateState(hwc_context_t *ctx, uint32_t state) {
ALOGD("%s: state: %d", __FUNCTION__, state);
switch(state) {
case IQService::PREF_PARTIAL_UPDATE:
if(qhwc::MDPComp::setPartialUpdatePref(ctx, true) < 0)
return NO_INIT;
return NO_ERROR;
case IQService::PREF_POST_PROCESSING:
if(qhwc::MDPComp::setPartialUpdatePref(ctx, false) < 0)
return NO_INIT;
qhwc::MDPComp::enablePartialUpdate(false);
return NO_ERROR;
case IQService::ENABLE_PARTIAL_UPDATE:
qhwc::MDPComp::enablePartialUpdate(true);
return NO_ERROR;
default:
ALOGE("%s: Invalid state", __FUNCTION__);
return NO_ERROR;
};
}
static void toggleScreenUpdate(hwc_context_t* ctx, uint32_t on) {
ALOGD("%s: toggle update: %d", __FUNCTION__, on);
if (on == 0) {
ctx->mDrawLock.lock();
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isPause = true;
ctx->mOverlay->configBegin();
ctx->mOverlay->configDone();
ctx->mRotMgr->clear();
if(!Overlay::displayCommit(ctx->dpyAttr[0].fd)) {
ALOGE("%s: Display commit failed", __FUNCTION__);
}
ctx->mDrawLock.unlock();
} else {
ctx->mDrawLock.lock();
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isPause = false;
ctx->mDrawLock.unlock();
ctx->proc->invalidate(ctx->proc);
}
}
static void setS3DMode(hwc_context_t* ctx, int mode) {
if (ctx->mHDMIDisplay) {
if(ctx->mHDMIDisplay->isS3DModeSupported(mode)) {
ALOGD("%s: Force S3D mode to %d", __FUNCTION__, mode);
Locker::Autolock _sl(ctx->mDrawLock);
ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].s3dModeForced = true;
setup3DMode(ctx, HWC_DISPLAY_EXTERNAL, mode);
} else {
ALOGD("%s: mode %d is not supported", __FUNCTION__, mode);
}
} else {
ALOGE("%s: No HDMI Display detected", __FUNCTION__);
}
}
static status_t setActiveConfig(hwc_context_t* ctx, const Parcel *inParcel,
Parcel *outParcel) {
uint32_t index = inParcel->readInt32();
int dpy = inParcel->readInt32();
//Currently only primary supported
if(dpy > HWC_DISPLAY_PRIMARY) {
return BAD_VALUE;
}
Configs *configs = Configs::getInstance();
if(configs == NULL) {
ALOGE("%s(): Unable to acquire a Configs instance", __FUNCTION__);
return INVALID_OPERATION;
}
if(configs->getActiveConfig() == index) {
ALOGI("%s(): Config %u is already set", __FUNCTION__, index);
return ALREADY_EXISTS;
}
ctx->mDrawLock.lock();
//Updates the necessary sysfs nodes and reads split info again which is
//needed to reinitialize composition resources.
if(configs->setActiveConfig(index) == false) {
ALOGE("%s(): Failed to set config %u", __FUNCTION__, index);
ctx->mDrawLock.unlock();
return UNKNOWN_ERROR;
}
qdutils::DisplayAttributes attr = configs->getAttributes(index);
ctx->dpyAttr[dpy].xres = attr.xres;
ctx->dpyAttr[dpy].yres = attr.yres;
ctx->dpyAttr[dpy].fbScaling = ((ctx->dpyAttr[dpy].xres !=
ctx->dpyAttr[dpy].xresFB) || (ctx->dpyAttr[dpy].yres !=
ctx->dpyAttr[dpy].yresFB));
destroyCompositionResources(ctx, dpy);
initCompositionResources(ctx, dpy);
ctx->dpyAttr[dpy].configSwitched = true;
ctx->mDrawLock.unlock();
ctx->proc->invalidate(ctx->proc);
return NO_ERROR;
}
static status_t getActiveConfig(hwc_context_t* ctx, const Parcel *inParcel,
Parcel *outParcel) {
Locker::Autolock _sl(ctx->mDrawLock);
int dpy = inParcel->readInt32();
//Currently only primary supported
if(dpy > HWC_DISPLAY_PRIMARY) {
return BAD_VALUE;
}
Configs *configs = Configs::getInstance();
if(configs == NULL) {
ALOGE("%s(): Unable to acquire a Configs instance", __FUNCTION__);
return INVALID_OPERATION;
}
outParcel->writeInt32(configs->getActiveConfig());
return NO_ERROR;
}
static status_t getConfigCount(hwc_context_t* ctx, const Parcel *inParcel,
Parcel *outParcel) {
Locker::Autolock _sl(ctx->mDrawLock);
int dpy = inParcel->readInt32();
//Currently only primary supported
if(dpy > HWC_DISPLAY_PRIMARY) {
return BAD_VALUE;
}
Configs *configs = Configs::getInstance();
if(configs == NULL) {
ALOGE("%s(): Unable to acquire a Configs instance", __FUNCTION__);
return INVALID_OPERATION;
}
outParcel->writeInt32(configs->getConfigCount());
return NO_ERROR;
}
static status_t getDisplayAttributesForConfig(hwc_context_t* ctx,
const Parcel *inParcel, Parcel *outParcel) {
Locker::Autolock _sl(ctx->mDrawLock);
uint32_t index = inParcel->readInt32();
int dpy = inParcel->readInt32();
//Currently only primary supported
if(dpy > HWC_DISPLAY_PRIMARY) {
return BAD_VALUE;
}
Configs *configs = Configs::getInstance();
if(configs == NULL) {
ALOGE("%s(): Unable to acquire a Configs instance", __FUNCTION__);
return INVALID_OPERATION;
}
//xres, yres are used from the Config class, we assume for now that the
//other params are the same. This might change in the future.
outParcel->writeInt32(ctx->dpyAttr[dpy].vsync_period);
qdutils::DisplayAttributes attr = configs->getAttributes(index);
outParcel->writeInt32(attr.xres);
outParcel->writeInt32(attr.yres);
outParcel->writeFloat(ctx->dpyAttr[dpy].xdpi);
outParcel->writeFloat(ctx->dpyAttr[dpy].ydpi);
outParcel->writeInt32(ctx->mMDP.panel);
return NO_ERROR;
}
/* register/unregister camera service */
static bool setCameraDeathNotifier(
android::sp<QClient::CamDeathNotifier> camDeathNotifier, bool on) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.camera"));
if (binder == 0) {
ALOGW("%s: CameraService not published or dead...", __FUNCTION__);
return false;
}
if(on) {
binder->linkToDeath(camDeathNotifier);
} else {
binder->unlinkToDeath(camDeathNotifier);
}
return true;
}
static bool updateDisplayBWCapForCam(bool on) {
char sysfsPath[255];
char bw[64];
int bw_flag = 0; // to reset to default.
memset(sysfsPath, 0, sizeof(sysfsPath));
snprintf(sysfsPath , sizeof(sysfsPath), FILE_MAX_MDSSBW_FLAG);
int sysfsFd = open(sysfsPath, O_RDWR);
if(sysfsFd < 0 ) {
ALOGE("%s: Status: %d Error in opening %s: %s",
__FUNCTION__, on, sysfsPath, strerror(errno));
return false;
}
if(on) {
bw_flag = MDSS_MAX_BW_LIMIT_CAMERA;
}
snprintf(bw, sizeof(bw), "%d", bw_flag);
ssize_t bytes = pwrite(sysfsFd, bw, strlen(bw), 0);
if(bytes < 0) {
ALOGE ("%s: Unable to write into %s node %s",
__FUNCTION__, sysfsPath, strerror(errno));
close(sysfsFd);
return false;
}
close(sysfsFd);
return true;
}
static void setCameraStatus(hwc_context_t* ctx,
android::sp<QClient::CamDeathNotifier> camDeathNotifier, uint32_t on) {
//Currently we need this only for 8952.
if(!MDPVersion::getInstance().is8x52()) {
ALOGI("%s Not 8952?? return", __FUNCTION__);
return;
}
if(!setCameraDeathNotifier(camDeathNotifier, on)) {
ALOGE("%s failed in updateCameraStatus", __FUNCTION__);
return;
}
if(!updateDisplayBWCapForCam(on)) {
ALOGE("%s failed in updateDisplayBWCap", __FUNCTION__);
return;
}
// Trigger a screen update so that our BW setting will reflect
// atleast by next vsync.
screenRefresh(ctx);
}
void QClient::CamDeathNotifier::binderDied(const wp<IBinder>& who) {
//If Cameraservice abruptly gone, reset mdss bw caps
//This new cap will be applicable from next frame onwards
if(!updateDisplayBWCapForCam(false)) {
ALOGE("%s failed in updateDisplayBWCap", __FUNCTION__);
}
}
status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
Parcel* outParcel) {
status_t ret = NO_ERROR;
switch(command) {
case IQService::SECURING:
securing(mHwcContext, inParcel->readInt32());
break;
case IQService::UNSECURING:
unsecuring(mHwcContext, inParcel->readInt32());
break;
case IQService::SCREEN_REFRESH:
return screenRefresh(mHwcContext);
break;
case IQService::EXTERNAL_ORIENTATION:
setExtOrientation(mHwcContext, inParcel->readInt32());
break;
case IQService::BUFFER_MIRRORMODE:
setBufferMirrorMode(mHwcContext, inParcel->readInt32());
break;
case IQService::GET_DISPLAY_VISIBLE_REGION:
ret = getDisplayVisibleRegion(mHwcContext, inParcel->readInt32(),
outParcel);
break;
case IQService::CHECK_EXTERNAL_STATUS:
isExternalConnected(mHwcContext, outParcel);
break;
case IQService::GET_DISPLAY_ATTRIBUTES:
getDisplayAttributes(mHwcContext, inParcel, outParcel);
break;
case IQService::SET_HSIC_DATA:
setHSIC(inParcel);
break;
case IQService::SET_SECONDARY_DISPLAY_STATUS:
setSecondaryDisplayStatus(mHwcContext, inParcel);
break;
case IQService::SET_VIEW_FRAME:
setViewFrame(mHwcContext, inParcel);
break;
case IQService::DYNAMIC_DEBUG:
toggleDynamicDebug(mHwcContext, inParcel);
break;
case IQService::SET_IDLE_TIMEOUT:
setIdleTimeout(mHwcContext, inParcel);
break;
case IQService::SET_MAX_PIPES_PER_MIXER:
setMaxPipesPerMixer(mHwcContext, inParcel);
break;
case IQService::SET_PARTIAL_UPDATE:
ret = setPartialUpdateState(mHwcContext, inParcel->readInt32());
break;
case IQService::TOGGLE_BWC:
toggleBWC(mHwcContext, inParcel);
break;
case IQService::CONFIGURE_DYN_REFRESH_RATE:
configureDynRefreshRate(mHwcContext, inParcel);
break;
case IQService::TOGGLE_SCREEN_UPDATE:
toggleScreenUpdate(mHwcContext, inParcel->readInt32());
break;
case IQService::SET_S3D_MODE:
setS3DMode(mHwcContext, inParcel->readInt32());
break;
case IQService::SET_ACTIVE_CONFIG:
ret = setActiveConfig(mHwcContext, inParcel, outParcel);
break;
case IQService::GET_ACTIVE_CONFIG:
ret = getActiveConfig(mHwcContext, inParcel, outParcel);
break;
case IQService::GET_CONFIG_COUNT:
ret = getConfigCount(mHwcContext, inParcel, outParcel);
break;
case IQService::GET_DISPLAY_ATTRIBUTES_FOR_CONFIG:
ret = getDisplayAttributesForConfig(mHwcContext, inParcel,
outParcel);
case IQService::QDCM_SVC_CMDS:
qdcmCmdsHandler(mHwcContext, inParcel, outParcel);
break;
case IQService::SET_CAMERA_STATUS:
setCameraStatus(mHwcContext,
mCamDeathNotifier, inParcel->readInt32());
break;
default:
ret = NO_ERROR;
}
return ret;
}
}

View File

@@ -1,76 +0,0 @@
/*
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR CLIENTS; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ANDROID_QCLIENT_H
#define ANDROID_QCLIENT_H
#include <utils/Errors.h>
#include <sys/types.h>
#include <cutils/log.h>
#include <utils/RefBase.h>
#include <binder/IServiceManager.h>
#include <media/IMediaDeathNotifier.h>
#include <IQClient.h>
struct hwc_context_t;
class Params;
namespace qClient {
// ----------------------------------------------------------------------------
class QClient : public BnQClient {
public:
QClient(hwc_context_t *ctx);
virtual ~QClient();
virtual android::status_t notifyCallback(uint32_t command,
const android::Parcel* inParcel,
android::Parcel* outParcel);
//Notifies camera service death
class CamDeathNotifier : public IBinder::DeathRecipient {
public:
CamDeathNotifier(){}
virtual void binderDied(const android::wp<IBinder>& who);
};
private:
//Notifies of Media Player death
class MPDeathNotifier : public android::IMediaDeathNotifier {
public:
MPDeathNotifier(hwc_context_t* ctx) : mHwcContext(ctx){}
virtual void died();
hwc_context_t *mHwcContext;
};
hwc_context_t *mHwcContext;
const android::sp<android::IMediaDeathNotifier> mMPDeathNotifier;
const android::sp<QClient::CamDeathNotifier> mCamDeathNotifier;
};
}; // namespace qClient
#endif // ANDROID_QCLIENT_H

View File

@@ -1,292 +0,0 @@
/*
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <hwc_qdcm.h>
#include <hwc_utils.h>
#include <utils/String16.h>
#include <mdp_version.h>
#include "mode_manager.h"
#include "libmm-disp-apis.h"
#include "IQService.h"
using namespace android;
using namespace qService;
using namespace qhwc;
using namespace qmode;
namespace qQdcm {
//----------------------------------------------------------------------------
void qdcmInitContext(hwc_context_t *ctx)
{
loadQdcmLibrary(ctx);
}
void qdcmCloseContext(hwc_context_t *ctx)
{
if (ctx->mQdcmInfo.mQdcmMode) {
unloadQdcmLibrary(ctx);
}
}
void qdcmApplyDefaultAfterBootAnimationDone(hwc_context_t *ctx)
{
if (ctx->mQdcmInfo.mQdcmMode)
ctx->mQdcmInfo.mQdcmMode->applyDefaultMode(0);
}
static void qdcmSetActiveMode(hwc_context_t *ctx, const Parcel *in, Parcel *out)
{
int ret = 0;
if (ctx->mQdcmInfo.mQdcmMode && in && out) {
struct SET_MODE_PROP_IN params =
{ (disp_id_type)in->readInt32(), in->readInt32()};
ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_SET_ACTIVE_MODE,
(void *)&params, (void *)NULL);
out->writeInt32(ret); //return operation status via binder.
}
}
static void qdcmSetDefaultMode(hwc_context_t *ctx, const Parcel *in, Parcel *out)
{
int ret = 0;
if (ctx->mQdcmInfo.mQdcmMode && in && out) {
struct SET_MODE_PROP_IN params =
{ (disp_id_type)in->readInt32(), in->readInt32()};
ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_SET_DEFAULT_MODE,
(void *)&params, (void *)NULL);
out->writeInt32(ret); //return operation status via binder.
}
}
static void qdcmGetDefaultMode(hwc_context_t *ctx,
const Parcel *in, Parcel *out)
{
int ret = 0;
if (ctx->mQdcmInfo.mQdcmMode && in && out) {
int params = in->readInt32();
int modeid = 0;
ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_GET_DEFAULT_MODE,
(const void *)&params, (void *)&modeid);
out->writeInt32(modeid);
out->writeInt32(ret); //return operation status via binder.
}
}
static void qdcmGetColorBalanceRange(hwc_context_t *ctx __unused,
const Parcel *in __unused, Parcel *out __unused)
{
}
static void qdcmGetColorBalance(hwc_context_t *ctx,
const Parcel *in, Parcel *out)
{
int ret = 0;
if (ctx->mQdcmInfo.mQdcmMode && in && out) {
int params = in->readInt32();
int warmness = 0;
ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_GET_CB,
(const void *)&params, (void *)&warmness);
out->writeInt32(warmness);
out->writeInt32(ret); //return operation status via binder.
}
}
static void qdcmSetColorBalance(hwc_context_t *ctx,
const Parcel *in, Parcel *out)
{
int ret = 0;
if (ctx->mQdcmInfo.mQdcmMode && in && out) {
struct SET_CB_IN params =
{ (disp_id_type)in->readInt32(), in->readInt32() };
ALOGD_IF(QDCM_DEBUG, "%s dispID = %d, warmness = %d\n",
__FUNCTION__, params.id, params.warmness);
ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_SET_CB,
(const void *)&params, NULL);
out->writeInt32(ret); //return operation status via binder.
}
}
static void qdcmSaveModeV2(hwc_context_t *ctx, const Parcel *in, Parcel *out)
{
int ret = 0;
if (ctx->mQdcmInfo.mQdcmMode && in && out) {
struct SAVE_DISPLAY_MODE_V2_IN params =
{ (disp_id_type)in->readInt32(),
in->readCString(),
(uint32_t)in->readInt32(),
in->readInt32()
};
int value = 0;
ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_SAVE_MODE_V2,
(const void *)&params, (void *)&value);
out->writeInt32(value);
out->writeInt32(ret); //return operation status via binder.
}
}
static void qdcmSetPaConfig(hwc_context_t *ctx, const Parcel *in, Parcel *out)
{
int ret = 0;
if (ctx->mQdcmInfo.mQdcmMode && in && out) {
struct SET_PA_CONFIG_IN params;
params.id = (disp_id_type)in->readInt32();
params.pa.ops = in->readInt32();
params.pa.data.hue = in->readInt32();
params.pa.data.saturation = in->readInt32();
params.pa.data.value = in->readInt32();
params.pa.data.contrast = in->readInt32();
params.pa.data.sat_thresh = in->readInt32();
ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_SET_PA_CONFIG,
(const void *)&params, NULL);
out->writeInt32(ret); //return operation status via binder.
}
}
static void qdcmGetPaConfig(hwc_context_t *ctx, const Parcel *in, Parcel *out)
{
int ret = 0;
if (ctx->mQdcmInfo.mQdcmMode && in && out) {
int params = in->readInt32();
struct disp_pa_config value;
ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_GET_PA_CONFIG,
(const void *)&params, (void *)&value);
out->writeInt32(value.ops);
out->writeInt32(value.data.hue);
out->writeInt32(value.data.saturation);
out->writeInt32(value.data.value);
out->writeInt32(value.data.contrast);
out->writeInt32(value.data.sat_thresh);
out->writeInt32(ret); //return operation status via binder.
}
}
static void qdcmGetPaRange(hwc_context_t *ctx, const Parcel *in, Parcel *out)
{
int ret = 0;
if (ctx->mQdcmInfo.mQdcmMode && in && out) {
int params = in->readInt32();
struct disp_pa_range value;
ret = ctx->mQdcmInfo.mQdcmMode->requestRoute((int)CMD_GET_PA_RANGE,
(const void *)&params, (void *)&value);
out->writeInt32(value.max.hue);
out->writeInt32(value.max.saturation);
out->writeInt32(value.max.value);
out->writeInt32(value.max.contrast);
out->writeInt32(value.max.sat_thresh);
out->writeInt32(value.min.hue);
out->writeInt32(value.min.saturation);
out->writeInt32(value.min.value);
out->writeInt32(value.min.contrast);
out->writeInt32(value.min.sat_thresh);
out->writeInt32(ret); //return operation status via binder.
}
}
void qdcmCmdsHandler(hwc_context_t *ctx, const Parcel *in, Parcel *out)
{
int subcmd = in->readInt32();
ALOGD_IF(QDCM_DEBUG, "%s enter subcmd = %d\n", __FUNCTION__, subcmd);
switch (subcmd) {
case CMD_SET_ACTIVE_MODE:
qdcmSetActiveMode(ctx, in, out);
break;
case CMD_SET_DEFAULT_MODE:
qdcmSetDefaultMode(ctx, in, out);
break;
case CMD_GET_DEFAULT_MODE:
qdcmGetDefaultMode(ctx, in, out);
break;
case CMD_GET_CB_RANGE:
qdcmGetColorBalanceRange(ctx, in, out);
break;
case CMD_GET_CB:
qdcmGetColorBalance(ctx, in, out);
break;
case CMD_SET_CB:
qdcmSetColorBalance(ctx, in, out);
break;
case CMD_SAVE_MODE_V2:
qdcmSaveModeV2(ctx, in, out);
break;
case CMD_SET_PA_CONFIG:
qdcmSetPaConfig(ctx, in, out);
break;
case CMD_GET_PA_CONFIG:
qdcmGetPaConfig(ctx, in, out);
break;
case CMD_GET_PA_RANGE:
qdcmGetPaRange(ctx, in, out);
break;
}
}
} //namespace qQdcm

View File

@@ -1,94 +0,0 @@
/*
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ANDROID_QDCM_H
#define ANDROID_QDCM_H
#include <utils/Errors.h>
#include <sys/types.h>
#include <cutils/log.h>
#include <hwc_utils.h>
#include <dlfcn.h>
#include <binder/Parcel.h>
#include <cutils/properties.h>
#define QDCM_DEBUG 0
namespace qmode {
class ModeManager;
}
using namespace android;
namespace qQdcm {
// ----------------------------------------------------------------------------
//function prototypes used for QDCM library and service
static inline void loadQdcmLibrary(hwc_context_t *ctx)
{
ctx->mQdcmInfo.mQdcmLib = dlopen("libmm-qdcm.so", RTLD_NOW);
qmode::ModeManager* (*factory)() = NULL;
if (ctx->mQdcmInfo.mQdcmLib)
*(void **)&factory = dlsym(ctx->mQdcmInfo.mQdcmLib, "getObject");
if (factory) {
ctx->mQdcmInfo.mQdcmMode = factory();
} else {
ctx->mQdcmInfo.mQdcmMode = NULL;
ALOGE("QDCM LIbrary load failing!");
}
ALOGD_IF(QDCM_DEBUG, "QDCM LIbrary loaded successfully!");
}
static inline void unloadQdcmLibrary(hwc_context_t *ctx)
{
void (*destroy)(qmode::ModeManager*) = NULL;
if (ctx->mQdcmInfo.mQdcmLib) {
*(void **)&destroy = dlsym(ctx->mQdcmInfo.mQdcmLib, "deleteObject");
if (destroy) {
destroy(ctx->mQdcmInfo.mQdcmMode);
ctx->mQdcmInfo.mQdcmMode = NULL;
}
dlclose(ctx->mQdcmInfo.mQdcmLib);
ctx->mQdcmInfo.mQdcmLib = NULL;
}
}
void qdcmInitContext(hwc_context_t *);
void qdcmCloseContext(hwc_context_t *);
void qdcmApplyDefaultAfterBootAnimationDone(hwc_context_t *);
void qdcmCmdsHandler(hwc_context_t*, const Parcel*, Parcel*);
}; // namespace qQdcm
#endif // ANDROID_QDCM_H

View File

@@ -1,79 +0,0 @@
/*
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <hwc_qdcm.h>
#include <hwc_utils.h>
#include <IQService.h>
#include <mdp_version.h>
#include <dlfcn.h>
using namespace android;
using namespace qService;
using namespace qhwc;
namespace qQdcm {
//----------------------------------------------------------------------------
void qdcmInitContext(hwc_context_t *ctx)
{
}
void qdcmCloseContext(hwc_context_t *ctx)
{
}
void qdcmApplyDefaultAfterBootAnimationDone(hwc_context_t *ctx)
{
int ret = 0;
int (*applyMode)(int) = NULL;
void *modeHandle = NULL;
modeHandle = dlopen("libmm-qdcm.so", RTLD_NOW);
if (modeHandle) {
*(void **)&applyMode = dlsym(modeHandle, "applyDefaults");
if (applyMode) {
ret = applyMode(HWC_DISPLAY_PRIMARY);
if (ret)
ALOGE("%s: Not able to apply default mode", __FUNCTION__);
} else {
ALOGE("%s: No symbol applyDefaults found", __FUNCTION__);
}
dlclose(modeHandle);
} else {
ALOGE("%s: Not able to load libmm-qdcm.so", __FUNCTION__);
}
}
//do nothing in case qdcm legacy implementation.
void qdcmCmdsHandler(hwc_context_t *ctx, const Parcel *in, Parcel *out)
{
}
} //namespace qQdcm

View File

@@ -1,272 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 2012-14, The Linux Foundation. All rights reserved.
*
* Not a Contribution, Apache license notifications and license are
* retained for attribution purposes only.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define UEVENT_DEBUG 0
#include <hardware_legacy/uevent.h>
#include <utils/Log.h>
#include <sys/resource.h>
#include <sys/prctl.h>
#include <string.h>
#include <stdlib.h>
#include "hwc_utils.h"
#include "hwc_fbupdate.h"
#include "hwc_mdpcomp.h"
#include "hwc_copybit.h"
#include "comptype.h"
#include "hdmi.h"
#include "hwc_virtual.h"
#include "mdp_version.h"
using namespace overlay;
namespace qhwc {
#define HWC_UEVENT_SWITCH_STR "change@/devices/virtual/switch/"
#define HWC_UEVENT_THREAD_NAME "hwcUeventThread"
/* Parse uevent data for devices which we are interested */
static int getConnectedDisplay(hwc_context_t* ctx, const char* strUdata)
{
int ret = -1;
// Switch node for HDMI as PRIMARY/EXTERNAL
if(strcasestr("change@/devices/virtual/switch/hdmi", strUdata)) {
if (ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) {
ret = HWC_DISPLAY_PRIMARY;
} else {
ret = HWC_DISPLAY_EXTERNAL;
}
}
return ret;
}
static bool getPanelResetStatus(hwc_context_t* ctx, const char* strUdata, int len)
{
const char* iter_str = strUdata;
if (strcasestr("change@/devices/virtual/graphics/fb0", strUdata)) {
while(((iter_str - strUdata) <= len) && (*iter_str)) {
char* pstr = strstr(iter_str, "PANEL_ALIVE=0");
if (pstr != NULL) {
ALOGI("%s: got change event in fb0 with PANEL_ALIVE=0",
__FUNCTION__);
ctx->mPanelResetStatus = true;
return true;
}
iter_str += strlen(iter_str)+1;
}
}
return false;
}
/* Parse uevent data for action requested for the display */
static int getConnectedState(const char* strUdata, int len)
{
const char* iter_str = strUdata;
while(((iter_str - strUdata) <= len) && (*iter_str)) {
char* pstr = strstr(iter_str, "SWITCH_STATE=");
if (pstr != NULL) {
return (atoi(pstr + strlen("SWITCH_STATE=")));
}
iter_str += strlen(iter_str)+1;
}
return -1;
}
static void handle_uevent(hwc_context_t* ctx, const char* udata, int len)
{
bool bpanelReset = getPanelResetStatus(ctx, udata, len);
if (bpanelReset) {
ctx->proc->invalidate(ctx->proc);
return;
}
int dpy = getConnectedDisplay(ctx, udata);
if(dpy < 0) {
ALOGD_IF(UEVENT_DEBUG, "%s: Not disp Event ", __FUNCTION__);
return;
}
int switch_state = getConnectedState(udata, len);
ALOGE_IF(UEVENT_DEBUG,"%s: uevent received: %s switch state: %d",
__FUNCTION__,udata, switch_state);
switch(switch_state) {
case EXTERNAL_OFFLINE:
{
/* Display not connected */
if(!ctx->dpyAttr[dpy].connected){
ALOGE_IF(UEVENT_DEBUG,"%s: Ignoring EXTERNAL_OFFLINE event"
"for display: %d", __FUNCTION__, dpy);
break;
}
ctx->mDrawLock.lock();
handle_offline(ctx, dpy);
ctx->mDrawLock.unlock();
/* We need to send hotplug to SF only when we are disconnecting
* HDMI as an external display. */
if(dpy == HWC_DISPLAY_EXTERNAL) {
ALOGI("%s: Sending EXTERNAL OFFLINE event", __FUNCTION__);
ctx->proc->hotplug(ctx->proc, dpy, EXTERNAL_OFFLINE);
}
// Report Hotplug via CEC HAL
ctx->mQService->onHdmiHotplug((int)ctx->dpyAttr[dpy].connected);
//On 8994, 8992 due to hardware limitations, we disable bwc
//when HDMI intf is active
if((qdutils::MDPVersion::getInstance().is8994() or
qdutils::MDPVersion::getInstance().is8992()) and
qdutils::MDPVersion::getInstance().supportsBWC()) {
Locker::Autolock _l(ctx->mDrawLock);
ctx->mBWCEnabled = true;
}
break;
}
case EXTERNAL_ONLINE:
{
/* Display already connected */
if(ctx->dpyAttr[dpy].connected) {
ALOGE_IF(UEVENT_DEBUG,"%s: Ignoring EXTERNAL_ONLINE event"
"for display: %d", __FUNCTION__, dpy);
break;
}
//On 8994, 8992 due to hardware limitations, we disable bwc
//when HDMI intf is active
if((qdutils::MDPVersion::getInstance().is8994() or
qdutils::MDPVersion::getInstance().is8992()) and
qdutils::MDPVersion::getInstance().supportsBWC()) {
Locker::Autolock _l(ctx->mDrawLock);
ctx->mBWCEnabled = false;
}
if (ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) {
ctx->mDrawLock.lock();
handle_online(ctx, dpy);
ctx->mDrawLock.unlock();
ctx->mQService->onHdmiHotplug(ctx->dpyAttr[dpy].connected);
ctx->proc->invalidate(ctx->proc);
break;
} else {
ctx->mDrawLock.lock();
//Force composition to give up resources like pipes and
//close fb. For example if assertive display is going on,
//fb2 could be open, thus connecting Layer Mixer#0 to
//WriteBack module. If HDMI attempts to open fb1, the driver
//will try to attach Layer Mixer#0 to HDMI INT, which will
//fail, since Layer Mixer#0 is still connected to WriteBack.
//This block will force composition to close fb2 in above
//example.
ctx->dpyAttr[dpy].isConfiguring = true;
ctx->mDrawLock.unlock();
ctx->proc->invalidate(ctx->proc);
}
//2 cycles for slower content
usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
* 2 / 1000);
if(isVDConnected(ctx)) {
// Do not initiate WFD teardown if WFD architecture is based
// on VDS mechanism.
// WFD Stack listens to HDMI intent and initiates virtual
// display teardown.
// ToDo: Currently non-WFD Virtual display clients do not
// involve HWC. If there is a change, we need to come up
// with mechanism of how to address non-WFD Virtual display
// clients + HDMI
ctx->mWfdSyncLock.lock();
ALOGD_IF(HWC_WFDDISPSYNC_LOG,
"%s: Waiting for wfd-teardown to be signalled",
__FUNCTION__);
ctx->mWfdSyncLock.wait();
ALOGD_IF(HWC_WFDDISPSYNC_LOG,
"%s: Teardown signalled. Completed waiting in"
"uevent thread", __FUNCTION__);
ctx->mWfdSyncLock.unlock();
}
// If FB open fails ignore this hotplug event
int error = ctx->mHDMIDisplay->configure();
if (error < 0) {
ALOGE("%s: Open Framebuffer for dpy = %d", __FUNCTION__, dpy);
ctx->mDrawLock.lock();
ctx->dpyAttr[dpy].isConfiguring = false;
ctx->mDrawLock.unlock();
break;
}
ctx->mHDMIDisplay->activateDisplay();
ctx->mDrawLock.lock();
updateDisplayInfo(ctx, dpy);
initCompositionResources(ctx, dpy);
ctx->dpyAttr[dpy].isPause = false;
ctx->dpyAttr[dpy].connected = true;
ctx->dpyAttr[dpy].isConfiguring = true;
ctx->mDrawLock.unlock();
/* External display is HDMI */
ALOGI("%s: Sending EXTERNAL ONLINE event", __FUNCTION__);
ctx->proc->hotplug(ctx->proc, dpy, EXTERNAL_ONLINE);
ctx->mQService->onHdmiHotplug(ctx->dpyAttr[dpy].connected);
break;
}
default:
{
ALOGE("%s: Invalid state to switch:%d", __FUNCTION__, switch_state);
break;
}
}
}
static void *uevent_loop(void *param)
{
int len = 0;
static char udata[PAGE_SIZE];
hwc_context_t * ctx = reinterpret_cast<hwc_context_t *>(param);
char thread_name[64] = HWC_UEVENT_THREAD_NAME;
prctl(PR_SET_NAME, (unsigned long) &thread_name, 0, 0, 0);
setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
if(!uevent_init()) {
ALOGE("%s: failed to init uevent ",__FUNCTION__);
return NULL;
}
while(1) {
len = uevent_next_event(udata, (int)sizeof(udata) - 2);
handle_uevent(ctx, udata, len);
}
return NULL;
}
void init_uevent_thread(hwc_context_t* ctx)
{
pthread_t uevent_thread;
int ret;
ALOGI("Initializing UEVENT Thread");
ret = pthread_create(&uevent_thread, NULL, uevent_loop, (void*) ctx);
if (ret) {
ALOGE("%s: failed to create %s: %s", __FUNCTION__,
HWC_UEVENT_THREAD_NAME, strerror(ret));
}
}
}; //namespace

File diff suppressed because it is too large Load Diff

View File

@@ -1,795 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C)2012-2014, The Linux Foundation. All rights reserved.
*
* Not a Contribution, Apache license notifications and license are retained
* for attribution purposes only.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef HWC_UTILS_H
#define HWC_UTILS_H
#define DEBUG_MDPDOWNSCALE 0
#define HWC_REMOVE_DEPRECATED_VERSIONS 1
#include <fcntl.h>
#include <math.h>
#include <hardware/hwcomposer.h>
#include <gr.h>
#include <gralloc_priv.h>
#include <utils/String8.h>
#include "qdMetaData.h"
#include "mdp_version.h"
#include <overlayUtils.h>
#include <overlayRotator.h>
#include <EGL/egl.h>
#include <QService.h>
#define ALIGN_TO(x, align) (((x) + ((align)-1)) & ~((align)-1))
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
#define MAX_NUM_APP_LAYERS 32
#define MAX_NUM_BLEND_STAGES 16
#define MIN_DISPLAY_XRES 200
#define MIN_DISPLAY_YRES 200
#define HWC_WFDDISPSYNC_LOG 0
#define STR(f) #f;
// Max number of PTOR layers handled
#define MAX_PTOR_LAYERS 2
//Fwrd decls
struct hwc_context_t;
namespace ovutils = overlay::utils;
namespace qmode {
class ModeManager;
}
namespace overlay {
class Overlay;
class Rotator;
class RotMgr;
}
namespace qhwc {
//fwrd decl
class QueuedBufferStore;
class HDMIDisplay;
class VirtualDisplay;
class IFBUpdate;
class IVideoOverlay;
class MDPComp;
class CopyBit;
class HwcDebug;
class AssertiveDisplay;
class HWCVirtualVDS;
struct MDPInfo {
int version;
char panel;
bool hasOverlay;
};
struct DisplayAttributes {
uint32_t refreshRate;
uint32_t dynRefreshRate;
uint32_t vsync_period; //nanos
uint32_t xres;
uint32_t yres;
uint32_t stride;
float xdpi;
float ydpi;
bool secure;
uint32_t fbformat;
int fd;
bool connected; //Applies only to pluggable disp.
//Connected does not mean it ready to use.
//It should be active also. (UNBLANKED)
bool isActive;
// In pause state, composition is bypassed
// used for WFD displays and in QDCM calibration mode
bool isPause;
// To trigger padding round to clean up mdp
// pipes
bool isConfiguring;
// Indicates whether external/virtual display is in MDP scaling mode
bool mMDPScalingMode;
// Ext dst Rect
hwc_rect_t mDstRect;
//Action safe attributes
// Flag to indicate the presence of action safe dimensions for external
bool mActionSafePresent;
int mAsWidthRatio;
int mAsHeightRatio;
// This is the 3D mode to which the TV is set
// The mode may be set via the appearance of a layer with 3D format
// or by forcing the mode via binder.
// If the mode is set via binder, the s3dModeForced flag is set, so that the
// mode is not changed back when the 3D video layer drops out.
// If the forced mode is different from the one in 3D video, the results
// are unpredictable. The assumption is made here that the caller forcing
// the mode via binder knows the right formats to use.
// The s3dModeForced flag is also used to force 2D if the s3dMode is
// HDMI_S3D_NONE
int s3dMode;
bool s3dModeForced;
//If property fbsize set via adb shell debug.hwc.fbsize = XRESxYRES
//following fields are used.
//Also used when the actual panel's dimensions change and FB remains
//constant
bool fbScaling;
uint32_t xresFB; //FB's width, by default from VSCREEN overridden by prop
uint32_t yresFB; //FB's height, by default from VSCREEN overridden by prop
float fbWidthScaleRatio; // Panel Width / FB Width
float fbHeightScaleRatio; // Panel Height / FB Height
//If configuration changed dynamically without subsequent GEOMETRY changes
//we may still need to adjust destination params
bool configSwitched;
};
struct ListStats {
int numAppLayers; //Total - 1, excluding FB layer.
int skipCount;
int fbLayerIndex; //Always last for now. = numAppLayers
//Video specific
int yuvCount;
int yuvIndices[MAX_NUM_APP_LAYERS];
bool preMultipliedAlpha;
int yuv4k2kIndices[MAX_NUM_APP_LAYERS];
int yuv4k2kCount;
// Notifies hwcomposer about the start and end of animation
// This will be set to true during animation, otherwise false.
bool isDisplayAnimating;
bool secureUI; // Secure display layer
bool isSecurePresent;
hwc_rect_t lRoi; //left ROI
hwc_rect_t rRoi; //right ROI. Unused in single DSI panels.
//App Buffer Composition index
int renderBufIndexforABC;
// Secure RGB specific
int secureRGBCount;
int secureRGBIndices[MAX_NUM_APP_LAYERS];
//dyn refresh rate-Client requested refreshrate
uint32_t refreshRateRequest;
// Flag related to windowboxing feature
bool mAIVVideoMode;
// curser layer info
bool cursorLayerPresent;
};
//PTOR Comp info
struct PtorInfo {
int count;
int layerIndex[MAX_PTOR_LAYERS];
hwc_rect_t displayFrame[MAX_PTOR_LAYERS];
bool isActive() { return (count>0); }
int getPTORArrayIndex(int index) {
int idx = -1;
for(int i = 0; i < count; i++) {
if(index == layerIndex[i])
idx = i;
}
return idx;
}
};
struct LayerProp {
uint32_t mFlags; //qcom specific layer flags
LayerProp():mFlags(0){};
};
struct VsyncState {
bool enable;
bool fakevsync;
bool debug;
};
struct BwcPM {
static void setBwc(const hwc_context_t *ctx, const int& dpy,
const private_handle_t *hnd,
const hwc_rect_t& crop, const hwc_rect_t& dst,
const int& transform, const int& downscale,
ovutils::eMdpFlags& mdpFlags);
};
// LayerProp::flag values
enum {
HWC_MDPCOMP = 0x00000001,
HWC_COPYBIT = 0x00000002,
};
// AIV specific flags
enum {
HWC_AIV_VIDEO = 0x80000000,
HWC_AIV_CC = 0x40000000,
};
// HAL specific features
enum {
HWC_COLOR_FILL = 0x00000008,
HWC_FORMAT_RB_SWAP = 0x00000040,
};
/* External Display states */
enum {
EXTERNAL_OFFLINE = 0,
EXTERNAL_ONLINE,
EXTERNAL_PAUSE,
EXTERNAL_RESUME,
EXTERNAL_MAXSTATES
};
class LayerRotMap {
public:
LayerRotMap() { reset(); }
void add(hwc_layer_1_t* layer, overlay::Rotator *rot);
//Resets the mapping of layer to rotator
void reset();
//Clears mappings and existing rotator fences
//Intended to be used during errors
void clear();
uint32_t getCount() const;
hwc_layer_1_t* getLayer(uint32_t index) const;
overlay::Rotator* getRot(uint32_t index) const;
bool isRotCached(uint32_t index) const;
void setReleaseFd(const int& fence);
private:
hwc_layer_1_t* mLayer[overlay::RotMgr::MAX_ROT_SESS];
overlay::Rotator* mRot[overlay::RotMgr::MAX_ROT_SESS];
uint32_t mCount;
};
inline uint32_t LayerRotMap::getCount() const {
return mCount;
}
inline hwc_layer_1_t* LayerRotMap::getLayer(uint32_t index) const {
if(index >= mCount) return NULL;
return mLayer[index];
}
inline overlay::Rotator* LayerRotMap::getRot(uint32_t index) const {
if(index >= mCount) return NULL;
return mRot[index];
}
inline hwc_rect_t integerizeSourceCrop(const hwc_frect_t& cropF) {
hwc_rect_t cropI = {0,0,0,0};
cropI.left = int(floorf(cropF.left));
cropI.top = int(floorf(cropF.top));
cropI.right = int(ceilf(cropF.right));
cropI.bottom = int(ceilf(cropF.bottom));
return cropI;
}
inline bool isNonIntegralSourceCrop(const hwc_frect_t& cropF) {
if(cropF.left - roundf(cropF.left) ||
cropF.top - roundf(cropF.top) ||
cropF.right - roundf(cropF.right) ||
cropF.bottom - roundf(cropF.bottom))
return true;
else
return false;
}
// -----------------------------------------------------------------------------
// Utility functions - implemented in hwc_utils.cpp
void dumpLayer(hwc_layer_1_t const* l);
void setListStats(hwc_context_t *ctx, hwc_display_contents_1_t *list,
int dpy);
int initContext(hwc_context_t *ctx);
void closeContext(hwc_context_t *ctx);
//Crops source buffer against destination and FB boundaries
void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst,
const hwc_rect_t& scissor, int orient);
void getNonWormholeRegion(hwc_display_contents_1_t* list,
hwc_rect_t& nwr);
bool isSecuring(hwc_context_t* ctx, hwc_layer_1_t const* layer);
bool isSecureModePolicy(int mdpVersion);
// Returns true, if the input layer format is supported by rotator
bool isRotatorSupportedFormat(private_handle_t *hnd);
//Returns true, if the layer is YUV or the layer has been rendered by CPU
bool isRotationDoable(hwc_context_t *ctx, private_handle_t *hnd);
bool isAlphaScaled(hwc_layer_1_t const* layer);
bool needsScaling(hwc_layer_1_t const* layer);
bool isDownscaleRequired(hwc_layer_1_t const* layer);
bool isDownscaleWithinThreshold(hwc_layer_1_t const* layer, float threshold);
bool needsScalingWithSplit(hwc_context_t* ctx, hwc_layer_1_t const* layer,
const int& dpy);
void sanitizeSourceCrop(hwc_rect_t& cropL, hwc_rect_t& cropR,
private_handle_t *hnd);
bool isAlphaPresent(hwc_layer_1_t const* layer);
bool isAlphaPresentinFB(hwc_context_t* ctx, int dpy);
int hwc_vsync_control(hwc_context_t* ctx, int dpy, int enable);
int getBlending(int blending);
bool isGLESOnlyComp(hwc_context_t *ctx, const int& dpy);
void reset_layer_prop(hwc_context_t* ctx, int dpy, int numAppLayers);
bool isAbcInUse(hwc_context_t *ctx);
void dumpBuffer(private_handle_t *ohnd, char *bufferName);
void updateDisplayInfo(hwc_context_t* ctx, int dpy);
void resetDisplayInfo(hwc_context_t* ctx, int dpy);
void initCompositionResources(hwc_context_t* ctx, int dpy);
void destroyCompositionResources(hwc_context_t* ctx, int dpy);
void clearPipeResources(hwc_context_t* ctx, int dpy);
//Helper function to dump logs
void dumpsys_log(android::String8& buf, const char* fmt, ...);
int getExtOrientation(hwc_context_t* ctx);
bool isValidRect(const hwc_rect_t& rect);
hwc_rect_t deductRect(const hwc_rect_t& rect1, const hwc_rect_t& rect2);
bool isSameRect(const hwc_rect& rect1, const hwc_rect& rect2);
hwc_rect_t moveRect(const hwc_rect_t& rect, const int& x_off, const int& y_off);
hwc_rect_t getIntersection(const hwc_rect_t& rect1, const hwc_rect_t& rect2);
hwc_rect_t getUnion(const hwc_rect_t& rect1, const hwc_rect_t& rect2);
void optimizeLayerRects(const hwc_display_contents_1_t *list);
bool areLayersIntersecting(const hwc_layer_1_t* layer1,
const hwc_layer_1_t* layer2);
bool operator ==(const hwc_rect_t& lhs, const hwc_rect_t& rhs);
// returns true if Action safe dimensions are set and target supports Actionsafe
bool isActionSafePresent(hwc_context_t *ctx, int dpy);
/* Calculates the destination position based on the action safe rectangle */
void getActionSafePosition(hwc_context_t *ctx, int dpy, hwc_rect_t& dst);
void getAspectRatioPosition(hwc_context_t* ctx, int dpy, int extOrientation,
hwc_rect_t& inRect, hwc_rect_t& outRect);
uint32_t getRefreshRate(hwc_context_t* ctx, uint32_t requestedRefreshRate);
uint32_t roundOff(uint32_t refreshRate);
void setRefreshRate(hwc_context_t *ctx, int dpy, uint32_t refreshRate);
bool isPrimaryPortrait(hwc_context_t *ctx);
bool isOrientationPortrait(hwc_context_t *ctx);
void calcExtDisplayPosition(hwc_context_t *ctx,
private_handle_t *hnd,
int dpy,
hwc_rect_t& sourceCrop,
hwc_rect_t& displayFrame,
int& transform,
ovutils::eTransform& orient);
// Returns the orientation that needs to be set on external for
// BufferMirrirMode(Sidesync)
int getMirrorModeOrientation(hwc_context_t *ctx);
/* Get External State names */
const char* getExternalDisplayState(uint32_t external_state);
// Resets display ROI to full panel resoluion
void resetROI(hwc_context_t *ctx, const int dpy);
// Modifies ROI even from middle of the screen
hwc_rect expandROIFromMidPoint(hwc_rect roi, hwc_rect fullFrame);
// Aligns updating ROI to panel restrictions
hwc_rect_t getSanitizeROI(struct hwc_rect roi, hwc_rect boundary);
// Handles wfd Pause and resume events
void handle_pause(hwc_context_t *ctx, int dpy);
void handle_resume(hwc_context_t *ctx, int dpy);
// Handle ONLINE/OFFLINE for HDMI display
void handle_online(hwc_context_t* ctx, int dpy);
void handle_offline(hwc_context_t* ctx, int dpy);
//Close acquireFenceFds of all layers of incoming list
void closeAcquireFds(hwc_display_contents_1_t* list);
//Sync point impl if swapinterval is set to 0
void hwc_sync_sz(hwc_context_t* ctx, hwc_display_contents_1_t* list, int dpy);
//Sync point impl for rotator
void hwc_sync_rotator(hwc_context_t *ctx, hwc_display_contents_1_t* list,
int dpy);
//Sync point impl for mdss
int hwc_sync_mdss(hwc_context_t *ctx, hwc_display_contents_1_t *list, int dpy,
bool isExtAnimating, int fd);
//Sync point impl.
int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy,
int fd);
//Sets appropriate mdp flags for a layer.
void setMdpFlags(hwc_context_t *ctx, hwc_layer_1_t *layer,
ovutils::eMdpFlags &mdpFlags,
int rotDownscale, int transform);
int configRotator(overlay::Rotator *rot, ovutils::Whf& whf,
hwc_rect_t& crop, const ovutils::eMdpFlags& mdpFlags,
const ovutils::eTransform& orient, const int& downscale,
const uint32_t& frame_rate);
int configMdp(overlay::Overlay *ov, const ovutils::PipeArgs& parg,
const ovutils::eTransform& orient, const hwc_rect_t& crop,
const hwc_rect_t& pos, const MetaData_t *metadata,
const ovutils::eDest& dest);
int configColorLayer(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
const ovutils::eDest& dest);
void updateSource(ovutils::eTransform& orient, ovutils::Whf& whf,
hwc_rect_t& crop, overlay::Rotator *rot);
bool configHwCursor(const int fd, int dpy, hwc_layer_1_t* layer);
void freeHwCursor(const int fd, int dpy);
bool isZoomModeEnabled(hwc_rect_t crop);
void updateCropAIVVideoMode(hwc_context_t *ctx, hwc_rect_t& crop, int dpy);
void updateDestAIVVideoMode(hwc_context_t *ctx, hwc_rect_t& dst, int dpy);
void updateCoordinates(hwc_context_t *ctx, hwc_rect_t& crop,
hwc_rect_t& dst, int dpy);
//Routine to configure low resolution panels (<= 2048 width)
int configureNonSplit(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
const ovutils::eDest& dest,
overlay::Rotator **rot);
//Routine to configure high resolution panels (> 2048 width)
int configureSplit(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
const ovutils::eDest& lDest,
const ovutils::eDest& rDest, overlay::Rotator **rot);
//Check if the current round needs 3D composition
bool needs3DComposition(hwc_context_t* ctx, int dpy);
//Routine to configure 3D video
int configure3DVideo(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
const ovutils::eDest& lDest,
const ovutils::eDest& rDest, overlay::Rotator **rot);
//Routine to split and configure high resolution YUV layer (> 2048 width)
int configureSourceSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
const int& dpy,
ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
const ovutils::eDest& lDest,
const ovutils::eDest& rDest, overlay::Rotator **rot);
//On certain targets DMA pipes are used for rotation and they won't be available
//for line operations. On a per-target basis we can restrict certain use cases
//from using rotator, since we know before-hand that such scenarios can lead to
//extreme unavailability of pipes. This can also be done via hybrid calculations
//also involving many more variables like number of write-back interfaces etc,
//but the variety of scenarios is too high to warrant that.
bool canUseRotator(hwc_context_t *ctx, int dpy);
int getLeftSplit(hwc_context_t *ctx, const int& dpy);
bool isDisplaySplit(hwc_context_t* ctx, int dpy);
int getRotDownscale(hwc_context_t *ctx, const hwc_layer_1_t *layer);
// Set the GPU hint flag to high for MIXED/GPU composition only for
// first frame after MDP to GPU/MIXED mode transition.
// Set the GPU hint to default if the current composition type is GPU
// due to idle fallback or MDP composition.
void setGPUHint(hwc_context_t* ctx, hwc_display_contents_1_t* list);
// Returns true if rect1 is peripheral to rect2, false otherwise.
bool isPeripheral(const hwc_rect_t& rect1, const hwc_rect_t& rect2);
// Checks if boot animation has completed and applies default mode
void processBootAnimCompleted(hwc_context_t *ctx);
//The gralloc API and driver have different formats
//The format needs to be converted before passing to libhdmi
int convertS3DFormatToMode(int s3DFormat);
//Configure resources for 3D mode
void setup3DMode(hwc_context_t* ctx, int dpy, int s3dMode);
//Checks if this display supports 3D
bool displaySupports3D(hwc_context_t* ctx, int dpy);
// Inline utility functions
static inline bool isSkipLayer(const hwc_layer_1_t* l) {
return (UNLIKELY(l && (l->flags & HWC_SKIP_LAYER)));
}
static inline bool isAIVVideoLayer(const hwc_layer_1_t* l) {
return (UNLIKELY(l && (l->flags & HWC_AIV_VIDEO)));
}
static inline bool isAIVCCLayer(const hwc_layer_1_t* l) {
return (UNLIKELY(l && (l->flags & HWC_AIV_CC)));
}
static inline bool isCursorLayer(const hwc_layer_1_t* l) {
return (UNLIKELY(l && (l->flags & HWC_IS_CURSOR_LAYER)));
}
// Returns true if the buffer is yuv
static inline bool isYuvBuffer(const private_handle_t* hnd) {
return (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO));
}
// Returns true if the buffer is yuv and exceeds the mixer width
static inline bool isYUVSplitNeeded(const private_handle_t* hnd) {
int maxPipeWidth = qdutils::MDPVersion::getInstance().getMaxPipeWidth();
return (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO) &&
(hnd->width > maxPipeWidth));
}
// Returns true if the buffer is secure(using secure heap)
static inline bool isSecureBuffer(const private_handle_t* hnd) {
return (hnd && (private_handle_t::PRIV_FLAGS_SECURE_BUFFER & hnd->flags));
}
// Returns true if the buffer is protected(L3 using IOMMU heap)
static inline bool isProtectedBuffer(const private_handle_t* hnd) {
return (hnd && (private_handle_t::PRIV_FLAGS_PROTECTED_BUFFER & hnd->flags));
}
static inline bool isTileRendered(const private_handle_t* hnd) {
return (hnd && (private_handle_t::PRIV_FLAGS_TILE_RENDERED & hnd->flags));
}
//Return true if the buffer is intended for Secure Display
static inline bool isSecureDisplayBuffer(const private_handle_t* hnd) {
return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY));
}
static inline uint32_t get3DFormat(const private_handle_t* hnd) {
MetaData_t *metadata = reinterpret_cast<MetaData_t*>(hnd->base_metadata);
if(isYuvBuffer(hnd) && metadata && metadata->operation & S3D_FORMAT) {
return metadata->s3dFormat;
}
return HAL_NO_3D;
}
static inline int getWidth(const private_handle_t* hnd) {
MetaData_t *metadata = reinterpret_cast<MetaData_t*>(hnd->base_metadata);
if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) {
return metadata->bufferDim.sliceWidth;
}
return hnd->width;
}
static inline int getHeight(const private_handle_t* hnd) {
MetaData_t *metadata = reinterpret_cast<MetaData_t*>(hnd->base_metadata);
if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) {
return metadata->bufferDim.sliceHeight;
}
return hnd->height;
}
template<typename T> inline T max(T a, T b) { return (a > b) ? a : b; }
template<typename T> inline T min(T a, T b) { return (a < b) ? a : b; }
// Initialize uevent thread
void init_uevent_thread(hwc_context_t* ctx);
// Initialize vsync thread
void init_vsync_thread(hwc_context_t* ctx);
inline void getLayerResolution(const hwc_layer_1_t* layer,
int& width, int& height) {
hwc_rect_t displayFrame = layer->displayFrame;
width = displayFrame.right - displayFrame.left;
height = displayFrame.bottom - displayFrame.top;
}
static inline int openFb(int dpy) {
int fd = -1;
const char *devtmpl = "/dev/graphics/fb%u";
char name[64] = {0};
snprintf(name, 64, devtmpl, dpy);
fd = open(name, O_RDWR);
return fd;
}
template <class T>
inline void swap(T& a, T& b) {
T tmp = a;
a = b;
b = tmp;
}
}; //qhwc namespace
enum eAnimationState{
ANIMATION_STOPPED,
ANIMATION_STARTED,
};
enum eCompositionState {
COMPOSITION_STATE_MDP = 0, // Set if composition type is MDP
COMPOSITION_STATE_GPU, // Set if composition type is GPU or MIXED
COMPOSITION_STATE_IDLE_FALLBACK, // Set if it is idlefallback
};
// Structure holds the information about the GPU hint.
struct gpu_hint_info {
// system level flag to enable gpu_perf_mode
bool mGpuPerfModeEnable;
// Stores the current GPU performance mode DEFAULT/HIGH
bool mCurrGPUPerfMode;
// Stores the compositon state GPU, MDP or IDLE_FALLBACK
bool mCompositionState;
// Stores the EGLContext of current process
EGLContext mEGLContext;
// Stores the EGLDisplay of current process
EGLDisplay mEGLDisplay;
};
//struct holds the information about libmm-qdcm.so
struct qdcm_info {
qmode::ModeManager *mQdcmMode;
void *mQdcmLib;
bool mBootAnimCompleted;
};
// -----------------------------------------------------------------------------
// HWC context
// This structure contains overall state
struct hwc_context_t {
hwc_composer_device_1_t device;
const hwc_procs_t* proc;
//CopyBit objects
qhwc::CopyBit *mCopyBit[HWC_NUM_DISPLAY_TYPES];
//Overlay object - NULL for non overlay devices
overlay::Overlay *mOverlay;
//Holds a few rot objects
overlay::RotMgr *mRotMgr;
//Primary and external FB updater
qhwc::IFBUpdate *mFBUpdate[HWC_NUM_DISPLAY_TYPES];
// HDMI display related object. Used to configure/teardown
// HDMI when it is connected as primary or external.
qhwc::HDMIDisplay *mHDMIDisplay;
qhwc::MDPInfo mMDP;
qhwc::VsyncState vstate;
qhwc::DisplayAttributes dpyAttr[HWC_NUM_DISPLAY_TYPES];
qhwc::ListStats listStats[HWC_NUM_DISPLAY_TYPES];
qhwc::LayerProp *layerProp[HWC_NUM_DISPLAY_TYPES];
qhwc::MDPComp *mMDPComp[HWC_NUM_DISPLAY_TYPES];
qhwc::HwcDebug *mHwcDebug[HWC_NUM_DISPLAY_TYPES];
hwc_rect_t mViewFrame[HWC_NUM_DISPLAY_TYPES];
qhwc::AssertiveDisplay *mAD;
eAnimationState mAnimationState[HWC_NUM_DISPLAY_TYPES];
qhwc::HWCVirtualVDS *mHWCVirtual;
// stores the #numHwLayers of the previous frame
// for each display device
int mPrevHwLayerCount[HWC_NUM_DISPLAY_TYPES];
// stores the primary device orientation
int deviceOrientation;
//Securing in progress indicator
bool mSecuring;
//Display in secure mode indicator
bool mSecureMode;
//Lock to protect drawing data structures
mutable Locker mDrawLock;
//Drawing round when we use GPU
bool isPaddingRound;
// Used to mark composition cycle when DMA state change is required
bool isDMAStateChanging;
// External Orientation
int mExtOrientation;
//Flags the transition of a video session
bool mVideoTransFlag;
//Used for SideSync feature
//which overrides the mExtOrientation
bool mBufferMirrorMode;
// Used to synchronize between WFD and Display modules
mutable Locker mWfdSyncLock;
qhwc::LayerRotMap *mLayerRotMap[HWC_NUM_DISPLAY_TYPES];
// Panel reset flag will be set if BTA check fails
bool mPanelResetStatus;
// number of active Displays
int numActiveDisplays;
struct gpu_hint_info mGPUHintInfo;
//App Buffer Composition
bool enableABC;
// PTOR Info
qhwc::PtorInfo mPtorInfo;
//Running in Thermal burst mode
bool mThermalBurstMode;
//Layers out of ROI
bool copybitDrop[MAX_NUM_APP_LAYERS];
// Flag related to windowboxing feature
bool mWindowboxFeature;
// This denotes the tolerance between video layer and external display
// aspect ratio
float mAspectRatioToleranceLevel;
// Runtime switch for BWC for targets that support it
bool mBWCEnabled;
// Provides a way for OEM's to disable setting dynfps via metadata.
bool mUseMetaDataRefreshRate;
// Stores the hpd enabled status- avoids re-enabling HDP on suspend resume.
bool mHPDEnabled;
//Used to notify that boot has completed
bool mBootAnimCompleted;
// Display binder service
qService::QService* mQService;
//struct holds the information about display tuning service library.
struct qdcm_info mQdcmInfo;
};
namespace qhwc {
static inline bool isSkipPresent (hwc_context_t *ctx, int dpy) {
return ctx->listStats[dpy].skipCount;
}
static inline bool isYuvPresent (hwc_context_t *ctx, int dpy) {
return ctx->listStats[dpy].yuvCount;
}
static inline bool has90Transform(hwc_layer_1_t const* layer) {
return ((layer->transform & HWC_TRANSFORM_ROT_90) &&
!(layer->flags & HWC_COLOR_FILL));
}
inline bool isSecurePresent(hwc_context_t *ctx, int dpy) {
return ctx->listStats[dpy].isSecurePresent;
}
static inline bool isCursorPresent (hwc_context_t *ctx, int dpy) {
return ctx->listStats[dpy].cursorLayerPresent;
}
static inline bool isSecondaryConfiguring(hwc_context_t* ctx) {
return (ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isConfiguring ||
ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isConfiguring);
}
static inline bool isSecondaryConnected(hwc_context_t* ctx) {
return (ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected ||
ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected);
}
static inline bool isSecondaryAnimating(hwc_context_t* ctx) {
return (ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected &&
(!ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isPause) &&
ctx->listStats[HWC_DISPLAY_EXTERNAL].isDisplayAnimating)
||
(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected &&
(!ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isPause) &&
ctx->listStats[HWC_DISPLAY_VIRTUAL].isDisplayAnimating);
}
/* Return Virtual Display connection status */
static inline bool isVDConnected(hwc_context_t* ctx) {
return ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected;
}
inline uint32_t getLayerClock(const uint32_t& dstW, const uint32_t& dstH,
const uint32_t& srcH) {
return max(dstW, (srcH * dstW) / dstH);
}
};
#endif //HWC_UTILS_H

View File

@@ -1,238 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
*
* Not a Contribution, Apache license notifications and license are retained
* for attribution purposes only.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <overlayWriteback.h>
#include "hwc_utils.h"
#include "hwc_fbupdate.h"
#include "hwc_mdpcomp.h"
#include "hwc_dump_layers.h"
#include "hwc_copybit.h"
#include "hwc_virtual.h"
#include "sync/sync.h"
#include <utils/Trace.h>
#define HWCVIRTUAL_LOG 0
using namespace qhwc;
using namespace overlay;
bool HWCVirtualVDS::sVDDumpEnabled = false;
void HWCVirtualVDS::init(hwc_context_t *ctx) {
const int dpy = HWC_DISPLAY_VIRTUAL;
mScalingWidth = 0, mScalingHeight = 0;
initCompositionResources(ctx, dpy);
if(ctx->mFBUpdate[dpy])
ctx->mFBUpdate[dpy]->reset();
if(ctx->mMDPComp[dpy])
ctx->mMDPComp[dpy]->reset();
}
void HWCVirtualVDS::destroy(hwc_context_t *ctx, size_t /*numDisplays*/,
hwc_display_contents_1_t** displays) {
int dpy = HWC_DISPLAY_VIRTUAL;
//Cleanup virtual display objs, since there is no explicit disconnect
if(ctx->dpyAttr[dpy].connected && (displays[dpy] == NULL)) {
ctx->dpyAttr[dpy].connected = false;
ctx->dpyAttr[dpy].isPause = false;
destroyCompositionResources(ctx, dpy);
// signal synclock to indicate successful wfd teardown
ctx->mWfdSyncLock.lock();
ctx->mWfdSyncLock.signal();
ctx->mWfdSyncLock.unlock();
}
}
int HWCVirtualVDS::prepare(hwc_composer_device_1 *dev,
hwc_display_contents_1_t *list) {
ATRACE_CALL();
//XXX: Fix when framework support is added
hwc_context_t* ctx = (hwc_context_t*)(dev);
const int dpy = HWC_DISPLAY_VIRTUAL;
if (list && list->outbuf && list->numHwLayers > 0) {
reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1);
uint32_t last = (uint32_t)list->numHwLayers - 1;
hwc_layer_1_t *fbLayer = &list->hwLayers[last];
int fbWidth = 0, fbHeight = 0;
getLayerResolution(fbLayer, fbWidth, fbHeight);
ctx->dpyAttr[dpy].xres = fbWidth;
ctx->dpyAttr[dpy].yres = fbHeight;
if(ctx->dpyAttr[dpy].connected == false) {
ctx->dpyAttr[dpy].connected = true;
ctx->dpyAttr[dpy].isPause = false;
// We set the vsync period to the primary refresh rate, leaving
// it up to the consumer to decide how fast to consume frames.
ctx->dpyAttr[dpy].vsync_period
= ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period;
ctx->dpyAttr[dpy].fbformat = HAL_PIXEL_FORMAT_RGBA_8888;
init(ctx);
// Do one padding round for cases where primary has all pipes
// The virtual composition falls back to GPU in such cases.
ctx->isPaddingRound = true;
}
if(!ctx->dpyAttr[dpy].isPause) {
ctx->dpyAttr[dpy].isConfiguring = false;
ctx->dpyAttr[dpy].fd = Writeback::getInstance()->getFbFd();
private_handle_t *ohnd = (private_handle_t *)list->outbuf;
setMDPScalingMode(ctx, ohnd, dpy);
mScalingWidth = getWidth(ohnd);
mScalingHeight = getHeight(ohnd);
Writeback::getInstance()->configureDpyInfo(mScalingWidth,
mScalingHeight);
setListStats(ctx, list, dpy);
if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
const int fbZ = 0;
if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ))
{
ctx->mOverlay->clear(dpy);
ctx->mLayerRotMap[dpy]->clear();
}
}
} else {
/* Virtual Display is in Pause state.
* Mark all application layers as OVERLAY so that
* GPU will not compose.
*/
Writeback::getInstance(); //Ensure that WB is active during pause
for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
hwc_layer_1_t *layer = &list->hwLayers[i];
layer->compositionType = HWC_OVERLAY;
}
}
}
return 0;
}
int HWCVirtualVDS::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
ATRACE_CALL();
int ret = 0;
const int dpy = HWC_DISPLAY_VIRTUAL;
if (list && list->outbuf && list->numHwLayers > 0) {
uint32_t last = (uint32_t)list->numHwLayers - 1;
hwc_layer_1_t *fbLayer = &list->hwLayers[last];
if(ctx->dpyAttr[dpy].connected
&& (!ctx->dpyAttr[dpy].isPause))
{
private_handle_t *ohnd = (private_handle_t *)list->outbuf;
int format = ohnd->format;
if (format == HAL_PIXEL_FORMAT_RGBA_8888)
format = HAL_PIXEL_FORMAT_RGBX_8888;
Writeback::getInstance()->setOutputFormat(
utils::getMdpFormat(format));
// Configure WB secure mode based on output buffer handle
if(! Writeback::getInstance()->setSecure(isSecureBuffer(ohnd)))
{
ALOGE("Failed to set WB secure mode: %d for virtual display",
isSecureBuffer(ohnd));
return false;
}
int fd = -1; //FenceFD from the Copybit
hwc_sync(ctx, list, dpy, fd);
// Dump the layers for virtual
if(ctx->mHwcDebug[dpy])
ctx->mHwcDebug[dpy]->dumpLayers(list);
if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
ALOGE("%s: MDPComp draw failed", __FUNCTION__);
ret = -1;
}
// We need an FB layer handle check to cater for this usecase:
// Video is playing in landscape on primary, then launch
// ScreenRecord app.
// In this scenario, the first VDS draw call will have HWC
// composition and VDS does nit involve GPU to get eglSwapBuffer
// to get valid fb handle.
if (fbLayer->handle && !ctx->mFBUpdate[dpy]->draw(ctx,
(private_handle_t *)fbLayer->handle)) {
ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
ret = -1;
}
Writeback::getInstance()->queueBuffer(ohnd->fd,
(uint32_t)ohnd->offset);
if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
ALOGE("%s: display commit fail!", __FUNCTION__);
ret = -1;
}
if(sVDDumpEnabled) {
char bufferName[128];
// Dumping frame buffer
sync_wait(fbLayer->acquireFenceFd, 1000);
snprintf(bufferName, sizeof(bufferName), "vds.fb");
dumpBuffer((private_handle_t *)fbLayer->handle, bufferName);
// Dumping WB output for non-secure session
if(!isSecureBuffer(ohnd)) {
sync_wait(list->retireFenceFd, 1000);
snprintf(bufferName, sizeof(bufferName), "vds.wb");
dumpBuffer(ohnd, bufferName);
}
}
} else if(list->outbufAcquireFenceFd >= 0) {
//If we dont handle the frame, set retireFenceFd to outbufFenceFd,
//which will make sure, the framework waits on it and closes it.
//The other way is to wait on outbufFenceFd ourselves, close it and
//set retireFenceFd to -1. Since we want hwc to be async, choosing
//the former.
//Also dup because, the closeAcquireFds() will close the outbufFence
list->retireFenceFd = dup(list->outbufAcquireFenceFd);
}
}
closeAcquireFds(list);
return ret;
}
/* We set scaling mode on the VD if the output handle width and height
differs from the virtual frame buffer width and height. */
void HWCVirtualVDS::setMDPScalingMode(hwc_context_t* ctx,
private_handle_t* ohnd, int dpy) {
bool scalingMode = false;
int fbWidth = ctx->dpyAttr[dpy].xres;
int fbHeight = ctx->dpyAttr[dpy].yres;
int alW = 0, alH = 0;
getBufferSizeAndDimensions(fbWidth, fbHeight, ohnd->format, alW, alH);
if((getWidth(ohnd) != alW) || (getHeight(ohnd) != alH)) {
scalingMode = true;
}
ctx->dpyAttr[dpy].mMDPScalingMode = scalingMode;
ALOGD_IF(HWCVIRTUAL_LOG, "%s fb(%dx%d) outputBuffer(%dx%d) scalingMode=%d",
__FUNCTION__, alW, alH,
getWidth(ohnd), getHeight(ohnd), scalingMode);
}

View File

@@ -1,64 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
*
* Not a Contribution, Apache license notifications and license are retained
* for attribution purposes only.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef HWC_VIRTUAL
#define HWC_VIRTUAL
#include <hwc_utils.h>
namespace qhwc {
class HWCVirtualVDS {
public:
HWCVirtualVDS(){};
~HWCVirtualVDS(){};
// Chooses composition type and configures pipe for each layer in virtual
// display list
int prepare(hwc_composer_device_1 *dev,
hwc_display_contents_1_t* list);
// Queues the buffer for each layer in virtual display list and call display
// commit.
int set(hwc_context_t *ctx, hwc_display_contents_1_t *list);
// instantiates mdpcomp, copybit and fbupdate objects and initialize those
// objects for virtual display during virtual display connect.
void init(hwc_context_t *ctx);
// Destroys mdpcomp, copybit and fbupdate objects and for virtual display
// during virtual display disconnect.
void destroy(hwc_context_t *ctx, size_t numDisplays,
hwc_display_contents_1_t** displays);
int getScalingHeight() const { return mScalingHeight; };
int getScalingWidth() const { return mScalingWidth; };
// We can dump the frame buffer and WB
// output buffer by dynamically enabling
// dumping via a binder call:
// adb shell service call display.qservice 15 i32 3 i32 1
static bool sVDDumpEnabled;
static void dynamicDebug(bool enable) {sVDDumpEnabled = enable;};
private:
// These variables store the resolution that WB is being configured to
// in the current draw cycle.
int mScalingWidth, mScalingHeight;
void setMDPScalingMode(hwc_context_t* ctx,
private_handle_t* ohnd, int dpy);
};
}; //namespace
#endif

View File

@@ -1,249 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
* Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
*
* Not a Contribution, Apache license notifications and license are
* retained for attribution purposes only.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <cutils/properties.h>
#include <utils/Log.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/msm_mdp.h>
#include <sys/resource.h>
#include <sys/prctl.h>
#include <poll.h>
#include "hwc_utils.h"
#include "hdmi.h"
#include "qd_utils.h"
#include "string.h"
#include "overlay.h"
#define __STDC_FORMAT_MACROS 1
#include <inttypes.h>
#define DEBUG 0
using namespace qdutils;
namespace qhwc {
#define HWC_VSYNC_THREAD_NAME "hwcVsyncThread"
#define PANEL_ON_STR "panel_power_on ="
#define ARRAY_LENGTH(array) (sizeof((array))/sizeof((array)[0]))
#define MAX_THERMAL_LEVEL 3
const int MAX_DATA = 64;
int hwc_vsync_control(hwc_context_t* ctx, int dpy, int enable)
{
int ret = 0;
if(!ctx->vstate.fakevsync &&
ioctl(ctx->dpyAttr[dpy].fd, MSMFB_OVERLAY_VSYNC_CTRL,
&enable) < 0) {
ALOGE("%s: vsync control failed. Dpy=%d, enable=%d : %s",
__FUNCTION__, dpy, enable, strerror(errno));
ret = -errno;
}
return ret;
}
static void handle_vsync_event(hwc_context_t* ctx, int dpy, char *data,
ssize_t len __unused)
{
// extract timestamp
uint64_t timestamp = 0;
if (!strncmp(data, "VSYNC=", strlen("VSYNC="))) {
timestamp = strtoull(data + strlen("VSYNC="), NULL, 0);
}
// send timestamp to SurfaceFlinger
ALOGD_IF (ctx->vstate.debug, "%s: timestamp %"PRIu64" sent to SF for dpy=%d",
__FUNCTION__, timestamp, dpy);
ctx->proc->vsync(ctx->proc, dpy, timestamp);
}
static void handle_blank_event(hwc_context_t* ctx, int dpy, char *data,
ssize_t len __unused)
{
if (!strncmp(data, PANEL_ON_STR, strlen(PANEL_ON_STR))) {
unsigned long int poweron = strtoul(data + strlen(PANEL_ON_STR), NULL, 0);
ALOGI("%s: dpy:%d panel power state: %ld", __FUNCTION__, dpy, poweron);
if (!ctx->mHDMIDisplay->isHDMIPrimaryDisplay()) {
ctx->dpyAttr[dpy].isActive = poweron ? true: false;
}
}
}
static void handle_thermal_event(hwc_context_t* ctx, int dpy, char *data,
ssize_t len __unused)
{
// extract thermal level
uint64_t thermalLevel = 0;
if (!strncmp(data, "thermal_level=", strlen("thermal_level="))) {
thermalLevel = strtoull(data + strlen("thermal_level="), NULL, 0);
}
if (thermalLevel >= MAX_THERMAL_LEVEL) {
ALOGD("%s: dpy:%d thermal_level=%"PRIu64"",__FUNCTION__,dpy,thermalLevel);
ctx->mThermalBurstMode = true;
} else
ctx->mThermalBurstMode = false;
}
static void handle_cec_event(hwc_context_t* ctx, int dpy, char *data,
ssize_t len)
{
ALOGD_IF(DEBUG, "%s: Got CEC event from driver dpy:%d",
__FUNCTION__, dpy);
ctx->mQService->onCECMessageReceived(data, len);
}
struct event {
const char* name;
void (*callback)(hwc_context_t* ctx, int dpy, char *data, ssize_t len);
};
struct event event_list[] = {
{ "vsync_event", handle_vsync_event },
{ "show_blank_event", handle_blank_event },
{ "msm_fb_thermal_level", handle_thermal_event },
{ "cec/rd_msg", handle_cec_event },
};
#define num_events ARRAY_LENGTH(event_list)
static void *vsync_loop(void *param)
{
hwc_context_t * ctx = reinterpret_cast<hwc_context_t *>(param);
char thread_name[64] = HWC_VSYNC_THREAD_NAME;
prctl(PR_SET_NAME, (unsigned long) &thread_name, 0, 0, 0);
setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY +
android::PRIORITY_MORE_FAVORABLE);
char vdata[MAX_DATA];
//Number of physical displays
//We poll on all the nodes.
int num_displays = HWC_NUM_DISPLAY_TYPES - 1;
struct pollfd pfd[num_displays][num_events];
char property[PROPERTY_VALUE_MAX];
if(property_get("debug.hwc.fakevsync", property, NULL) > 0) {
if(atoi(property) == 1)
ctx->vstate.fakevsync = true;
}
char node_path[MAX_SYSFS_FILE_PATH];
for (int dpy = HWC_DISPLAY_PRIMARY; dpy < num_displays; dpy++) {
for(size_t ev = 0; ev < num_events; ev++) {
snprintf(node_path, sizeof(node_path),
"/sys/class/graphics/fb%d/%s",
dpy == HWC_DISPLAY_PRIMARY ? 0 :
overlay::Overlay::getInstance()->
getFbForDpy(HWC_DISPLAY_EXTERNAL),
event_list[ev].name);
ALOGI("%s: Reading event %zu for dpy %d from %s", __FUNCTION__,
ev, dpy, node_path);
pfd[dpy][ev].fd = open(node_path, O_RDONLY);
if (dpy == HWC_DISPLAY_PRIMARY && pfd[dpy][ev].fd < 0) {
// Make sure fb device is opened before starting
// this thread so this never happens.
ALOGE ("%s:unable to open event node for dpy=%d event=%zu, %s",
__FUNCTION__, dpy, ev, strerror(errno));
if (ev == 0) {
ctx->vstate.fakevsync = true;
//XXX: Blank events don't work with fake vsync,
//but we shouldn't be running on fake vsync anyway.
break;
}
}
memset(&vdata, '\0', sizeof(vdata));
// Read once from the fds to clear the first notify
pread(pfd[dpy][ev].fd, vdata , MAX_DATA - 1, 0);
if (pfd[dpy][ev].fd >= 0)
pfd[dpy][ev].events = POLLPRI | POLLERR;
}
}
if (LIKELY(!ctx->vstate.fakevsync)) {
do {
int err = poll(*pfd, (int)(num_displays * num_events), -1);
if(err > 0) {
for (int dpy = HWC_DISPLAY_PRIMARY; dpy < num_displays; dpy++) {
for(size_t ev = 0; ev < num_events; ev++) {
if (pfd[dpy][ev].revents & POLLPRI) {
// Clear vdata before writing into it
memset(&vdata, '\0', sizeof(vdata));
ssize_t len = pread(pfd[dpy][ev].fd, vdata,
MAX_DATA - 1, 0);
if (UNLIKELY(len < 0)) {
// If the read was just interrupted - it is not
// a fatal error. Just continue in this case
ALOGE ("%s: Unable to read event:%zu for \
dpy=%d : %s",
__FUNCTION__, ev, dpy, strerror(errno));
continue;
}
vdata[len] = '\0';
event_list[ev].callback(ctx, dpy, vdata, len);
}
}
}
} else {
ALOGE("%s: poll failed errno: %s", __FUNCTION__,
strerror(errno));
continue;
}
} while (true);
} else {
//Fake vsync is used only when set explicitly through a property or when
//the vsync timestamp node cannot be opened at bootup. There is no
//fallback to fake vsync from the true vsync loop, ever, as the
//condition can easily escape detection.
//Also, fake vsync is delivered only for the primary display.
do {
usleep(16666);
uint64_t timestamp = systemTime();
ctx->proc->vsync(ctx->proc, HWC_DISPLAY_PRIMARY, timestamp);
} while (true);
}
for (int dpy = HWC_DISPLAY_PRIMARY; dpy <= HWC_DISPLAY_EXTERNAL; dpy++ ) {
for( size_t event = 0; event < num_events; event++) {
if(pfd[dpy][event].fd >= 0)
close (pfd[dpy][event].fd);
}
}
return NULL;
}
void init_vsync_thread(hwc_context_t* ctx)
{
int ret;
pthread_t vsync_thread;
ALOGI("Initializing VSYNC Thread");
ret = pthread_create(&vsync_thread, NULL, vsync_loop, (void*) ctx);
if (ret) {
ALOGE("%s: failed to create %s: %s", __FUNCTION__,
HWC_VSYNC_THREAD_NAME, strerror(ret));
}
}
}; //namespace

View File

@@ -1,23 +0,0 @@
LOCAL_PATH := $(call my-dir)
include $(LOCAL_PATH)/../common.mk
include $(CLEAR_VARS)
LOCAL_MODULE := liboverlay
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
LOCAL_SHARED_LIBRARIES := $(common_libs) libqdutils libmemalloc \
libsync libdl
LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdoverlay\"
LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
LOCAL_SRC_FILES := \
overlay.cpp \
overlayUtils.cpp \
overlayMdp.cpp \
overlayRotator.cpp \
overlayMdpRot.cpp \
overlayMdssRot.cpp \
overlayWriteback.cpp \
overlayCursor.cpp \
pipes/overlayGenPipe.cpp
include $(BUILD_SHARED_LIBRARY)

View File

@@ -1,388 +0,0 @@
/*
* Copyright (c) 2011, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MDP_WRAPPER_H
#define MDP_WRAPPER_H
#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
/*
* In order to make overlay::mdp_wrapper shorter, please do something like:
* namespace mdpwrap = overlay::mdp_wrapper;
* */
#include <linux/msm_mdp.h>
#include <linux/msm_rotator.h>
#include <sys/ioctl.h>
#include <utils/Log.h>
#include <utils/Trace.h>
#include <errno.h>
#include "overlayUtils.h"
#include "overlay.h"
#define IOCTL_DEBUG 0
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
namespace overlay{
namespace mdp_wrapper{
/* FBIOGET_FSCREENINFO */
bool getFScreenInfo(int fd, fb_fix_screeninfo& finfo);
/* FBIOGET_VSCREENINFO */
bool getVScreenInfo(int fd, fb_var_screeninfo& vinfo);
/* FBIOPUT_VSCREENINFO */
bool setVScreenInfo(int fd, fb_var_screeninfo& vinfo);
/* MSM_ROTATOR_IOCTL_START */
bool startRotator(int fd, msm_rotator_img_info& rot);
/* MSM_ROTATOR_IOCTL_ROTATE */
bool rotate(int fd, msm_rotator_data_info& rot);
/* MSMFB_OVERLAY_SET */
bool setOverlay(int fd, mdp_overlay& ov);
/* MSMFB_OVERLAY_PREPARE */
int validateAndSet(const int& fd, mdp_overlay_list& list);
/* MSM_ROTATOR_IOCTL_FINISH */
bool endRotator(int fd, int sessionId);
/* MSMFB_OVERLAY_UNSET */
bool unsetOverlay(int fd, int ovId);
/* MSMFB_OVERLAY_GET */
bool getOverlay(int fd, mdp_overlay& ov);
/* MSMFB_OVERLAY_PLAY */
bool play(int fd, msmfb_overlay_data& od);
/* MSMFB_DISPLAY_COMMIT */
bool displayCommit(int fd);
/* MSMFB_WRITEBACK_INIT, MSMFB_WRITEBACK_START */
bool wbInitStart(int fbfd);
/* MSMFB_WRITEBACK_STOP, MSMFB_WRITEBACK_TERMINATE */
bool wbStopTerminate(int fbfd);
/* MSMFB_WRITEBACK_QUEUE_BUFFER */
bool wbQueueBuffer(int fbfd, struct msmfb_data& fbData);
/* MSMFB_WRITEBACK_DEQUEUE_BUFFER */
bool wbDequeueBuffer(int fbfd, struct msmfb_data& fbData);
/* the following are helper functions for dumping
* msm_mdp and friends*/
void dump(const char* const s, const msmfb_overlay_data& ov);
void dump(const char* const s, const msmfb_data& ov);
void dump(const char* const s, const mdp_overlay& ov);
void dump(const char* const s, const uint32_t u[], uint32_t cnt);
void dump(const char* const s, const msmfb_img& ov);
void dump(const char* const s, const mdp_rect& ov);
/* and rotator */
void dump(const char* const s, const msm_rotator_img_info& rot);
void dump(const char* const s, const msm_rotator_data_info& rot);
/* info */
void dump(const char* const s, const fb_fix_screeninfo& finfo);
void dump(const char* const s, const fb_var_screeninfo& vinfo);
//---------------Inlines -------------------------------------
inline bool getFScreenInfo(int fd, fb_fix_screeninfo& finfo) {
ATRACE_CALL();
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) < 0) {
ALOGE("Failed to call ioctl FBIOGET_FSCREENINFO err=%s",
strerror(errno));
return false;
}
return true;
}
inline bool getVScreenInfo(int fd, fb_var_screeninfo& vinfo) {
ATRACE_CALL();
if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) < 0) {
ALOGE("Failed to call ioctl FBIOGET_VSCREENINFO err=%s",
strerror(errno));
return false;
}
return true;
}
inline bool setVScreenInfo(int fd, fb_var_screeninfo& vinfo) {
ATRACE_CALL();
if (ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo) < 0) {
ALOGE("Failed to call ioctl FBIOPUT_VSCREENINFO err=%s",
strerror(errno));
return false;
}
return true;
}
inline bool startRotator(int fd, msm_rotator_img_info& rot) {
ATRACE_CALL();
if (ioctl(fd, MSM_ROTATOR_IOCTL_START, &rot) < 0){
ALOGE("Failed to call ioctl MSM_ROTATOR_IOCTL_START err=%s",
strerror(errno));
return false;
}
return true;
}
inline bool rotate(int fd, msm_rotator_data_info& rot) {
ATRACE_CALL();
if (ioctl(fd, MSM_ROTATOR_IOCTL_ROTATE, &rot) < 0) {
ALOGE("Failed to call ioctl MSM_ROTATOR_IOCTL_ROTATE err=%s",
strerror(errno));
return false;
}
return true;
}
inline bool setOverlay(int fd, mdp_overlay& ov) {
ATRACE_CALL();
if (ioctl(fd, MSMFB_OVERLAY_SET, &ov) < 0) {
ALOGE("Failed to call ioctl MSMFB_OVERLAY_SET err=%s",
strerror(errno));
return false;
}
return true;
}
inline int validateAndSet(const int& fd, mdp_overlay_list& list) {
ATRACE_CALL();
uint32_t id = 0;
if(UNLIKELY(Overlay::isDebugPipeLifecycle())) {
for(uint32_t i = 0; i < list.num_overlays; i++) {
if(list.overlay_list[i]->id != (uint32_t)MSMFB_NEW_REQUEST) {
id |= list.overlay_list[i]->id;
}
}
ALOGD("%s Total pipes needed: %d, Exisiting pipe mask 0x%04x",
__FUNCTION__, list.num_overlays, id);
id = 0;
}
if (ioctl(fd, MSMFB_OVERLAY_PREPARE, &list) < 0) {
ALOGD_IF(IOCTL_DEBUG, "Failed to call ioctl MSMFB_OVERLAY_PREPARE "
"err=%s", strerror(errno));
return errno;
}
if(UNLIKELY(Overlay::isDebugPipeLifecycle())) {
for(uint32_t i = 0; i < list.num_overlays; i++) {
id |= list.overlay_list[i]->id;
}
ALOGD("%s Pipe mask after OVERLAY_PREPARE 0x%04x", __FUNCTION__, id);
}
return 0;
}
inline bool endRotator(int fd, uint32_t sessionId) {
ATRACE_CALL();
if (ioctl(fd, MSM_ROTATOR_IOCTL_FINISH, &sessionId) < 0) {
ALOGE("Failed to call ioctl MSM_ROTATOR_IOCTL_FINISH err=%s",
strerror(errno));
return false;
}
return true;
}
inline bool unsetOverlay(int fd, int ovId) {
ATRACE_CALL();
ALOGD_IF(Overlay::isDebugPipeLifecycle(), "%s Unsetting pipe 0x%04x",
__FUNCTION__, ovId);
if (ioctl(fd, MSMFB_OVERLAY_UNSET, &ovId) < 0) {
ALOGE("Failed to call ioctl MSMFB_OVERLAY_UNSET err=%s",
strerror(errno));
return false;
}
return true;
}
inline bool getOverlay(int fd, mdp_overlay& ov) {
ATRACE_CALL();
if (ioctl(fd, MSMFB_OVERLAY_GET, &ov) < 0) {
ALOGE("Failed to call ioctl MSMFB_OVERLAY_GET err=%s",
strerror(errno));
return false;
}
return true;
}
inline bool play(int fd, msmfb_overlay_data& od) {
ATRACE_CALL();
if (ioctl(fd, MSMFB_OVERLAY_PLAY, &od) < 0) {
ALOGE("Failed to call ioctl MSMFB_OVERLAY_PLAY err=%s",
strerror(errno));
return false;
}
return true;
}
inline bool displayCommit(int fd, mdp_display_commit& info) {
ATRACE_CALL();
ALOGD_IF(Overlay::isDebugPipeLifecycle(), "%s", __FUNCTION__);
if(ioctl(fd, MSMFB_DISPLAY_COMMIT, &info) == -1) {
ALOGE("Failed to call ioctl MSMFB_DISPLAY_COMMIT err=%s",
strerror(errno));
return false;
}
return true;
}
inline bool wbInitStart(int fbfd) {
ATRACE_CALL();
if(ioctl(fbfd, MSMFB_WRITEBACK_INIT, NULL) < 0) {
ALOGE("Failed to call ioctl MSMFB_WRITEBACK_INIT err=%s",
strerror(errno));
return false;
}
if(ioctl(fbfd, MSMFB_WRITEBACK_START, NULL) < 0) {
ALOGE("Failed to call ioctl MSMFB_WRITEBACK_START err=%s",
strerror(errno));
return false;
}
return true;
}
inline bool wbStopTerminate(int fbfd) {
ATRACE_CALL();
if(ioctl(fbfd, MSMFB_WRITEBACK_STOP, NULL) < 0) {
ALOGE("Failed to call ioctl MSMFB_WRITEBACK_STOP err=%s",
strerror(errno));
return false;
}
if(ioctl(fbfd, MSMFB_WRITEBACK_TERMINATE, NULL) < 0) {
ALOGE("Failed to call ioctl MSMFB_WRITEBACK_TERMINATE err=%s",
strerror(errno));
return false;
}
return true;
}
inline bool wbQueueBuffer(int fbfd, struct msmfb_data& fbData) {
ATRACE_CALL();
if(ioctl(fbfd, MSMFB_WRITEBACK_QUEUE_BUFFER, &fbData) < 0) {
ALOGE("Failed to call ioctl MSMFB_WRITEBACK_QUEUE_BUFFER err=%s",
strerror(errno));
return false;
}
return true;
}
inline bool wbDequeueBuffer(int fbfd, struct msmfb_data& fbData) {
ATRACE_CALL();
if(ioctl(fbfd, MSMFB_WRITEBACK_DEQUEUE_BUFFER, &fbData) < 0) {
ALOGE("Failed to call ioctl MSMFB_WRITEBACK_DEQUEUE_BUFFER err=%s",
strerror(errno));
return false;
}
return true;
}
/* dump funcs */
inline void dump(const char* const s, const msmfb_overlay_data& ov) {
ALOGE("%s msmfb_overlay_data id=%d",
s, ov.id);
dump("data", ov.data);
}
inline void dump(const char* const s, const msmfb_data& ov) {
ALOGE("%s msmfb_data offset=%d memid=%d id=%d flags=0x%x priv=%d",
s, ov.offset, ov.memory_id, ov.id, ov.flags, ov.priv);
}
inline void dump(const char* const s, const mdp_overlay& ov) {
ALOGE("%s mdp_overlay z=%d alpha=%d mask=%d flags=0x%x id=%d",
s, ov.z_order, ov.alpha,
ov.transp_mask, ov.flags, ov.id);
dump("src", ov.src);
dump("src_rect", ov.src_rect);
dump("dst_rect", ov.dst_rect);
/*
Commented off to prevent verbose logging, since user_data could have 8 or so
fields which are mostly 0
dump("user_data", ov.user_data,
sizeof(ov.user_data)/sizeof(ov.user_data[0]));
*/
}
inline void dump(const char* const s, const msmfb_img& ov) {
ALOGE("%s msmfb_img w=%d h=%d format=%d %s",
s, ov.width, ov.height, ov.format,
overlay::utils::getFormatString(ov.format));
}
inline void dump(const char* const s, const mdp_rect& ov) {
ALOGE("%s mdp_rect x=%d y=%d w=%d h=%d",
s, ov.x, ov.y, ov.w, ov.h);
}
inline void dump(const char* const s, const uint32_t u[], uint32_t cnt) {
ALOGE("%s user_data cnt=%d", s, cnt);
for(uint32_t i=0; i < cnt; ++i) {
ALOGE("i=%d val=%d", i, u[i]);
}
}
inline void dump(const char* const s, const msm_rotator_img_info& rot) {
ALOGE("%s msm_rotator_img_info sessid=%u dstx=%d dsty=%d rot=%d, ena=%d scale=%d",
s, rot.session_id, rot.dst_x, rot.dst_y,
rot.rotations, rot.enable, rot.downscale_ratio);
dump("src", rot.src);
dump("dst", rot.dst);
dump("src_rect", rot.src_rect);
}
inline void dump(const char* const s, const msm_rotator_data_info& rot) {
ALOGE("%s msm_rotator_data_info sessid=%u verkey=%d",
s, rot.session_id, rot.version_key);
dump("src", rot.src);
dump("dst", rot.dst);
dump("src_chroma", rot.src_chroma);
dump("dst_chroma", rot.dst_chroma);
}
inline void dump(const char* const s, const fb_fix_screeninfo& finfo) {
ALOGE("%s fb_fix_screeninfo type=%d", s, finfo.type);
}
inline void dump(const char* const s, const fb_var_screeninfo& vinfo) {
ALOGE("%s fb_var_screeninfo xres=%d yres=%d",
s, vinfo.xres, vinfo.yres);
}
} // mdp_wrapper
} // overlay
#endif // MDP_WRAPPER_H

View File

@@ -1,629 +0,0 @@
/*
* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <dlfcn.h>
#include "overlay.h"
#include "pipes/overlayGenPipe.h"
#include "mdp_version.h"
#include "qdMetaData.h"
#include "qd_utils.h"
namespace overlay {
using namespace utils;
using namespace qdutils;
Overlay::Overlay() {
int numPipes = qdutils::MDPVersion::getInstance().getTotalPipes();
PipeBook::NUM_PIPES = (numPipes <= utils::OV_MAX)? numPipes : utils::OV_MAX;
for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
mPipeBook[i].init();
}
initScalar();
setDMAMultiplexingSupported();
#ifdef USES_POST_PROCESSING
initPostProc();
#endif
}
Overlay::~Overlay() {
for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
mPipeBook[i].destroy();
}
destroyScalar();
#ifdef USES_POST_PROCESSING
destroyPostProc();
#endif
}
void Overlay::configBegin() {
for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
//Mark as available for this round.
PipeBook::resetUse(i);
PipeBook::resetAllocation(i);
}
}
void Overlay::configDone() {
for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
if((PipeBook::isNotUsed(i) && !sessionInProgress((eDest)i)) ||
isSessionEnded((eDest)i)) {
//Forces UNSET on pipes, flushes rotator memory and session, closes
//fds
mPipeBook[i].destroy();
}
}
PipeBook::save();
}
int Overlay::getPipeId(utils::eDest dest) {
return mPipeBook[(int)dest].mPipe->getPipeId();
}
eDest Overlay::getDest(int pipeid) {
eDest dest = OV_INVALID;
// finding the dest corresponding to the given pipe
for(int i=0; i < PipeBook::NUM_PIPES; ++i) {
if(mPipeBook[i].valid() && mPipeBook[i].mPipe->getPipeId() == pipeid) {
return (eDest)i;
}
}
return dest;
}
eDest Overlay::reservePipe(int pipeid) {
eDest dest = getDest(pipeid);
PipeBook::setAllocation((int)dest);
return dest;
}
eDest Overlay::nextPipe(eMdpPipeType type, const PipeSpecs& pipeSpecs) {
eDest dest = OV_INVALID;
int dpy = pipeSpecs.dpy;
int mixer = pipeSpecs.mixer;
int formatType = pipeSpecs.formatClass;
for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
if( (type == OV_MDP_PIPE_ANY || //Pipe type match
type == PipeBook::getPipeType((eDest)i)) &&
(mPipeBook[i].mDisplay == DPY_UNUSED || //Free or same display
mPipeBook[i].mDisplay == dpy) &&
(mPipeBook[i].mMixer == MIXER_UNUSED || //Free or same mixer
mPipeBook[i].mMixer == mixer) &&
(mPipeBook[i].mFormatType == FORMAT_NONE || //Free or same format
mPipeBook[i].mFormatType == formatType) &&
PipeBook::isNotAllocated(i) && //Free pipe
( (sDMAMultiplexingSupported && dpy) ||
!(sDMAMode == DMA_BLOCK_MODE && //DMA pipe in Line mode
PipeBook::getPipeType((eDest)i) == OV_MDP_PIPE_DMA)) ){
//DMA-Multiplexing is only supported for WB on 8x26
dest = (eDest)i;
PipeBook::setAllocation(i);
break;
}
}
if(dest != OV_INVALID) {
int index = (int)dest;
mPipeBook[index].mDisplay = dpy;
mPipeBook[index].mMixer = mixer;
mPipeBook[index].mFormatType = formatType;
if(not mPipeBook[index].valid()) {
mPipeBook[index].mPipe = new GenericPipe(dpy);
mPipeBook[index].mSession = PipeBook::NONE;
}
}
return dest;
}
utils::eDest Overlay::getPipe(const PipeSpecs& pipeSpecs) {
if(MDPVersion::getInstance().is8x26()) {
return getPipe_8x26(pipeSpecs);
} else if(MDPVersion::getInstance().is8x16()) {
return getPipe_8x16(pipeSpecs);
} else if(MDPVersion::getInstance().is8x39()) {
return getPipe_8x39(pipeSpecs);
} else if(MDPVersion::getInstance().is8x52()) {
return getPipe_8x52(pipeSpecs);
} else if(MDPVersion::getInstance().is8994()) {
return getPipe_8994(pipeSpecs);
}
eDest dest = OV_INVALID;
//The default behavior is to assume RGB and VG pipes have scalars
if(pipeSpecs.formatClass == FORMAT_YUV) {
return nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
} else if(pipeSpecs.fb == false) { //RGB App layers
if(not pipeSpecs.needsScaling) {
dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs);
}
if(dest == OV_INVALID) {
dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs);
}
if(dest == OV_INVALID) {
dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
}
} else { //FB layer
dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs);
if(dest == OV_INVALID) {
dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
}
//Some features can cause FB to have scaling as well.
//If we ever come to this block with FB needing scaling,
//the screen will be black for a frame, since the FB won't get a pipe
//but atleast this will prevent a hang
if(dest == OV_INVALID and (not pipeSpecs.needsScaling)) {
dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs);
}
}
return dest;
}
utils::eDest Overlay::getPipe_8x26(const PipeSpecs& pipeSpecs) {
//Use this to hide all the 8x26 requirements that cannot be humanly
//described in a generic way
eDest dest = OV_INVALID;
if(pipeSpecs.formatClass == FORMAT_YUV) { //video
return nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
} else if(pipeSpecs.fb == false) { //RGB app layers
if((not pipeSpecs.needsScaling) and
(not (pipeSpecs.numActiveDisplays > 1 &&
pipeSpecs.dpy == DPY_PRIMARY))) {
dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs);
}
if(dest == OV_INVALID) {
dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs);
}
if(dest == OV_INVALID) {
dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
}
} else { //FB layer
//For 8x26 Secondary we use DMA always for FB for inline rotation
if(pipeSpecs.dpy == DPY_PRIMARY) {
dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs);
if(dest == OV_INVALID) {
dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
}
}
if(dest == OV_INVALID and (not pipeSpecs.needsScaling) and
(not (pipeSpecs.numActiveDisplays > 1 &&
pipeSpecs.dpy == DPY_PRIMARY))) {
dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs);
}
}
return dest;
}
utils::eDest Overlay::getPipe_8x16(const PipeSpecs& pipeSpecs) {
//Having such functions help keeping the interface generic but code specific
//and rife with assumptions
eDest dest = OV_INVALID;
if(pipeSpecs.formatClass == FORMAT_YUV or pipeSpecs.needsScaling) {
return nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
} else {
//Since this is a specific func, we can assume stuff like RGB pipe not
//having scalar blocks
dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs);
if(dest == OV_INVALID) {
dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs);
}
if(dest == OV_INVALID) {
dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
}
}
return dest;
}
utils::eDest Overlay::getPipe_8x39(const PipeSpecs& pipeSpecs) {
//8x16 & 8x36 has same number of pipes, pipe-types & scaling capabilities.
//Rely on 8x16 until we see a need to change.
return getPipe_8x16(pipeSpecs);
}
utils::eDest Overlay::getPipe_8x52(const PipeSpecs& pipeSpecs) {
//8x16 & 8x52 has same number of pipes, pipe-types & scaling capabilities.
//Rely on 8x16 until we see a need to change.
return getPipe_8x16(pipeSpecs);
}
utils::eDest Overlay::getPipe_8994(const PipeSpecs& pipeSpecs) {
//If DMA pipes need to be used in block mode for downscale, there could be
//cases where consecutive rounds need separate modes, which cannot be
//supported since we at least need 1 round in between where the DMA is
//unused
eDest dest = OV_INVALID;
if(pipeSpecs.formatClass == FORMAT_YUV) {
return nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
} else {
dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs);
if(dest == OV_INVALID) {
dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs);
}
if(dest == OV_INVALID and not pipeSpecs.needsScaling) {
dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs);
}
}
return dest;
}
void Overlay::endAllSessions() {
for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
if(mPipeBook[i].valid() && mPipeBook[i].mSession==PipeBook::START)
mPipeBook[i].mSession = PipeBook::END;
}
}
bool Overlay::isPipeTypeAttached(eMdpPipeType type) {
for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
if(type == PipeBook::getPipeType((eDest)i) &&
mPipeBook[i].mDisplay != DPY_UNUSED) {
return true;
}
}
return false;
}
bool Overlay::needsPrioritySwap(utils::eDest pipe1Index,
utils::eDest pipe2Index) {
validate((int)pipe1Index);
validate((int)pipe2Index);
uint8_t pipe1Prio = mPipeBook[(int)pipe1Index].mPipe->getPriority();
uint8_t pipe2Prio = mPipeBook[(int)pipe2Index].mPipe->getPriority();
int pipe1Id = mPipeBook[(int)pipe1Index].mPipe->getPipeId();
int pipe2Id = mPipeBook[(int)pipe2Index].mPipe->getPipeId();
utils::eMdpPipeType leftType = PipeBook::getPipeType(pipe1Index);
utils::eMdpPipeType rightType = PipeBook::getPipeType(pipe2Index);
if(pipe1Id >=0 && pipe2Id >=0) {
// LEFT priority should be higher then RIGHT
return (pipe1Prio > pipe2Prio);
} else if(pipe1Id < 0 && pipe2Id < 0) {
// If we are here, Source Split is enabled and both pipes are
// new requests. In this case left type should be of higher prio
// than right type
if(leftType == rightType) {
//Safe. Onus on driver to assign correct pipes within same type
return false;
} else {
//This check takes advantage of having only 3 types and avoids 3
//different failure combination checks.
// Swap IF:
// ----------------
// | Left | Right |
// ================
// | DMA | ViG |
// ----------------
// | DMA | RGB |
// ----------------
// | RGB | ViG |
// ----------------
return (leftType == OV_MDP_PIPE_DMA or rightType == OV_MDP_PIPE_VG);
}
} else if(pipe1Id < 0) {
//LEFT needs new allocation.
if(leftType == rightType) {
// If RIGHT has highest priority(lowest id), swap it.
return (pipe2Id == PipeBook::pipeMinID[leftType]);
} else {
return (leftType == OV_MDP_PIPE_DMA or rightType == OV_MDP_PIPE_VG);
}
} else { /* if (pipe2Id < 0) */
// RIGHT needs new allocation.
if(leftType == rightType) {
// If LEFT has lowest priority(highest id), swap it.
return (pipe1Id == PipeBook::pipeMaxID[leftType]);
} else {
return (leftType == OV_MDP_PIPE_DMA or rightType == OV_MDP_PIPE_VG);
}
}
}
bool Overlay::commit(utils::eDest dest) {
bool ret = false;
validate((int)dest);
if(mPipeBook[dest].mPipe->commit()) {
ret = true;
PipeBook::setUse((int)dest);
} else {
clear(mPipeBook[dest].mDisplay);
}
return ret;
}
bool Overlay::queueBuffer(int fd, uint32_t offset,
utils::eDest dest) {
bool ret = false;
validate((int)dest);
//Queue only if commit() has succeeded (and the bit set)
if(PipeBook::isUsed((int)dest)) {
ret = mPipeBook[dest].mPipe->queueBuffer(fd, offset);
}
return ret;
}
void Overlay::setCrop(const utils::Dim& d,
utils::eDest dest) {
validate((int)dest);
mPipeBook[dest].mPipe->setCrop(d);
}
void Overlay::setColor(const uint32_t color,
utils::eDest dest) {
validate((int)dest);
mPipeBook[dest].mPipe->setColor(color);
}
void Overlay::setPosition(const utils::Dim& d,
utils::eDest dest) {
validate((int)dest);
mPipeBook[dest].mPipe->setPosition(d);
}
void Overlay::setTransform(const int orient,
utils::eDest dest) {
validate((int)dest);
utils::eTransform transform =
static_cast<utils::eTransform>(orient);
mPipeBook[dest].mPipe->setTransform(transform);
}
void Overlay::setSource(const utils::PipeArgs args,
utils::eDest dest) {
validate((int)dest);
setPipeType(dest, PipeBook::getPipeType(dest));
mPipeBook[dest].mPipe->setSource(args);
}
void Overlay::setVisualParams(const MetaData_t& metadata, utils::eDest dest) {
validate((int)dest);
mPipeBook[dest].mPipe->setVisualParams(metadata);
}
void Overlay::setPipeType(utils::eDest pipeIndex,
const utils::eMdpPipeType pType) {
mPipeBook[pipeIndex].mPipe->setPipeType(pType);
}
Overlay* Overlay::getInstance() {
if(sInstance == NULL) {
sInstance = new Overlay();
}
return sInstance;
}
// Clears any VG pipes allocated to the fb devices
// Generates a LUT for pipe types.
int Overlay::initOverlay() {
int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion();
int numPipesXType[OV_MDP_PIPE_ANY] = {0};
numPipesXType[OV_MDP_PIPE_RGB] =
qdutils::MDPVersion::getInstance().getRGBPipes();
numPipesXType[OV_MDP_PIPE_VG] =
qdutils::MDPVersion::getInstance().getVGPipes();
numPipesXType[OV_MDP_PIPE_DMA] =
qdutils::MDPVersion::getInstance().getDMAPipes();
int index = 0;
for(int X = 0; X < (int)OV_MDP_PIPE_ANY; X++) { //iterate over types
for(int j = 0; j < numPipesXType[X]; j++) { //iterate over num
PipeBook::pipeTypeLUT[index] = (utils::eMdpPipeType)X;
index++;
}
}
PipeBook::pipeMinID[OV_MDP_PIPE_RGB] = 8;
PipeBook::pipeMaxID[OV_MDP_PIPE_RGB] = (numPipesXType[OV_MDP_PIPE_RGB] == 3)? 32 : 512;
PipeBook::pipeMinID[OV_MDP_PIPE_VG] = 1;
PipeBook::pipeMaxID[OV_MDP_PIPE_VG] = (numPipesXType[OV_MDP_PIPE_VG] == 3)? 4 : 256;
PipeBook::pipeMinID[OV_MDP_PIPE_DMA] = 64;
PipeBook::pipeMaxID[OV_MDP_PIPE_DMA] = 128;
FILE *displayDeviceFP = NULL;
char fbType[MAX_FRAME_BUFFER_NAME_SIZE];
char msmFbTypePath[MAX_FRAME_BUFFER_NAME_SIZE];
const char *strDtvPanel = "dtv panel";
const char *strWbPanel = "writeback panel";
for(int num = 1; num < MAX_FB_DEVICES; num++) {
snprintf (msmFbTypePath, sizeof(msmFbTypePath),
"/sys/class/graphics/fb%d/msm_fb_type", num);
displayDeviceFP = fopen(msmFbTypePath, "r");
if(displayDeviceFP){
fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE,
displayDeviceFP);
if(strncmp(fbType, strDtvPanel, strlen(strDtvPanel)) == 0) {
sDpyFbMap[DPY_EXTERNAL] = num;
} else if(strncmp(fbType, strWbPanel, strlen(strWbPanel)) == 0) {
sDpyFbMap[DPY_WRITEBACK] = num;
}
fclose(displayDeviceFP);
}
}
return 0;
}
bool Overlay::displayCommit(const int& fd) {
utils::Dim lRoi, rRoi;
return displayCommit(fd, lRoi, rRoi);
}
bool Overlay::displayCommit(const int& fd, const utils::Dim& lRoi,
const utils::Dim& rRoi) {
//Commit
struct mdp_display_commit info;
memset(&info, 0, sizeof(struct mdp_display_commit));
info.flags = MDP_DISPLAY_COMMIT_OVERLAY;
info.l_roi.x = lRoi.x;
info.l_roi.y = lRoi.y;
info.l_roi.w = lRoi.w;
info.l_roi.h = lRoi.h;
info.r_roi.x = rRoi.x;
info.r_roi.y = rRoi.y;
info.r_roi.w = rRoi.w;
info.r_roi.h = rRoi.h;
if(!mdp_wrapper::displayCommit(fd, info)) {
ALOGE("%s: commit failed", __func__);
return false;
}
return true;
}
void Overlay::getDump(char *buf, size_t len) {
int totalPipes = 0;
const char *str = "\nOverlay State\n\n";
strlcat(buf, str, len);
for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
if(mPipeBook[i].valid()) {
mPipeBook[i].mPipe->getDump(buf, len);
char str[64] = {'\0'};
snprintf(str, 64, "Display=%d\n\n", mPipeBook[i].mDisplay);
strlcat(buf, str, len);
totalPipes++;
}
}
char str_pipes[64] = {'\0'};
snprintf(str_pipes, 64, "Pipes=%d\n\n", totalPipes);
strlcat(buf, str_pipes, len);
}
void Overlay::clear(int dpy) {
for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
if (mPipeBook[i].mDisplay == dpy) {
// Mark as available for this round
PipeBook::resetUse(i);
PipeBook::resetAllocation(i);
if(getPipeId((utils::eDest)i) == -1) {
mPipeBook[i].destroy();
}
}
}
}
bool Overlay::validateAndSet(const int& dpy, const int& fbFd) {
GenericPipe* pipeArray[PipeBook::NUM_PIPES];
memset(pipeArray, 0, sizeof(GenericPipe*)*(PipeBook::NUM_PIPES));
int num = 0;
for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
if(PipeBook::isUsed(i) && mPipeBook[i].valid() &&
mPipeBook[i].mDisplay == dpy) {
pipeArray[num++] = mPipeBook[i].mPipe;
}
}
//Protect against misbehaving clients
return num ? GenericPipe::validateAndSet(pipeArray, num, fbFd) : true;
}
void Overlay::initScalar() {
if(sLibScaleHandle == NULL) {
sLibScaleHandle = dlopen("libscale.so", RTLD_NOW);
if(sLibScaleHandle) {
*(void **) &sFnProgramScale =
dlsym(sLibScaleHandle, "programScale");
}
}
}
void Overlay::destroyScalar() {
if(sLibScaleHandle) {
dlclose(sLibScaleHandle);
sLibScaleHandle = NULL;
}
}
void Overlay::initPostProc() {
sLibAblHandle = dlopen("libmm-abl.so", RTLD_NOW);
if (sLibAblHandle) {
*(void **)&sFnppParams = dlsym(sLibAblHandle,
"display_pp_compute_params");
} else {
ALOGE("%s: Not able to load libmm-abl.so", __FUNCTION__);
}
}
void Overlay::destroyPostProc() {
if (sLibAblHandle) {
dlclose(sLibAblHandle);
sLibAblHandle = NULL;
}
}
void Overlay::PipeBook::init() {
mPipe = NULL;
mDisplay = DPY_UNUSED;
mMixer = MIXER_UNUSED;
mFormatType = FORMAT_NONE;
}
void Overlay::PipeBook::destroy() {
if(mPipe) {
delete mPipe;
mPipe = NULL;
}
mDisplay = DPY_UNUSED;
mMixer = MIXER_UNUSED;
mFormatType = FORMAT_NONE;
mSession = NONE;
}
Overlay* Overlay::sInstance = 0;
int Overlay::sDpyFbMap[DPY_MAX] = {0, -1, -1};
int Overlay::sDMAMode = DMA_LINE_MODE;
bool Overlay::sDMAMultiplexingSupported = false;
bool Overlay::sDebugPipeLifecycle = false;
int Overlay::PipeBook::NUM_PIPES = 0;
int Overlay::PipeBook::sPipeUsageBitmap = 0;
int Overlay::PipeBook::sLastUsageBitmap = 0;
int Overlay::PipeBook::sAllocatedBitmap = 0;
utils::eMdpPipeType Overlay::PipeBook::pipeTypeLUT[utils::OV_MAX] =
{utils::OV_MDP_PIPE_ANY};
int Overlay::PipeBook::pipeMinID[utils::OV_MDP_PIPE_ANY] = {0};
int Overlay::PipeBook::pipeMaxID[utils::OV_MDP_PIPE_ANY] = {0};
void *Overlay::sLibScaleHandle = NULL;
int (*Overlay::sFnProgramScale)(struct mdp_overlay_list *) = NULL;
/* Dynamically link ABL library */
void *Overlay::sLibAblHandle = NULL;
int (*Overlay::sFnppParams)(const struct compute_params *,
struct mdp_overlay_pp_params *) = NULL;
}; // namespace overlay

View File

@@ -1,450 +0,0 @@
/*
* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OVERLAY_H
#define OVERLAY_H
#include "overlayUtils.h"
#include "mdp_version.h"
#include "utils/threads.h"
#ifdef USES_POST_PROCESSING
#include "lib-postproc.h"
#endif
struct MetaData_t;
namespace overlay {
class GenericPipe;
class Overlay : utils::NoCopy {
public:
enum { DMA_BLOCK_MODE, DMA_LINE_MODE };
//Abstract Display types. Each backed by a LayerMixer,
//represented by a fb node.
//High res panels can be backed by 2 layer mixers and a single fb node.
enum { DPY_PRIMARY, DPY_EXTERNAL, DPY_WRITEBACK, DPY_UNUSED };
enum { DPY_MAX = DPY_UNUSED };
enum { MIXER_LEFT, MIXER_RIGHT, MIXER_UNUSED };
enum { MIXER_DEFAULT = MIXER_LEFT, MIXER_MAX = MIXER_UNUSED };
enum { MAX_FB_DEVICES = DPY_MAX };
enum { FORMAT_YUV, FORMAT_RGB , FORMAT_NONE };
struct PipeSpecs {
PipeSpecs() : formatClass(FORMAT_RGB), needsScaling(false), fb(false),
dpy(DPY_PRIMARY), mixer(MIXER_DEFAULT), numActiveDisplays(1) {}
int formatClass;
bool needsScaling;
bool fb;
int dpy;
int mixer;
int numActiveDisplays;
};
/* dtor close */
~Overlay();
/* Marks the beginning of a drawing round, resets usage bits on pipes
* Should be called when drawing begins before any pipe config is done.
*/
void configBegin();
/* Marks the end of config for this drawing round
* Will do garbage collection of pipe objects and thus calling UNSETs,
* closing FDs, removing rotator objects and memory, if allocated.
* Should be called after all pipe configs are done.
*/
void configDone();
/* Get a pipe that supported the specified format class (yuv, rgb) and has
* scaling capabilities.
*/
utils::eDest getPipe(const PipeSpecs& pipeSpecs);
/* Returns the eDest corresponding to an already allocated pipeid.
* Useful for the reservation case, when libvpu reserves the pipe at its
* end, and expect the overlay to allocate a given pipe for a layer.
*/
utils::eDest reservePipe(int pipeid);
/* getting dest for the given pipeid */
utils::eDest getDest(int pipeid);
/* getting overlay.pipeid for the given dest */
int getPipeId(utils::eDest dest);
void setSource(const utils::PipeArgs args, utils::eDest dest);
void setCrop(const utils::Dim& d, utils::eDest dest);
void setColor(const uint32_t color, utils::eDest dest);
void setTransform(const int orientation, utils::eDest dest);
void setPosition(const utils::Dim& dim, utils::eDest dest);
void setVisualParams(const MetaData_t& data, utils::eDest dest);
bool commit(utils::eDest dest);
bool queueBuffer(int fd, uint32_t offset, utils::eDest dest);
/* pipe reservation session is running */
bool sessionInProgress(utils::eDest dest);
/* pipe reservation session has ended*/
bool isSessionEnded(utils::eDest dest);
/* start session for the pipe reservation */
void startSession(utils::eDest dest);
/* end all started sesisons */
void endAllSessions();
/* Returns available ("unallocated") pipes for a display's mixer */
int availablePipes(int dpy, int mixer);
/* Returns available ("unallocated") pipes for a display */
int availablePipes(int dpy);
/* Returns available ("unallocated") pipe of given type for a display */
int availablePipes(int dpy, utils::eMdpPipeType type);
/* Returns if any of the requested pipe type is attached to any of the
* displays
*/
bool isPipeTypeAttached(utils::eMdpPipeType type);
/* Compare pipe priorities and return
* true - A swap is needed to fix the priority.
* false - Good, priority wise.
*/
bool needsPrioritySwap(utils::eDest pipe1Index, utils::eDest pipe2Index);
/* Returns pipe dump. Expects a NULL terminated buffer of big enough size
* to populate.
*/
/* Returns if DMA pipe multiplexing is supported by the mdss driver */
static bool isDMAMultiplexingSupported();
/* Returns if UI scaling on external is supported on the targets */
static bool isUIScalingOnExternalSupported();
void getDump(char *buf, size_t len);
/* Reset usage and allocation bits on all pipes for given display */
void clear(int dpy);
/* Validate the set of pipes for a display and set them in driver */
bool validateAndSet(const int& dpy, const int& fbFd);
/* Closes open pipes, called during startup */
static int initOverlay();
/* Returns the singleton instance of overlay */
static Overlay* getInstance();
static void setDMAMode(const int& mode);
static int getDMAMode();
/* Returns the framebuffer node backing up the display */
static int getFbForDpy(const int& dpy);
static bool displayCommit(const int& fd);
/* Overloads display commit with ROI's of each halves.
* Single interface panels will only update left ROI. */
static bool displayCommit(const int& fd, const utils::Dim& lRoi,
const utils::Dim& rRoi);
/* Logs pipe lifecycle events like set, unset, commit when enabled */
static void debugPipeLifecycle(const bool& enable);
/* Returns true if pipe life cycle logging is enabled */
static bool isDebugPipeLifecycle();
private:
/* Ctor setup */
explicit Overlay();
/*Validate index range, abort if invalid */
void validate(int index);
static void setDMAMultiplexingSupported();
/* Returns an available pipe based on the type of pipe requested. When ANY
* is requested, the first available VG or RGB is returned. If no pipe is
* available for the display "dpy" then INV is returned. Note: If a pipe is
* assigned to a certain display, then it cannot be assigned to another
* display without being garbage-collected once. To add if a pipe is
* asisgned to a mixer within a display it cannot be reused for another
* mixer without being UNSET once*/
utils::eDest nextPipe(utils::eMdpPipeType, const PipeSpecs& pipeSpecs);
/* Helpers that enfore target specific policies while returning pipes */
utils::eDest getPipe_8x26(const PipeSpecs& pipeSpecs);
utils::eDest getPipe_8x16(const PipeSpecs& pipeSpecs);
utils::eDest getPipe_8x39(const PipeSpecs& pipeSpecs);
utils::eDest getPipe_8x52(const PipeSpecs& pipeSpecs);
utils::eDest getPipe_8994(const PipeSpecs& pipeSpecs);
/* Returns the handle to libscale.so's programScale function */
static int (*getFnProgramScale())(struct mdp_overlay_list *);
/* Creates a scalar object using libscale.so */
static void initScalar();
/* Destroys the scalar object using libscale.so */
static void destroyScalar();
/* Sets the pipe type RGB/VG/DMA*/
void setPipeType(utils::eDest pipeIndex, const utils::eMdpPipeType pType);
/* Dynamically link ABL library */
static void initPostProc();
static void destroyPostProc();
static int (*getFnPpParams())(const struct compute_params *,
struct mdp_overlay_pp_params *);
/* Just like a Facebook for pipes, but much less profile info */
struct PipeBook {
void init();
void destroy();
/* Check if pipe exists and return true, false otherwise */
bool valid();
/* Hardware pipe wrapper */
GenericPipe *mPipe;
/* Display using this pipe. Refer to enums above */
int mDisplay;
/* Mixer within a split display this pipe is attached to */
int mMixer;
/* Format for which this pipe is attached to the mixer*/
int mFormatType;
/* operations on bitmap */
static bool pipeUsageUnchanged();
static void setUse(int index);
static void resetUse(int index);
static bool isUsed(int index);
static bool isNotUsed(int index);
static void save();
static void setAllocation(int index);
static void resetAllocation(int index);
static bool isAllocated(int index);
static bool isNotAllocated(int index);
static utils::eMdpPipeType getPipeType(utils::eDest dest);
static const char* getDestStr(utils::eDest dest);
static int NUM_PIPES;
static utils::eMdpPipeType pipeTypeLUT[utils::OV_MAX];
static int pipeMinID[utils::OV_MDP_PIPE_ANY];
static int pipeMaxID[utils::OV_MDP_PIPE_ANY];
/* Session for reserved pipes */
enum Session {
NONE,
START,
END
};
Session mSession;
private:
//usage tracks if a successful commit happened. So a pipe could be
//allocated to a display, but it may not end up using it for various
//reasons. If one display actually uses a pipe then it amy not be
//used by another display, without an UNSET in between.
static int sPipeUsageBitmap;
static int sLastUsageBitmap;
//Tracks which pipe objects are allocated. This does not imply that they
//will actually be used. For example, a display might choose to acquire
//3 pipe objects in one shot and proceed with config only if it gets all
//3. The bitmap helps allocate different pipe objects on each request.
static int sAllocatedBitmap;
};
PipeBook mPipeBook[utils::OV_INVALID]; //Used as max
/* Singleton Instance*/
static Overlay *sInstance;
static int sDpyFbMap[DPY_MAX];
static int sDMAMode;
static bool sDMAMultiplexingSupported;
static void *sLibScaleHandle;
static int (*sFnProgramScale)(struct mdp_overlay_list *);
/* Dynamically link ABL library */
static void *sLibAblHandle;
static int (*sFnppParams)(const struct compute_params *,
struct mdp_overlay_pp_params *);
static bool sDebugPipeLifecycle;
friend class MdpCtrl;
};
inline void Overlay::validate(int index) {
OVASSERT(index >=0 && index < PipeBook::NUM_PIPES, \
"%s, Index out of bounds: %d", __FUNCTION__, index);
OVASSERT(mPipeBook[index].valid(), "Pipe does not exist %s",
PipeBook::getDestStr((utils::eDest)index));
}
inline int Overlay::availablePipes(int dpy, int mixer) {
int avail = 0;
for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
if( (mPipeBook[i].mDisplay == DPY_UNUSED ||
mPipeBook[i].mDisplay == dpy) &&
(mPipeBook[i].mMixer == MIXER_UNUSED ||
mPipeBook[i].mMixer == mixer) &&
PipeBook::isNotAllocated(i) &&
!(Overlay::getDMAMode() == Overlay::DMA_BLOCK_MODE &&
PipeBook::getPipeType((utils::eDest)i) ==
utils::OV_MDP_PIPE_DMA)) {
avail++;
}
}
return avail;
}
inline int Overlay::availablePipes(int dpy) {
int avail = 0;
for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
if( (mPipeBook[i].mDisplay == DPY_UNUSED ||
mPipeBook[i].mDisplay == dpy) &&
PipeBook::isNotAllocated(i) &&
!(Overlay::getDMAMode() == Overlay::DMA_BLOCK_MODE &&
PipeBook::getPipeType((utils::eDest)i) ==
utils::OV_MDP_PIPE_DMA)) {
avail++;
}
}
return avail;
}
inline int Overlay::availablePipes(int dpy, utils::eMdpPipeType type) {
int avail = 0;
for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
if((mPipeBook[i].mDisplay == DPY_UNUSED ||
mPipeBook[i].mDisplay == dpy) &&
PipeBook::isNotAllocated(i) &&
type == PipeBook::getPipeType((utils::eDest)i)) {
avail++;
}
}
return avail;
}
inline void Overlay::setDMAMode(const int& mode) {
if(mode == DMA_LINE_MODE || mode == DMA_BLOCK_MODE)
sDMAMode = mode;
}
inline void Overlay::setDMAMultiplexingSupported() {
sDMAMultiplexingSupported = false;
if(qdutils::MDPVersion::getInstance().is8x26())
sDMAMultiplexingSupported = true;
}
inline bool Overlay::isDMAMultiplexingSupported() {
return sDMAMultiplexingSupported;
}
inline bool Overlay::isUIScalingOnExternalSupported() {
if(qdutils::MDPVersion::getInstance().is8x26() or
qdutils::MDPVersion::getInstance().is8x16() or
qdutils::MDPVersion::getInstance().is8x39() or
qdutils::MDPVersion::getInstance().is8x52()) {
return false;
}
return true;
}
inline int Overlay::getDMAMode() {
return sDMAMode;
}
inline int Overlay::getFbForDpy(const int& dpy) {
OVASSERT(dpy >= 0 && dpy < DPY_MAX, "Invalid dpy %d", dpy);
return sDpyFbMap[dpy];
}
inline int (*Overlay::getFnProgramScale())(struct mdp_overlay_list *) {
return sFnProgramScale;
}
inline int (*Overlay::getFnPpParams())(const struct compute_params *,
struct mdp_overlay_pp_params *) {
return sFnppParams;
}
inline void Overlay::debugPipeLifecycle(const bool& enable) {
sDebugPipeLifecycle = enable;
}
inline bool Overlay::isDebugPipeLifecycle() {
return sDebugPipeLifecycle;
}
inline bool Overlay::PipeBook::valid() {
return (mPipe != NULL);
}
inline bool Overlay::PipeBook::pipeUsageUnchanged() {
return (sPipeUsageBitmap == sLastUsageBitmap);
}
inline void Overlay::PipeBook::setUse(int index) {
sPipeUsageBitmap |= (1 << index);
}
inline void Overlay::PipeBook::resetUse(int index) {
sPipeUsageBitmap &= ~(1 << index);
}
inline bool Overlay::PipeBook::isUsed(int index) {
return sPipeUsageBitmap & (1 << index);
}
inline bool Overlay::PipeBook::isNotUsed(int index) {
return !isUsed(index);
}
inline void Overlay::PipeBook::save() {
sLastUsageBitmap = sPipeUsageBitmap;
}
inline void Overlay::PipeBook::setAllocation(int index) {
sAllocatedBitmap |= (1 << index);
}
inline void Overlay::PipeBook::resetAllocation(int index) {
sAllocatedBitmap &= ~(1 << index);
}
inline bool Overlay::PipeBook::isAllocated(int index) {
return sAllocatedBitmap & (1 << index);
}
inline bool Overlay::PipeBook::isNotAllocated(int index) {
return !isAllocated(index);
}
inline utils::eMdpPipeType Overlay::PipeBook::getPipeType(utils::eDest dest) {
return pipeTypeLUT[(int)dest];
}
inline void Overlay::startSession(utils::eDest dest) {
mPipeBook[(int)dest].mSession = PipeBook::START;
}
inline bool Overlay::sessionInProgress(utils::eDest dest) {
return (mPipeBook[(int)dest].mSession == PipeBook::START);
}
inline bool Overlay::isSessionEnded(utils::eDest dest) {
return (mPipeBook[(int)dest].mSession == PipeBook::END);
}
inline const char* Overlay::PipeBook::getDestStr(utils::eDest dest) {
switch(getPipeType(dest)) {
case utils::OV_MDP_PIPE_RGB: return "RGB";
case utils::OV_MDP_PIPE_VG: return "VG";
case utils::OV_MDP_PIPE_DMA: return "DMA";
default: return "Invalid";
}
return "Invalid";
}
}; // overlay
#endif // OVERLAY_H

View File

@@ -1,249 +0,0 @@
/*
* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OVERLAY_CTRLDATA_H
#define OVERLAY_CTRLDATA_H
#include "overlayUtils.h"
#include "overlayMdp.h"
#include "gralloc_priv.h" // INTERLACE_MASK
namespace ovutils = overlay::utils;
namespace overlay {
/*
* Sequence to use:
* init
* start
* setXXX
* close
* */
class Ctrl : utils::NoCopy {
public:
/* ctor */
explicit Ctrl(const int& dpy);
/* dtor close */
~Ctrl();
/* set source using whf, orient and wait flag */
void setSource(const utils::PipeArgs& args);
/* set crop info and pass it down to mdp */
void setCrop(const utils::Dim& d);
/* set color for mdp pipe */
void setColor(const uint32_t color);
/* set orientation */
void setTransform(const utils::eTransform& p);
/* set mdp position using dim */
void setPosition(const utils::Dim& dim);
/* set mdp visual params using metadata */
bool setVisualParams(const MetaData_t &metadata);
/* set pipe type RGB/DMA/VG */
void setPipeType(const utils::eMdpPipeType& pType);
/* mdp set overlay/commit changes */
bool commit();
/* ctrl id */
int getPipeId() const;
/* ctrl fd */
int getFd() const;
/* retrieve crop data */
utils::Dim getCrop() const;
utils::Dim getPosition() const;
/* Update the src format based on rotator's dest */
void updateSrcFormat(const uint32_t& rotDstFormat);
/* return pipe priority */
uint8_t getPriority() const;
/* dump the state of the object */
void dump() const;
/* Return the dump in the specified buffer */
void getDump(char *buf, size_t len);
static bool validateAndSet(Ctrl* ctrlArray[], const int& count,
const int& fbFd);
private:
// mdp ctrl struct(info e.g.)
MdpCtrl *mMdp;
};
class Data : utils::NoCopy {
public:
/* init, reset */
explicit Data(const int& dpy);
/* calls close */
~Data();
/* set overlay pipe id in the mdp struct */
void setPipeId(int id);
/* get overlay id in the mdp struct */
int getPipeId() const;
/* queue buffer to the overlay */
bool queueBuffer(int fd, uint32_t offset);
/* sump the state of the obj */
void dump() const;
/* Return the dump in the specified buffer */
void getDump(char *buf, size_t len);
private:
// mdp data struct
MdpData *mMdp;
};
//-------------Inlines-------------------------------
inline Ctrl::Ctrl(const int& dpy) : mMdp(new MdpCtrl(dpy)) {
}
inline Ctrl::~Ctrl() {
delete mMdp;
}
inline void Ctrl::setSource(const utils::PipeArgs& args)
{
mMdp->setSource(args);
}
inline void Ctrl::setPosition(const utils::Dim& dim)
{
mMdp->setPosition(dim);
}
inline void Ctrl::setTransform(const utils::eTransform& orient)
{
mMdp->setTransform(orient);
}
inline void Ctrl::setCrop(const utils::Dim& d)
{
mMdp->setCrop(d);
}
inline void Ctrl::setColor(const uint32_t color)
{
mMdp->setColor(color);
}
inline bool Ctrl::setVisualParams(const MetaData_t &metadata)
{
if (!mMdp->setVisualParams(metadata)) {
ALOGE("Ctrl setVisualParams failed in MDP setVisualParams");
return false;
}
return true;
}
inline void Ctrl::setPipeType(const utils::eMdpPipeType& pType)
{
mMdp->setPipeType(pType);
}
inline void Ctrl::dump() const {
ALOGE("== Dump Ctrl start ==");
mMdp->dump();
ALOGE("== Dump Ctrl end ==");
}
inline bool Ctrl::commit() {
if(!mMdp->set()) {
ALOGE("Ctrl commit failed set overlay");
return false;
}
return true;
}
inline int Ctrl::getPipeId() const {
return mMdp->getPipeId();
}
inline int Ctrl::getFd() const {
return mMdp->getFd();
}
inline void Ctrl::updateSrcFormat(const uint32_t& rotDstFmt) {
mMdp->updateSrcFormat(rotDstFmt);
}
inline bool Ctrl::validateAndSet(Ctrl* ctrlArray[], const int& count,
const int& fbFd) {
MdpCtrl* mdpCtrlArray[count];
memset(&mdpCtrlArray, 0, sizeof(mdpCtrlArray));
for(int i = 0; i < count; i++) {
mdpCtrlArray[i] = ctrlArray[i]->mMdp;
}
bool ret = MdpCtrl::validateAndSet(mdpCtrlArray, count, fbFd);
return ret;
}
inline utils::Dim Ctrl::getCrop() const {
return mMdp->getSrcRectDim();
}
inline utils::Dim Ctrl::getPosition() const {
return mMdp->getDstRectDim();
}
inline uint8_t Ctrl::getPriority() const {
return mMdp->getPriority();
}
inline void Ctrl::getDump(char *buf, size_t len) {
mMdp->getDump(buf, len);
}
inline Data::Data(const int& dpy) : mMdp(new MdpData(dpy)) {
}
inline Data::~Data() {
delete mMdp;
}
inline void Data::setPipeId(int id) { mMdp->setPipeId(id); }
inline int Data::getPipeId() const { return mMdp->getPipeId(); }
inline bool Data::queueBuffer(int fd, uint32_t offset) {
return mMdp->play(fd, offset);
}
inline void Data::dump() const {
ALOGE("== Dump Data MDP start ==");
mMdp->dump();
ALOGE("== Dump Data MDP end ==");
}
inline void Data::getDump(char *buf, size_t len) {
mMdp->getDump(buf, len);
}
} // overlay
#endif

View File

@@ -1,147 +0,0 @@
/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//#include "overlay.h"
#include "overlayCursor.h"
#include "mdpWrapper.h"
namespace overlay {
HWCursor* HWCursor::sHwCursor = 0;
//=========== class HWCursor =================================================
HWCursor* HWCursor::getInstance() {
if (sHwCursor == NULL) {
sHwCursor = new HWCursor();
}
return sHwCursor;
}
bool HWCursor::config(const int fd, void* base, PipeArgs& pargs,
Dim& crop, Dim& dest) {
bool ret = true;
fb_cursor *cursor = &mfbCursor;
fb_image cursorImage;
cursor->set = FB_CUR_SETIMAGE | FB_CUR_SETPOS;
cursor->enable = (uint16_t)1;
cursor->rop = 0,
cursor->mask = NULL;
cursor->hot.x = (uint16_t)crop.x;
cursor->hot.y = (uint16_t)crop.y;
cursorImage.dx = dest.x;
cursorImage.dy = dest.y;
cursorImage.width = pargs.whf.w;
cursorImage.height = pargs.whf.h;
cursorImage.fg_color = pargs.planeAlpha; // Hint for PMA
cursorImage.bg_color = 0xffffff00; // RGBA
cursorImage.depth = 32;
cursorImage.data = (char*)base;
cursor->image = cursorImage;
if (!setCursor(fd)) {
ALOGE("%s: Failed to setup HW cursor", __FUNCTION__);
ret = false;
memset(cursor, 0, sizeof(fb_cursor));
}
return ret;
}
bool HWCursor::setPositionAsync(const int fd, int x, int y) {
bool ret = true;
if (isCursorSet()) {
fb_cursor *cursor = &mfbCursor;
cursor->set = FB_CUR_SETPOS;
cursor->image.dx = x;
cursor->image.dy = y;
if (!setCursor(fd)) {
ALOGE("%s: Failed to set position x = %d y = %d", __FUNCTION__, x, y);
ret = false;
}
}
return ret;
}
bool HWCursor::free(const int fd) {
fb_cursor *cursor = &mfbCursor;
fb_image cursorImage;
bool ret = true;
if(!cursor->enable) {
return ret;
}
cursor->enable = (uint16_t)0;
if (!setCursor(fd)) {
ALOGE("%s: Failed to free cursor hw", __FUNCTION__);
ret = false;
}
memset(cursor, 0, sizeof(fb_cursor));
return ret;
}
bool HWCursor::setCursor(const int fd) {
bool ret = true;
ATRACE_CALL();
fb_cursor *cursor = &mfbCursor;
if(fd <= 0) {
ALOGE("%s: Invalid fd", fd);
return false;
}
if (ioctl(fd, MSMFB_CURSOR, cursor) < 0) {
ALOGE("%s: Failed to call ioctl MSMFB_CURSOR err=%s\n", __FUNCTION__,
strerror(errno));
ret = false;
}
return ret;
}
void HWCursor::getDump(char* buf, size_t len) {
char cursordump[len];
fb_cursor* cursor = &mfbCursor;
if (cursor->enable) {
snprintf(cursordump, sizeof(cursordump),
"HWCursor on Primary: src w=%d h=%d\n"
"\tsrc_rect x=%d y=%d w=%d h=%d\n"
"\tdst_rect x=%d y=%d w=%d h=%d\n\n", cursor->image.width,
cursor->image.height, cursor->hot.x, cursor->hot.y,
cursor->image.width, cursor->image.height,
cursor->image.dx, cursor->image.dy, cursor->image.width,
cursor->image.height);
strlcat(buf, cursordump, len);
}
}
} //namespace overlay

View File

@@ -1,60 +0,0 @@
/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OVERLAY_CURSOR_H
#define OVERLAY_CURSOR_H
#include "overlay.h"
#include "overlayUtils.h"
namespace overlay {
using namespace overlay;
using namespace overlay::utils;
// HW Cursor Helper
class HWCursor {
public:
static HWCursor* getInstance();
bool config(const int fd, void* base, PipeArgs& pargs, Dim& crop,
Dim& dest);
bool setPositionAsync(const int fd, int x, int y);
bool free(const int fd);
bool isCursorSet() { return mfbCursor.enable; }
void getDump(char* buf, size_t len);
private:
HWCursor() { memset(&mfbCursor, 0, sizeof(mfbCursor)); }
bool setCursor(const int fd);
fb_cursor mfbCursor;
static HWCursor* sHwCursor;
};
}
#endif // OVERLAY_CURSOR_H

View File

@@ -1,442 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <math.h>
#include <mdp_version.h>
#include "overlayUtils.h"
#include "overlayMdp.h"
#include "mdp_version.h"
#include <overlay.h>
#include <dlfcn.h>
#define HSIC_SETTINGS_DEBUG 0
using namespace qdutils;
static inline bool isEqual(float f1, float f2) {
return ((int)(f1*100) == (int)(f2*100)) ? true : false;
}
namespace ovutils = overlay::utils;
namespace overlay {
bool MdpCtrl::init(const int& dpy) {
int fbnum = Overlay::getFbForDpy(dpy);
if( fbnum < 0 ) {
ALOGE("%s: Invalid FB for the display: %d",__FUNCTION__, dpy);
return false;
}
// FD init
if(!utils::openDev(mFd, fbnum,
Res::fbPath, O_RDWR)){
ALOGE("Ctrl failed to init fbnum=%d", fbnum);
return false;
}
mDpy = dpy;
return true;
}
void MdpCtrl::reset() {
utils::memset0(mOVInfo);
mOVInfo.id = MSMFB_NEW_REQUEST;
mOrientation = utils::OVERLAY_TRANSFORM_0;
mDpy = 0;
#ifdef USES_POST_PROCESSING
memset(&mParams, 0, sizeof(struct compute_params));
mParams.params.conv_params.order = hsic_order_hsc_i;
mParams.params.conv_params.interface = interface_rec601;
mParams.params.conv_params.cc_matrix[0][0] = 1;
mParams.params.conv_params.cc_matrix[1][1] = 1;
mParams.params.conv_params.cc_matrix[2][2] = 1;
#endif
}
bool MdpCtrl::close() {
bool result = true;
if(MSMFB_NEW_REQUEST != static_cast<int>(mOVInfo.id)) {
if(!mdp_wrapper::unsetOverlay(mFd.getFD(), mOVInfo.id)) {
ALOGE("MdpCtrl close error in unset");
result = false;
}
}
#ifdef USES_POST_PROCESSING
/* free allocated memory in PP */
if (mOVInfo.overlay_pp_cfg.igc_cfg.c0_c1_data)
free(mOVInfo.overlay_pp_cfg.igc_cfg.c0_c1_data);
#endif
reset();
if(!mFd.close()) {
result = false;
}
return result;
}
void MdpCtrl::setSource(const utils::PipeArgs& args) {
setSrcWhf(args.whf);
//TODO These are hardcoded. Can be moved out of setSource.
mOVInfo.transp_mask = 0xffffffff;
//TODO These calls should ideally be a part of setPipeParams API
setFlags(args.mdpFlags);
setZ(args.zorder);
setPlaneAlpha(args.planeAlpha);
setBlending(args.blending);
}
void MdpCtrl::setCrop(const utils::Dim& d) {
setSrcRectDim(d);
}
void MdpCtrl::setColor(const uint32_t color) {
mOVInfo.bg_color = color;
}
void MdpCtrl::setPosition(const overlay::utils::Dim& d) {
setDstRectDim(d);
}
void MdpCtrl::setTransform(const utils::eTransform& orient) {
int rot = utils::getMdpOrient(orient);
setUserData(rot);
mOrientation = static_cast<utils::eTransform>(rot);
}
void MdpCtrl::setPipeType(const utils::eMdpPipeType& pType){
switch((int) pType){
case utils::OV_MDP_PIPE_RGB:
mOVInfo.pipe_type = PIPE_TYPE_RGB;
break;
case utils::OV_MDP_PIPE_VG:
mOVInfo.pipe_type = PIPE_TYPE_VIG;
break;
case utils::OV_MDP_PIPE_DMA:
mOVInfo.pipe_type = PIPE_TYPE_DMA;
break;
default:
mOVInfo.pipe_type = PIPE_TYPE_AUTO;
break;
}
}
void MdpCtrl::doTransform() {
setRotationFlags();
utils::Whf whf = getSrcWhf();
utils::Dim dim = getSrcRectDim();
utils::preRotateSource(mOrientation, whf, dim);
setSrcWhf(whf);
setSrcRectDim(dim);
}
void MdpCtrl::doDownscale() {
if(MDPVersion::getInstance().supportsDecimation()) {
utils::getDecimationFactor(mOVInfo.src_rect.w, mOVInfo.src_rect.h,
mOVInfo.dst_rect.w, mOVInfo.dst_rect.h, mOVInfo.horz_deci,
mOVInfo.vert_deci);
}
}
bool MdpCtrl::set() {
int mdpVersion = MDPVersion::getInstance().getMDPVersion();
//deferred calcs, so APIs could be called in any order.
doTransform();
utils::Whf whf = getSrcWhf();
if(utils::isYuv(whf.format)) {
utils::normalizeCrop(mOVInfo.src_rect.x, mOVInfo.src_rect.w);
utils::normalizeCrop(mOVInfo.src_rect.y, mOVInfo.src_rect.h);
if(mdpVersion < MDSS_V5) {
utils::even_floor(mOVInfo.dst_rect.w);
utils::even_floor(mOVInfo.dst_rect.h);
} else if (mOVInfo.flags & MDP_DEINTERLACE) {
// For interlaced, crop.h should be 4-aligned
if (!(mOVInfo.flags & MDP_SOURCE_ROTATED_90) &&
(mOVInfo.src_rect.h % 4))
mOVInfo.src_rect.h = utils::aligndown(mOVInfo.src_rect.h, 4);
// For interlaced, width must be multiple of 4 when rotated 90deg.
else if ((mOVInfo.flags & MDP_SOURCE_ROTATED_90) &&
(mOVInfo.src_rect.w % 4))
mOVInfo.src_rect.w = utils::aligndown(mOVInfo.src_rect.w, 4);
}
} else {
// On 8974 and 8x26, there is a limitation of 1-pixel down-scaling
if (mdpVersion >= MDSS_V5) {
if(qdutils::MDPVersion::getInstance().is8x74v2() ||
qdutils::MDPVersion::getInstance().is8x26()) {
if (mOVInfo.src_rect.w - mOVInfo.dst_rect.w == 1)
mOVInfo.src_rect.w -= 1;
if (mOVInfo.src_rect.h - mOVInfo.dst_rect.h == 1)
mOVInfo.src_rect.h -= 1;
}
}
}
doDownscale();
return true;
}
//Update src format based on rotator's destination format.
void MdpCtrl::updateSrcFormat(const uint32_t& rotDestFmt) {
utils::Whf whf = getSrcWhf();
whf.format = rotDestFmt;
setSrcWhf(whf);
}
void MdpCtrl::dump() const {
ALOGE("== Dump MdpCtrl start ==");
mFd.dump();
mdp_wrapper::dump("mOVInfo", mOVInfo);
ALOGE("== Dump MdpCtrl end ==");
}
void MdpCtrl::getDump(char *buf, size_t len) {
ovutils::getDump(buf, len, "Ctrl", mOVInfo);
}
void MdpData::dump() const {
ALOGE("== Dump MdpData start ==");
mFd.dump();
mdp_wrapper::dump("mOvData", mOvData);
ALOGE("== Dump MdpData end ==");
}
void MdpData::getDump(char *buf, size_t len) {
ovutils::getDump(buf, len, "Data", mOvData);
}
bool MdpCtrl::setVisualParams(const MetaData_t& data) {
ALOGD_IF(0, "In %s: data.operation = %d", __FUNCTION__, data.operation);
// Set Color Space for MDP to configure CSC matrix
mOVInfo.color_space = ITU_R_601;
if (data.operation & UPDATE_COLOR_SPACE) {
mOVInfo.color_space = data.colorSpace;
}
#ifdef USES_POST_PROCESSING
bool needUpdate = false;
/* calculate the data */
if (data.operation & PP_PARAM_HSIC) {
if (mParams.params.pa_params.hue != data.hsicData.hue) {
ALOGD_IF(HSIC_SETTINGS_DEBUG,
"Hue has changed from %d to %d",
mParams.params.pa_params.hue,data.hsicData.hue);
needUpdate = true;
}
if (!isEqual(mParams.params.pa_params.sat,
data.hsicData.saturation)) {
ALOGD_IF(HSIC_SETTINGS_DEBUG,
"Saturation has changed from %f to %f",
mParams.params.pa_params.sat,
data.hsicData.saturation);
needUpdate = true;
}
if (mParams.params.pa_params.intensity != data.hsicData.intensity) {
ALOGD_IF(HSIC_SETTINGS_DEBUG,
"Intensity has changed from %d to %d",
mParams.params.pa_params.intensity,
data.hsicData.intensity);
needUpdate = true;
}
if (!isEqual(mParams.params.pa_params.contrast,
data.hsicData.contrast)) {
ALOGD_IF(HSIC_SETTINGS_DEBUG,
"Contrast has changed from %f to %f",
mParams.params.pa_params.contrast,
data.hsicData.contrast);
needUpdate = true;
}
if (needUpdate) {
mParams.params.pa_params.hue = (float)data.hsicData.hue;
mParams.params.pa_params.sat = data.hsicData.saturation;
mParams.params.pa_params.intensity = data.hsicData.intensity;
mParams.params.pa_params.contrast = data.hsicData.contrast;
mParams.params.pa_params.ops = MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE;
mParams.operation |= PP_OP_PA;
}
}
if (data.operation & PP_PARAM_SHARP2) {
if (mParams.params.sharp_params.strength != data.Sharp2Data.strength) {
needUpdate = true;
}
if (mParams.params.sharp_params.edge_thr != data.Sharp2Data.edge_thr) {
needUpdate = true;
}
if (mParams.params.sharp_params.smooth_thr !=
data.Sharp2Data.smooth_thr) {
needUpdate = true;
}
if (mParams.params.sharp_params.noise_thr !=
data.Sharp2Data.noise_thr) {
needUpdate = true;
}
if (needUpdate) {
mParams.params.sharp_params.strength = data.Sharp2Data.strength;
mParams.params.sharp_params.edge_thr = data.Sharp2Data.edge_thr;
mParams.params.sharp_params.smooth_thr =
data.Sharp2Data.smooth_thr;
mParams.params.sharp_params.noise_thr = data.Sharp2Data.noise_thr;
mParams.params.sharp_params.ops =
MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE;
mParams.operation |= PP_OP_SHARP;
}
}
if (data.operation & PP_PARAM_IGC) {
if (mOVInfo.overlay_pp_cfg.igc_cfg.c0_c1_data == NULL){
uint32_t *igcData
= (uint32_t *)malloc(2 * MAX_IGC_LUT_ENTRIES * sizeof(uint32_t));
if (!igcData) {
ALOGE("IGC storage allocated failed");
return false;
}
mOVInfo.overlay_pp_cfg.igc_cfg.c0_c1_data = igcData;
mOVInfo.overlay_pp_cfg.igc_cfg.c2_data
= igcData + MAX_IGC_LUT_ENTRIES;
}
memcpy(mParams.params.igc_lut_params.c0,
data.igcData.c0, sizeof(uint16_t) * MAX_IGC_LUT_ENTRIES);
memcpy(mParams.params.igc_lut_params.c1,
data.igcData.c1, sizeof(uint16_t) * MAX_IGC_LUT_ENTRIES);
memcpy(mParams.params.igc_lut_params.c2,
data.igcData.c2, sizeof(uint16_t) * MAX_IGC_LUT_ENTRIES);
mParams.params.igc_lut_params.ops
= MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE;
mParams.operation |= PP_OP_IGC;
needUpdate = true;
}
if (data.operation & PP_PARAM_VID_INTFC) {
mParams.params.conv_params.interface =
(interface_type) data.video_interface;
needUpdate = true;
}
if (needUpdate) {
int (*sFnppParams)(const struct compute_params *,
struct mdp_overlay_pp_params *) =
Overlay::getFnPpParams();
if(sFnppParams) {
int ret = sFnppParams(&mParams, &mOVInfo.overlay_pp_cfg);
if (ret) {
ALOGE("%s: Unable to set PP params", __FUNCTION__);
}
}
}
#endif
return true;
}
bool MdpCtrl::validateAndSet(MdpCtrl* mdpCtrlArray[], const int& count,
const int& fbFd) {
mdp_overlay* ovArray[count];
memset(&ovArray, 0, sizeof(ovArray));
uint8_t max_horz_deci = 0, max_vert_deci = 0;
// Decimation factor for the left and right pipe differs, when there is a
// one pixel difference in the dst width of right pipe and the left pipe.
// libscalar returns a failure as it expects decimation on both the pipe
// to be same. So compare the decimation factor on both the pipes and assign
// the maximum of it.
for(int i = 0; i < count; i++) {
mdp_overlay *ov_current = &mdpCtrlArray[i]->mOVInfo;
for(int j = i + 1; j < count; j++) {
mdp_overlay *ov_next = &mdpCtrlArray[j]->mOVInfo;
if(ov_current->z_order == ov_next->z_order) {
max_horz_deci = utils::max(ov_current->horz_deci,
ov_next->horz_deci);
max_vert_deci = utils::max(ov_current->vert_deci,
ov_next->vert_deci);
ov_current->horz_deci = max_horz_deci;
ov_next->horz_deci = max_horz_deci;
ov_current->vert_deci = max_vert_deci;
ov_next->vert_deci = max_vert_deci;
break;
}
}
ovArray[i] = ov_current;
}
struct mdp_overlay_list list;
memset(&list, 0, sizeof(struct mdp_overlay_list));
list.num_overlays = count;
list.overlay_list = ovArray;
int (*fnProgramScale)(struct mdp_overlay_list *) =
Overlay::getFnProgramScale();
if(fnProgramScale) {
fnProgramScale(&list);
}
// Error value is based on file errno-base.h
// 0 - indicates no error.
int errVal = mdp_wrapper::validateAndSet(fbFd, list);
if(errVal) {
/* No dump for failure due to insufficient resource */
if(errVal != E2BIG && errVal != EBADSLT) {
//ENODEV is returned when the driver cannot satisfy a pipe request.
//This could happen if previous round's UNSET hasn't been commited
//yet, either because of a missed vsync or because of difference in
//vsyncs of primary and external. This is expected during
//transition scenarios, but should be considered fatal if seen
//continuously.
if(errVal == ENODEV) {
ALOGW("%s: Pipe unavailable. Likely previous UNSET pending. "
"Fatal if seen continuously.", __FUNCTION__);
} else {
ALOGE("%s failed, error %d: %s", __FUNCTION__, errVal,
strerror(errVal));
mdp_wrapper::dump("Bad ov dump: ",
*list.overlay_list[list.processed_overlays]);
}
}
return false;
}
return true;
}
//// MdpData ////////////
bool MdpData::init(const int& dpy) {
int fbnum = Overlay::getFbForDpy(dpy);
if( fbnum < 0 ) {
ALOGE("%s: Invalid FB for the display: %d",__FUNCTION__, dpy);
return false;
}
// FD init
if(!utils::openDev(mFd, fbnum, Res::fbPath, O_RDWR)){
ALOGE("Ctrl failed to init fbnum=%d", fbnum);
return false;
}
return true;
}
} // overlay

View File

@@ -1,317 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef OVERLAY_MDP_H
#define OVERLAY_MDP_H
#include <linux/msm_mdp.h>
#include "overlayUtils.h"
#include "mdpWrapper.h"
#include "qdMetaData.h"
#ifdef USES_POST_PROCESSING
#include "lib-postproc.h"
#endif
namespace overlay{
/*
* Mdp Ctrl holds corresponding fd and MDP related struct.
* It is simple wrapper to MDP services
* */
class MdpCtrl {
public:
/* ctor reset */
explicit MdpCtrl(const int& dpy);
/* dtor close */
~MdpCtrl();
/* init underlying device using fbnum for dpy */
bool init(const int& dpy);
/* unset overlay, reset and close fd */
bool close();
/* reset and set ov id to -1 / MSMFB_NEW_REQUEST */
void reset();
/* calls overlay set
* Set would always consult last good known ov instance.
* Only if it is different, set would actually exectue ioctl.
* On a sucess ioctl. last good known ov instance is updated */
bool set();
/* Sets the source total width, height, format */
void setSource(const utils::PipeArgs& pargs);
/*
* Sets ROI, the unpadded region, for source buffer.
* Dim - ROI dimensions.
*/
void setCrop(const utils::Dim& d);
/* set color for mdp pipe */
void setColor(const uint32_t color);
void setTransform(const utils::eTransform& orient);
/* given a dim and w/h, set overlay dim */
void setPosition(const utils::Dim& dim);
/* using user_data, sets/unsets roationvalue in mdp flags */
void setRotationFlags();
/* Update the src format with rotator's dest*/
void updateSrcFormat(const uint32_t& rotDstFormat);
/* dump state of the object */
void dump() const;
/* Return the dump in the specified buffer */
void getDump(char *buf, size_t len);
/* returns session id */
int getPipeId() const;
/* returns the fd associated to ctrl*/
int getFd() const;
/* returns a copy ro dst rect dim */
utils::Dim getDstRectDim() const;
/* returns a copy to src rect dim */
utils::Dim getSrcRectDim() const;
/* return pipe priority */
uint8_t getPriority() const;
/* setVisualParam */
bool setVisualParams(const MetaData_t& data);
/* sets pipe type RGB/DMA/VG */
void setPipeType(const utils::eMdpPipeType& pType);
static bool validateAndSet(MdpCtrl* mdpCtrlArray[], const int& count,
const int& fbFd);
private:
/* Perform transformation calculations */
void doTransform();
void doDownscale();
/* get orient / user_data[0] */
int getOrient() const;
/* returns flags from mdp structure */
int getFlags() const;
/* set flags to mdp structure */
void setFlags(int f);
/* set z order */
void setZ(utils::eZorder z);
/* return a copy of src whf*/
utils::Whf getSrcWhf() const;
/* set plane alpha */
void setPlaneAlpha(int planeAlpha);
/* set blending method */
void setBlending(overlay::utils::eBlending blending);
/* set src whf */
void setSrcWhf(const utils::Whf& whf);
/* set src/dst rect dim */
void setSrcRectDim(const utils::Dim d);
void setDstRectDim(const utils::Dim d);
/* returns user_data[0]*/
int getUserData() const;
/* sets user_data[0] */
void setUserData(int v);
utils::eTransform mOrientation; //Holds requested orientation
/* Actual overlay mdp structure */
mdp_overlay mOVInfo;
/* FD for the mdp fbnum */
OvFD mFd;
int mDpy;
#ifdef USES_POST_PROCESSING
/* PP Compute Params */
struct compute_params mParams;
#endif
};
/* MDP data */
class MdpData {
public:
/* ctor reset data */
explicit MdpData(const int& dpy);
/* dtor close*/
~MdpData();
/* init FD */
bool init(const int& dpy);
/* memset0 the underlying mdp object */
void reset();
/* close fd, and reset */
bool close();
/* set id of mdp data */
void setPipeId(int id);
/* return ses id of data */
int getPipeId() const;
/* get underlying fd*/
int getFd() const;
/* get memory_id */
int getSrcMemoryId() const;
/* calls wrapper play */
bool play(int fd, uint32_t offset);
/* dump state of the object */
void dump() const;
/* Return the dump in the specified buffer */
void getDump(char *buf, size_t len);
private:
/* actual overlay mdp data */
msmfb_overlay_data mOvData;
/* fd to mdp fbnum */
OvFD mFd;
};
//--------------Inlines---------------------------------
///// MdpCtrl //////
inline MdpCtrl::MdpCtrl(const int& dpy) {
reset();
init(dpy);
}
inline MdpCtrl::~MdpCtrl() {
close();
}
inline int MdpCtrl::getOrient() const {
return getUserData();
}
inline int MdpCtrl::getPipeId() const {
return mOVInfo.id;
}
inline int MdpCtrl::getFd() const {
return mFd.getFD();
}
inline int MdpCtrl::getFlags() const {
return mOVInfo.flags;
}
inline void MdpCtrl::setFlags(int f) {
mOVInfo.flags = f;
}
inline void MdpCtrl::setZ(overlay::utils::eZorder z) {
mOVInfo.z_order = z;
}
inline void MdpCtrl::setPlaneAlpha(int planeAlpha) {
mOVInfo.alpha = planeAlpha;
}
inline void MdpCtrl::setBlending(overlay::utils::eBlending blending) {
switch((int) blending) {
case utils::OVERLAY_BLENDING_OPAQUE:
mOVInfo.blend_op = BLEND_OP_OPAQUE;
break;
case utils::OVERLAY_BLENDING_PREMULT:
mOVInfo.blend_op = BLEND_OP_PREMULTIPLIED;
break;
case utils::OVERLAY_BLENDING_COVERAGE:
default:
mOVInfo.blend_op = BLEND_OP_COVERAGE;
}
}
inline overlay::utils::Whf MdpCtrl::getSrcWhf() const {
return utils::Whf( mOVInfo.src.width,
mOVInfo.src.height,
mOVInfo.src.format);
}
inline void MdpCtrl::setSrcWhf(const overlay::utils::Whf& whf) {
mOVInfo.src.width = whf.w;
mOVInfo.src.height = whf.h;
mOVInfo.src.format = whf.format;
}
inline overlay::utils::Dim MdpCtrl::getSrcRectDim() const {
return utils::Dim( mOVInfo.src_rect.x,
mOVInfo.src_rect.y,
mOVInfo.src_rect.w,
mOVInfo.src_rect.h);
}
inline void MdpCtrl::setSrcRectDim(const overlay::utils::Dim d) {
mOVInfo.src_rect.x = d.x;
mOVInfo.src_rect.y = d.y;
mOVInfo.src_rect.w = d.w;
mOVInfo.src_rect.h = d.h;
}
inline overlay::utils::Dim MdpCtrl::getDstRectDim() const {
return utils::Dim( mOVInfo.dst_rect.x,
mOVInfo.dst_rect.y,
mOVInfo.dst_rect.w,
mOVInfo.dst_rect.h);
}
inline void MdpCtrl::setDstRectDim(const overlay::utils::Dim d) {
mOVInfo.dst_rect.x = d.x;
mOVInfo.dst_rect.y = d.y;
mOVInfo.dst_rect.w = d.w;
mOVInfo.dst_rect.h = d.h;
}
inline int MdpCtrl::getUserData() const { return mOVInfo.user_data[0]; }
inline void MdpCtrl::setUserData(int v) { mOVInfo.user_data[0] = v; }
inline void MdpCtrl::setRotationFlags() {
const int u = getUserData();
if (u & MDP_ROT_90)
mOVInfo.flags |= MDP_SOURCE_ROTATED_90;
}
inline uint8_t MdpCtrl::getPriority() const {
return mOVInfo.priority;
}
/////// MdpData //////
inline MdpData::MdpData(const int& dpy) {
reset();
init(dpy);
}
inline MdpData::~MdpData() { close(); }
inline void MdpData::reset() {
overlay::utils::memset0(mOvData);
mOvData.data.memory_id = -1;
}
inline bool MdpData::close() {
reset();
return mFd.close();
}
inline int MdpData::getSrcMemoryId() const { return mOvData.data.memory_id; }
inline void MdpData::setPipeId(int id) { mOvData.id = id; }
inline int MdpData::getPipeId() const { return mOvData.id; }
inline int MdpData::getFd() const { return mFd.getFD(); }
inline bool MdpData::play(int fd, uint32_t offset) {
mOvData.data.memory_id = fd;
mOvData.data.offset = offset;
if(!mdp_wrapper::play(mFd.getFD(), mOvData)){
ALOGE("MdpData failed to play");
dump();
return false;
}
return true;
}
} // overlay
#endif // OVERLAY_MDP_H

View File

@@ -1,326 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
* Not a Contribution, Apache license notifications and license are retained
* for attribution purposes only.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <math.h>
#include "overlayUtils.h"
#include "overlayRotator.h"
#include "gr.h"
namespace ovutils = overlay::utils;
namespace overlay {
MdpRot::MdpRot() {
reset();
init();
}
MdpRot::~MdpRot() { close(); }
bool MdpRot::enabled() const { return mRotImgInfo.enable; }
void MdpRot::setRotations(uint32_t r) { mRotImgInfo.rotations = (uint8_t)r; }
int MdpRot::getSrcMemId() const {
return mRotDataInfo.src.memory_id;
}
int MdpRot::getDstMemId() const {
return mRotDataInfo.dst.memory_id;
}
uint32_t MdpRot::getSrcOffset() const {
return mRotDataInfo.src.offset;
}
uint32_t MdpRot::getDstOffset() const {
return mRotDataInfo.dst.offset;
}
uint32_t MdpRot::getDstFormat() const {
return mRotImgInfo.dst.format;
}
//Added for completeness. Not expected to be called.
utils::Whf MdpRot::getDstWhf() const {
int alW = 0, alH = 0;
int halFormat = ovutils::getHALFormat(mRotImgInfo.dst.format);
getBufferSizeAndDimensions(mRotImgInfo.dst.width, mRotImgInfo.dst.height,
halFormat, alW, alH);
return utils::Whf(alW, alH, mRotImgInfo.dst.format);
}
//Added for completeness. Not expected to be called.
utils::Dim MdpRot::getDstDimensions() const {
int alW = 0, alH = 0;
int halFormat = ovutils::getHALFormat(mRotImgInfo.dst.format);
getBufferSizeAndDimensions(mRotImgInfo.dst.width, mRotImgInfo.dst.height,
halFormat, alW, alH);
return utils::Dim(0, 0, alW, alH);
}
uint32_t MdpRot::getSessId() const { return mRotImgInfo.session_id; }
void MdpRot::setDownscale(int ds) {
if ((utils::ROT_DS_EIGHTH == ds) && (mRotImgInfo.src_rect.h & 0xF)) {
// Ensure src_rect.h is a multiple of 16 for 1/8 downscaling.
// This is an undocumented MDP Rotator constraint.
mRotImgInfo.src_rect.h = utils::aligndown(mRotImgInfo.src_rect.h, 16);
}
mRotImgInfo.downscale_ratio = ds;
}
void MdpRot::save() {
mLSRotImgInfo = mRotImgInfo;
}
bool MdpRot::rotConfChanged() const {
// 0 means same
if(0 == ::memcmp(&mRotImgInfo, &mLSRotImgInfo,
sizeof (msm_rotator_img_info))) {
return false;
}
return true;
}
bool MdpRot::init()
{
if(!mFd.open(Res::rotPath, O_RDWR)){
ALOGE("MdpRot failed to init %s", Res::rotPath);
return false;
}
return true;
}
void MdpRot::setSource(const overlay::utils::Whf& awhf) {
utils::Whf whf(awhf);
mRotImgInfo.src.format = whf.format;
mRotImgInfo.src.width = whf.w;
mRotImgInfo.src.height = whf.h;
mRotImgInfo.src_rect.w = whf.w;
mRotImgInfo.src_rect.h = whf.h;
mRotImgInfo.dst.width = whf.w;
mRotImgInfo.dst.height = whf.h;
}
void MdpRot::setCrop(const utils::Dim& /*crop*/) {
// NO-OP for non-mdss rotator due to possible h/w limitations
}
void MdpRot::setFrameRate(uint32_t /*frame_rate*/) {
// NO-OP for non-mdss rotator
}
void MdpRot::setFlags(const utils::eMdpFlags& flags) {
mRotImgInfo.secure = 0;
if(flags & utils::OV_MDP_SECURE_OVERLAY_SESSION)
mRotImgInfo.secure = 1;
}
void MdpRot::setTransform(const utils::eTransform& rot)
{
int r = utils::getMdpOrient(rot);
setRotations(r);
mOrientation = static_cast<utils::eTransform>(r);
ALOGE_IF(DEBUG_OVERLAY, "%s: r=%d", __FUNCTION__, r);
}
void MdpRot::doTransform() {
if(mOrientation & utils::OVERLAY_TRANSFORM_ROT_90)
utils::swap(mRotImgInfo.dst.width, mRotImgInfo.dst.height);
}
bool MdpRot::commit() {
doTransform();
if(rotConfChanged()) {
mRotImgInfo.enable = 1;
if(!overlay::mdp_wrapper::startRotator(mFd.getFD(), mRotImgInfo)) {
ALOGE("MdpRot commit failed");
dump();
mRotImgInfo.enable = 0;
return false;
}
mRotDataInfo.session_id = mRotImgInfo.session_id;
}
return true;
}
uint32_t MdpRot::calcOutputBufSize() {
ovutils::Whf destWhf(mRotImgInfo.dst.width,
mRotImgInfo.dst.height, mRotImgInfo.dst.format);
return Rotator::calcOutputBufSize(destWhf);
}
bool MdpRot::open_i(uint32_t numbufs, uint32_t bufsz)
{
OvMem mem;
OVASSERT(MAP_FAILED == mem.addr(), "MAP failed in open_i");
if(!mem.open(numbufs, bufsz, mRotImgInfo.secure)){
ALOGE("%s: Failed to open", __func__);
mem.close();
return false;
}
OVASSERT(MAP_FAILED != mem.addr(), "MAP failed");
OVASSERT(mem.getFD() != -1, "getFd is -1");
mRotDataInfo.dst.memory_id = mem.getFD();
mRotDataInfo.dst.offset = 0;
mMem.mem = mem;
return true;
}
bool MdpRot::close() {
bool success = true;
if(mFd.valid() && (getSessId() != 0)) {
if(!mdp_wrapper::endRotator(mFd.getFD(), getSessId())) {
ALOGE("Mdp Rot error endRotator, fd=%d sessId=%u",
mFd.getFD(), getSessId());
success = false;
}
}
if (!mFd.close()) {
ALOGE("Mdp Rot error closing fd");
success = false;
}
if (!mMem.close()) {
ALOGE("Mdp Rot error closing mem");
success = false;
}
reset();
return success;
}
bool MdpRot::remap(uint32_t numbufs) {
// if current size changed, remap
uint32_t opBufSize = calcOutputBufSize();
if(opBufSize == mMem.size()) {
ALOGE_IF(DEBUG_OVERLAY, "%s: same size %d", __FUNCTION__, opBufSize);
return true;
}
if(!mMem.close()) {
ALOGE("%s error in closing prev rot mem", __FUNCTION__);
return false;
}
ALOGE_IF(DEBUG_OVERLAY, "%s: size changed - remapping", __FUNCTION__);
if(!open_i(numbufs, opBufSize)) {
ALOGE("%s Error could not open", __FUNCTION__);
return false;
}
for (uint32_t i = 0; i < numbufs; ++i) {
mMem.mRotOffset[i] = i * opBufSize;
}
return true;
}
void MdpRot::reset() {
ovutils::memset0(mRotImgInfo);
ovutils::memset0(mLSRotImgInfo);
ovutils::memset0(mRotDataInfo);
ovutils::memset0(mMem.mRotOffset);
mMem.mCurrIndex = 0;
mOrientation = utils::OVERLAY_TRANSFORM_0;
}
bool MdpRot::queueBuffer(int fd, uint32_t offset) {
if(enabled() and (not isRotCached(fd,offset))) {
int prev_fd = getSrcMemId();
uint32_t prev_offset = getSrcOffset();
mRotDataInfo.src.memory_id = fd;
mRotDataInfo.src.offset = offset;
if(false == remap(RotMem::ROT_NUM_BUFS)) {
ALOGE("%s Remap failed, not queueing", __FUNCTION__);
return false;
}
mRotDataInfo.dst.offset =
mMem.mRotOffset[mMem.mCurrIndex];
if(!overlay::mdp_wrapper::rotate(mFd.getFD(), mRotDataInfo)) {
ALOGE("MdpRot failed rotate");
dump();
mRotDataInfo.src.memory_id = prev_fd;
mRotDataInfo.src.offset = prev_offset;
return false;
}
save();
mMem.mCurrIndex =
(mMem.mCurrIndex + 1) % mMem.mem.numBufs();
}
return true;
}
void MdpRot::dump() const {
ALOGE("== Dump MdpRot start ==");
mFd.dump();
mMem.mem.dump();
mdp_wrapper::dump("mRotImgInfo", mRotImgInfo);
mdp_wrapper::dump("mRotDataInfo", mRotDataInfo);
ALOGE("== Dump MdpRot end ==");
}
void MdpRot::getDump(char *buf, size_t len) const {
ovutils::getDump(buf, len, "MdpRotCtrl", mRotImgInfo);
ovutils::getDump(buf, len, "MdpRotData", mRotDataInfo);
}
int MdpRot::getDownscaleFactor(const int& src_w, const int& src_h,
const int& dst_w, const int& dst_h, const uint32_t& /*mdpFormat*/,
const bool& /*isInterlaced*/) {
int dscale_factor = utils::ROT_DS_NONE;
// We need this check to engage the rotator whenever possible to assist MDP
// in performing video downscale.
// This saves bandwidth and avoids causing the driver to make too many panel
// -mode switches between BLT (writeback) and non-BLT (Direct) modes.
// Use-case: Video playback [with downscaling and rotation].
if (dst_w && dst_h)
{
float fDscale = (float)(src_w * src_h) / (float)(dst_w * dst_h);
uint32_t dscale = (int)sqrtf(fDscale);
if(dscale < 2) {
// Down-scale to > 50% of orig.
dscale_factor = utils::ROT_DS_NONE;
} else if(dscale < 4) {
// Down-scale to between > 25% to <= 50% of orig.
dscale_factor = utils::ROT_DS_HALF;
} else if(dscale < 8) {
// Down-scale to between > 12.5% to <= 25% of orig.
dscale_factor = utils::ROT_DS_FOURTH;
} else {
// Down-scale to <= 12.5% of orig.
dscale_factor = utils::ROT_DS_EIGHTH;
}
}
return dscale_factor;
}
} // namespace overlay

View File

@@ -1,434 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
* Not a Contribution, Apache license notifications and license are retained
* for attribution purposes only.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <math.h>
#include "overlayUtils.h"
#include "overlayRotator.h"
#define DEBUG_MDSS_ROT 0
#ifdef VENUS_COLOR_FORMAT
#include <media/msm_media_info.h>
#else
#define VENUS_BUFFER_SIZE(args...) 0
#endif
#ifndef MDSS_MDP_ROT_ONLY
#define MDSS_MDP_ROT_ONLY 0x80
#endif
#define MDSS_ROT_MASK (MDP_ROT_90 | MDP_FLIP_UD | MDP_FLIP_LR)
namespace ovutils = overlay::utils;
namespace overlay {
using namespace utils;
MdssRot::MdssRot() {
reset();
init();
}
MdssRot::~MdssRot() { close(); }
bool MdssRot::enabled() const { return mEnabled; }
void MdssRot::setRotations(uint32_t flags) { mRotInfo.flags |= flags; }
int MdssRot::getSrcMemId() const {
return mRotData.data.memory_id;
}
int MdssRot::getDstMemId() const {
return mRotData.dst_data.memory_id;
}
uint32_t MdssRot::getSrcOffset() const {
return mRotData.data.offset;
}
uint32_t MdssRot::getDstOffset() const {
return mRotData.dst_data.offset;
}
uint32_t MdssRot::getDstFormat() const {
//For mdss src and dst formats are same
return mRotInfo.src.format;
}
utils::Whf MdssRot::getDstWhf() const {
//For Mdss dst_rect itself represents buffer dimensions. We ignore actual
//aligned values during buffer allocation. Also the driver overwrites the
//src.format field if destination format is different.
//This implementation detail makes it possible to retrieve w,h even before
//buffer allocation, which happens in queueBuffer.
return utils::Whf(mRotInfo.dst_rect.w, mRotInfo.dst_rect.h,
mRotInfo.src.format);
}
utils::Dim MdssRot::getDstDimensions() const {
return utils::Dim(mRotInfo.dst_rect.x, mRotInfo.dst_rect.y,
mRotInfo.dst_rect.w, mRotInfo.dst_rect.h);
}
uint32_t MdssRot::getSessId() const { return mRotInfo.id; }
void MdssRot::save() {
mLSRotInfo = mRotInfo;
}
bool MdssRot::rotConfChanged() const {
// 0 means same
if(0 == ::memcmp(&mRotInfo, &mLSRotInfo,
sizeof (mdp_overlay))) {
return false;
}
return true;
}
bool MdssRot::init() {
if(!utils::openDev(mFd, 0, Res::fbPath, O_RDWR)) {
ALOGE("MdssRot failed to init fb0");
return false;
}
return true;
}
void MdssRot::setSource(const overlay::utils::Whf& awhf) {
utils::Whf whf(awhf);
mRotInfo.src.format = whf.format;
mRotInfo.src.width = whf.w;
mRotInfo.src.height = whf.h;
}
void MdssRot::setCrop(const utils::Dim& crop) {
mRotInfo.src_rect.x = crop.x;
mRotInfo.src_rect.y = crop.y;
mRotInfo.src_rect.w = crop.w;
mRotInfo.src_rect.h = crop.h;
}
void MdssRot::setDownscale(int downscale) {
mDownscale = downscale;
}
void MdssRot::setFrameRate(uint32_t frame_rate) {
mRotInfo.frame_rate = frame_rate;
}
void MdssRot::setFlags(const utils::eMdpFlags& flags) {
mRotInfo.flags = flags;
}
void MdssRot::setTransform(const utils::eTransform& rot)
{
// reset rotation flags to avoid stale orientation values
mRotInfo.flags &= ~MDSS_ROT_MASK;
int flags = utils::getMdpOrient(rot);
if (flags != -1)
setRotations(flags);
mOrientation = static_cast<utils::eTransform>(flags);
ALOGE_IF(DEBUG_OVERLAY, "%s: rot=%d", __FUNCTION__, flags);
}
void MdssRot::doTransform() {
mRotInfo.flags |= mOrientation;
if(mOrientation & utils::OVERLAY_TRANSFORM_ROT_90)
utils::swap(mRotInfo.dst_rect.w, mRotInfo.dst_rect.h);
}
bool MdssRot::commit() {
Dim adjCrop(mRotInfo.src_rect.x,mRotInfo.src_rect.y,
mRotInfo.src_rect.w,mRotInfo.src_rect.h);
adjCrop = getFormatAdjustedCrop(adjCrop, mRotInfo.src.format,
mRotInfo.flags & utils::OV_MDP_DEINTERLACE);
adjCrop = getDownscaleAdjustedCrop(adjCrop, mDownscale);
mRotInfo.src_rect.x = adjCrop.x;
mRotInfo.src_rect.y = adjCrop.y;
mRotInfo.src_rect.w = adjCrop.w;
mRotInfo.src_rect.h = adjCrop.h;
mRotInfo.dst_rect.x = 0;
mRotInfo.dst_rect.y = 0;
mRotInfo.dst_rect.w = mDownscale ?
mRotInfo.src_rect.w / mDownscale : mRotInfo.src_rect.w;
mRotInfo.dst_rect.h = mDownscale ?
mRotInfo.src_rect.h / mDownscale : mRotInfo.src_rect.h;
//Clear for next round
mDownscale = 0;
doTransform();
mRotInfo.flags |= MDSS_MDP_ROT_ONLY;
mEnabled = true;
if(!overlay::mdp_wrapper::setOverlay(mFd.getFD(), mRotInfo)) {
ALOGE("MdssRot commit failed!");
dump();
return (mEnabled = false);
}
mRotData.id = mRotInfo.id;
return true;
}
bool MdssRot::queueBuffer(int fd, uint32_t offset) {
if(enabled() and (not isRotCached(fd,offset))) {
int prev_fd = getSrcMemId();
uint32_t prev_offset = getSrcOffset();
mRotData.data.memory_id = fd;
mRotData.data.offset = offset;
if(false == remap(RotMem::ROT_NUM_BUFS)) {
ALOGE("%s Remap failed, not queuing", __FUNCTION__);
return false;
}
mRotData.dst_data.offset =
mMem.mRotOffset[mMem.mCurrIndex];
if(!overlay::mdp_wrapper::play(mFd.getFD(), mRotData)) {
ALOGE("MdssRot play failed!");
dump();
mRotData.data.memory_id = prev_fd;
mRotData.data.offset = prev_offset;
return false;
}
save();
mMem.mCurrIndex =
(mMem.mCurrIndex + 1) % mMem.mem.numBufs();
}
return true;
}
bool MdssRot::open_i(uint32_t numbufs, uint32_t bufsz)
{
OvMem mem;
OVASSERT(MAP_FAILED == mem.addr(), "MAP failed in open_i");
bool isSecure = mRotInfo.flags & utils::OV_MDP_SECURE_OVERLAY_SESSION;
if(!mem.open(numbufs, bufsz, isSecure)){
ALOGE("%s: Failed to open", __func__);
mem.close();
return false;
}
OVASSERT(MAP_FAILED != mem.addr(), "MAP failed");
OVASSERT(mem.getFD() != -1, "getFd is -1");
mRotData.dst_data.memory_id = mem.getFD();
mRotData.dst_data.offset = 0;
mMem.mem = mem;
return true;
}
bool MdssRot::remap(uint32_t numbufs) {
// Calculate the size based on rotator's dst format, w and h.
uint32_t opBufSize = calcOutputBufSize();
// If current size changed, remap
if(opBufSize == mMem.size()) {
ALOGE_IF(DEBUG_OVERLAY, "%s: same size %d", __FUNCTION__, opBufSize);
return true;
}
ALOGE_IF(DEBUG_OVERLAY, "%s: size changed - remapping", __FUNCTION__);
if(!mMem.close()) {
ALOGE("%s error in closing prev rot mem", __FUNCTION__);
return false;
}
if(!open_i(numbufs, opBufSize)) {
ALOGE("%s Error could not open", __FUNCTION__);
return false;
}
for (uint32_t i = 0; i < numbufs; ++i) {
mMem.mRotOffset[i] = i * opBufSize;
}
return true;
}
bool MdssRot::close() {
bool success = true;
if(mFd.valid() && (getSessId() != (uint32_t) MSMFB_NEW_REQUEST)) {
if(!mdp_wrapper::unsetOverlay(mFd.getFD(), getSessId())) {
ALOGE("MdssRot::close unsetOverlay failed, fd=%d sessId=%d",
mFd.getFD(), getSessId());
success = false;
}
}
if (!mFd.close()) {
ALOGE("Mdss Rot error closing fd");
success = false;
}
if (!mMem.close()) {
ALOGE("Mdss Rot error closing mem");
success = false;
}
reset();
return success;
}
void MdssRot::reset() {
ovutils::memset0(mRotInfo);
ovutils::memset0(mLSRotInfo);
ovutils::memset0(mRotData);
mRotData.data.memory_id = -1;
mRotInfo.id = MSMFB_NEW_REQUEST;
ovutils::memset0(mMem.mRotOffset);
mMem.mCurrIndex = 0;
mOrientation = utils::OVERLAY_TRANSFORM_0;
mDownscale = 0;
}
void MdssRot::dump() const {
ALOGE("== Dump MdssRot start ==");
mFd.dump();
mMem.mem.dump();
mdp_wrapper::dump("mRotInfo", mRotInfo);
mdp_wrapper::dump("mRotData", mRotData);
ALOGE("== Dump MdssRot end ==");
}
uint32_t MdssRot::calcOutputBufSize() {
uint32_t opBufSize = 0;
ovutils::Whf destWhf(mRotInfo.dst_rect.w, mRotInfo.dst_rect.h,
mRotInfo.src.format); //mdss src and dst formats are same.
if (mRotInfo.flags & ovutils::OV_MDSS_MDP_BWC_EN) {
opBufSize = calcCompressedBufSize(destWhf);
} else {
opBufSize = Rotator::calcOutputBufSize(destWhf);
}
return opBufSize;
}
void MdssRot::getDump(char *buf, size_t len) const {
ovutils::getDump(buf, len, "MdssRotCtrl", mRotInfo);
ovutils::getDump(buf, len, "MdssRotData", mRotData);
}
// Calculate the compressed o/p buffer size for BWC
uint32_t MdssRot::calcCompressedBufSize(const ovutils::Whf& destWhf) {
uint32_t bufSize = 0;
//Worst case alignments
int aWidth = ovutils::align(destWhf.w, 64);
int aHeight = ovutils::align(destWhf.h, 4);
/*
Format | RAU size (width x height)
----------------------------------------------
ARGB | 32 pixel x 4 line
RGB888 | 32 pixel x 4 line
Y (Luma) | 64 pixel x 4 line
CRCB 420 | 32 pixel x 2 line
CRCB 422 H2V1 | 32 pixel x 4 line
CRCB 422 H1V2 | 64 pixel x 2 line
Metadata requirements:-
1 byte meta data for every 8 RAUs
2 byte meta data per RAU
*/
//These blocks attempt to allocate for the worst case in each of the
//respective format classes, yuv/rgb. The table above is for reference
if(utils::isYuv(destWhf.format)) {
int yRauCount = aWidth / 64; //Y
int cRauCount = aWidth / 32; //C
int yStride = (64 * 4 * yRauCount) + alignup(yRauCount, 8) / 8;
int cStride = ((32 * 2 * cRauCount) + alignup(cRauCount, 8) / 8) * 2;
int yStrideOffset = (aHeight / 4);
int cStrideOffset = (aHeight / 2);
bufSize = (yStride * yStrideOffset + cStride * cStrideOffset) +
(yRauCount * yStrideOffset * 2) +
(cRauCount * cStrideOffset * 2) * 2;
ALOGD_IF(DEBUG_MDSS_ROT, "%s:YUV Y RAU Count = %d C RAU Count = %d",
__FUNCTION__, yRauCount, cRauCount);
} else {
int rauCount = aWidth / 32;
//Single plane
int stride = (32 * 4 * rauCount) + alignup(rauCount, 8) / 8;
int strideOffset = (aHeight / 4);
bufSize = (stride * strideOffset * 4 /*bpp*/) +
(rauCount * strideOffset * 2);
ALOGD_IF(DEBUG_MDSS_ROT, "%s:RGB RAU count = %d", __FUNCTION__,
rauCount);
}
ALOGD_IF(DEBUG_MDSS_ROT, "%s: aligned width = %d, aligned height = %d "
"Buf Size = %d", __FUNCTION__, aWidth, aHeight, bufSize);
return bufSize;
}
int MdssRot::getDownscaleFactor(const int& srcW, const int& srcH,
const int& dstW, const int& dstH, const uint32_t& mdpFormat,
const bool& isInterlaced) {
if(not srcW or not srcH or not dstW or not dstH or isInterlaced) return 0;
Dim crop(0, 0, srcW, srcH);
Dim adjCrop = getFormatAdjustedCrop(crop, mdpFormat,
false /*isInterlaced */);
uint32_t downscale = min((adjCrop.w / dstW), (adjCrop.h / dstH));
//Reduced to a power of 2
downscale = (uint32_t) powf(2.0f, floorf(log2f((float)downscale)));
if(downscale < 2 or downscale > 32) return 0;
//Allow only 1 line or pixel to be chopped off since the source needs to
//be aligned to downscale. Progressively try with smaller downscale to see
//if we can satisfy the threshold
//For YUV the loop shouldnt be needed, unless in exceptional cases
Dim dsAdjCrop = getDownscaleAdjustedCrop(adjCrop, downscale);
while(downscale > 2 and (adjCrop.w > dsAdjCrop.w or
adjCrop.h > dsAdjCrop.h)) {
downscale /= 2;
dsAdjCrop = getDownscaleAdjustedCrop(adjCrop, downscale);
}
if(not dsAdjCrop.w or not dsAdjCrop.h) return 0;
return downscale;
}
Dim MdssRot::getFormatAdjustedCrop(const Dim& crop,
const uint32_t& mdpFormat, const bool& isInterlaced) {
Dim adjCrop = crop;
if (isYuv(mdpFormat)) {
normalizeCrop(adjCrop.x, adjCrop.w);
normalizeCrop(adjCrop.y, adjCrop.h);
// For interlaced, crop.h should be 4-aligned
if (isInterlaced and (adjCrop.h % 4))
adjCrop.h = aligndown(adjCrop.h, 4);
}
return adjCrop;
}
Dim MdssRot::getDownscaleAdjustedCrop(const Dim& crop,
const uint32_t& downscale) {
uint32_t alignedSrcW = aligndown(crop.w, downscale * 2);
uint32_t alignedSrcH = aligndown(crop.h, downscale * 2);
return Dim(crop.x, crop.y, alignedSrcW, alignedSrcH);
}
} // namespace overlay

View File

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

View File

@@ -1,242 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
* Not a Contribution, Apache license notifications and license are retained
* for attribution purposes only.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "overlayRotator.h"
#include "overlayUtils.h"
#include "mdp_version.h"
#include "sync/sync.h"
#include "gr.h"
namespace ovutils = overlay::utils;
namespace overlay {
//============Rotator=========================
Rotator::Rotator() {
char property[PROPERTY_VALUE_MAX];
mRotCacheDisabled = false;
if((property_get("debug.rotcache.disable", property, NULL) > 0) &&
(!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
(!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
/* Used in debugging to turnoff rotator caching */
mRotCacheDisabled = true;
}
}
Rotator::~Rotator() {}
Rotator* Rotator::getRotator() {
int type = getRotatorHwType();
if(type == TYPE_MDP) {
return new MdpRot(); //will do reset
} else if(type == TYPE_MDSS) {
return new MdssRot();
} else {
ALOGE("%s Unknown h/w type %d", __FUNCTION__, type);
return NULL;
}
}
int Rotator::getDownscaleFactor(const int& srcW, const int& srcH,
const int& dstW, const int& dstH, const uint32_t& mdpFormat,
const bool& isInterlaced) {
if(getRotatorHwType() == TYPE_MDSS) {
return MdssRot::getDownscaleFactor(srcW, srcH, dstW, dstH,
mdpFormat, isInterlaced);
}
return MdpRot::getDownscaleFactor(srcW, srcH, dstW, dstH,
mdpFormat, isInterlaced);
}
uint32_t Rotator::calcOutputBufSize(const utils::Whf& destWhf) {
//dummy aligned w & h.
int alW = 0, alH = 0;
int halFormat = ovutils::getHALFormat(destWhf.format);
//A call into gralloc/memalloc
return getBufferSizeAndDimensions(
destWhf.w, destWhf.h, halFormat, alW, alH);
}
int Rotator::getRotatorHwType() {
int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion();
if (mdpVersion == qdutils::MDSS_V5)
return TYPE_MDSS;
return TYPE_MDP;
}
bool Rotator::isRotCached(int fd, uint32_t offset) const {
if(mRotCacheDisabled or rotConfChanged() or rotDataChanged(fd,offset))
return false;
return true;
}
bool Rotator::rotDataChanged(int fd, uint32_t offset) const {
/* fd and offset are the attributes of the current rotator input buffer.
* At this instance, getSrcMemId() and getSrcOffset() return the
* attributes of the previous rotator input buffer */
if( (fd == getSrcMemId()) and (offset == getSrcOffset()) )
return false;
return true;
}
//============RotMem=========================
bool RotMem::close() {
bool ret = true;
if(valid()) {
if(mem.close() == false) {
ALOGE("%s error in closing rot mem", __FUNCTION__);
ret = false;
}
}
return ret;
}
RotMem::RotMem() : mCurrIndex(0) {
utils::memset0(mRotOffset);
for(int i = 0; i < ROT_NUM_BUFS; i++) {
mRelFence[i] = -1;
}
}
RotMem::~RotMem() {
for(int i = 0; i < ROT_NUM_BUFS; i++) {
::close(mRelFence[i]);
mRelFence[i] = -1;
}
}
void RotMem::setCurrBufReleaseFd(const int& fence) {
int ret = 0;
if(mRelFence[mCurrIndex] >= 0) {
//Wait for previous usage of this buffer to be over.
//Can happen if rotation takes > vsync and a fast producer. i.e queue
//happens in subsequent vsyncs either because content is 60fps or
//because the producer is hasty sometimes.
ret = sync_wait(mRelFence[mCurrIndex], 1000);
if(ret < 0) {
ALOGE("%s: sync_wait error!! error no = %d err str = %s",
__FUNCTION__, errno, strerror(errno));
}
::close(mRelFence[mCurrIndex]);
}
mRelFence[mCurrIndex] = fence;
}
void RotMem::setPrevBufReleaseFd(const int& fence) {
uint32_t numRotBufs = mem.numBufs();
uint32_t prevIndex = (mCurrIndex + numRotBufs - 1) % (numRotBufs);
if(mRelFence[prevIndex] >= 0) {
/* No need of any wait as nothing will be written into this
* buffer by the rotator (this func is called when rotator is
* in cache mode) */
::close(mRelFence[prevIndex]);
}
mRelFence[prevIndex] = fence;
}
//============RotMgr=========================
RotMgr * RotMgr::sRotMgr = NULL;
RotMgr* RotMgr::getInstance() {
if(sRotMgr == NULL) {
sRotMgr = new RotMgr();
}
return sRotMgr;
}
RotMgr::RotMgr() {
for(int i = 0; i < MAX_ROT_SESS; i++) {
mRot[i] = 0;
}
mUseCount = 0;
mRotDevFd = -1;
}
RotMgr::~RotMgr() {
clear();
}
void RotMgr::configBegin() {
//Reset the number of objects used
mUseCount = 0;
}
void RotMgr::configDone() {
//Remove the top most unused objects. Videos come and go.
for(int i = mUseCount; i < MAX_ROT_SESS; i++) {
if(mRot[i]) {
delete mRot[i];
mRot[i] = 0;
}
}
}
Rotator* RotMgr::getNext() {
//Return a rot object, creating one if necessary
overlay::Rotator *rot = NULL;
if(mUseCount >= MAX_ROT_SESS) {
ALOGW("%s, MAX rotator sessions reached, request rejected", __func__);
} else {
if(mRot[mUseCount] == NULL)
mRot[mUseCount] = overlay::Rotator::getRotator();
rot = mRot[mUseCount++];
}
return rot;
}
void RotMgr::clear() {
//Brute force obj destruction, helpful in suspend.
for(int i = 0; i < MAX_ROT_SESS; i++) {
if(mRot[i]) {
delete mRot[i];
mRot[i] = 0;
}
}
mUseCount = 0;
::close(mRotDevFd);
mRotDevFd = -1;
}
void RotMgr::getDump(char *buf, size_t len) {
for(int i = 0; i < MAX_ROT_SESS; i++) {
if(mRot[i]) {
mRot[i]->getDump(buf, len);
}
}
char str[4] = {'\0'};
snprintf(str, 4, "\n");
strlcat(buf, str, len);
}
int RotMgr::getRotDevFd() {
if(mRotDevFd < 0 && Rotator::getRotatorHwType() == Rotator::TYPE_MDSS) {
mRotDevFd = ::open("/dev/graphics/fb0", O_RDWR, 0);
if(mRotDevFd < 0) {
ALOGE("%s failed to open fb0", __FUNCTION__);
}
}
return mRotDevFd;
}
}

View File

@@ -1,325 +0,0 @@
/*
* Copyright (c) 2011,2013 The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OVERlAY_ROTATOR_H
#define OVERlAY_ROTATOR_H
#include <stdlib.h>
#include "mdpWrapper.h"
#include "overlayUtils.h"
#include "overlayMem.h"
namespace overlay {
/*
Manages the case where new rotator memory needs to be
allocated, before previous is freed, due to resolution change etc. If we make
rotator memory to be always max size, irrespctive of source resolution then
we don't need this RotMem wrapper. The inner class is sufficient.
*/
struct RotMem {
// Max rotator buffers
enum { ROT_NUM_BUFS = 2 };
RotMem();
~RotMem();
bool close();
bool valid() { return mem.valid(); }
uint32_t size() const { return mem.bufSz(); }
void setCurrBufReleaseFd(const int& fence);
void setPrevBufReleaseFd(const int& fence);
// rotator data info dst offset
uint32_t mRotOffset[ROT_NUM_BUFS];
int mRelFence[ROT_NUM_BUFS];
// current slot being used
uint32_t mCurrIndex;
OvMem mem;
};
class Rotator
{
public:
enum { TYPE_MDP, TYPE_MDSS };
virtual ~Rotator();
virtual void setSource(const utils::Whf& wfh) = 0;
virtual void setCrop(const utils::Dim& crop) = 0;
virtual void setFlags(const utils::eMdpFlags& flags) = 0;
virtual void setTransform(const utils::eTransform& rot) = 0;
virtual bool commit() = 0;
/* return true if the current rotator state is cached */
virtual bool isRotCached(int fd, uint32_t offset) const;
/* return true if current rotator config is same as the last round*/
virtual bool rotConfChanged() const = 0;
/* return true if the current rotator input buffer fd and offset
* are same as the last round */
virtual bool rotDataChanged(int fd, uint32_t offset) const;
virtual void setDownscale(int ds) = 0;
/* returns the src buffer of the rotator for the previous/current round,
* depending on when it is called(before/after the queuebuffer)*/
virtual int getSrcMemId() const = 0;
//Mem id and offset should be retrieved only after rotator kickoff
virtual int getDstMemId() const = 0;
virtual uint32_t getSrcOffset() const = 0;
virtual uint32_t getDstOffset() const = 0;
//Destination width, height, format, position should be retrieved only after
//rotator configuration is committed via commit API
virtual uint32_t getDstFormat() const = 0;
virtual utils::Whf getDstWhf() const = 0;
virtual utils::Dim getDstDimensions() const = 0;
virtual uint32_t getSessId() const = 0;
virtual bool queueBuffer(int fd, uint32_t offset) = 0;
virtual void dump() const = 0;
virtual void getDump(char *buf, size_t len) const = 0;
virtual void setFrameRate(uint32_t frame_rate) = 0;
inline void setCurrBufReleaseFd(const int& fence) {
mMem.setCurrBufReleaseFd(fence);
}
inline void setPrevBufReleaseFd(const int& fence) {
mMem.setPrevBufReleaseFd(fence);
}
static Rotator *getRotator();
/* Returns downscale by successfully applying constraints
* Returns 0 if target doesnt support rotator downscaling
* or if any of the constraints are not met
*/
static int getDownscaleFactor(const int& srcW, const int& srcH,
const int& dstW, const int& dstH, const uint32_t& mdpFormat,
const bool& isInterlaced);
protected:
/* Rotator memory manager */
RotMem mMem;
Rotator();
static uint32_t calcOutputBufSize(const utils::Whf& destWhf);
private:
bool mRotCacheDisabled;
/*Returns rotator h/w type */
static int getRotatorHwType();
friend class RotMgr;
};
/*
* MDP rot holds MDP's rotation related structures.
*
* */
class MdpRot : public Rotator {
public:
virtual ~MdpRot();
virtual void setSource(const utils::Whf& wfh);
virtual void setCrop(const utils::Dim& crop);
virtual void setFlags(const utils::eMdpFlags& flags);
virtual void setTransform(const utils::eTransform& rot);
virtual bool commit();
virtual bool rotConfChanged() const;
virtual void setDownscale(int ds);
virtual int getSrcMemId() const;
virtual int getDstMemId() const;
virtual uint32_t getSrcOffset() const;
virtual uint32_t getDstOffset() const;
virtual uint32_t getDstFormat() const;
virtual utils::Whf getDstWhf() const;
virtual utils::Dim getDstDimensions() const;
virtual uint32_t getSessId() const;
virtual bool queueBuffer(int fd, uint32_t offset);
virtual void dump() const;
virtual void getDump(char *buf, size_t len) const;
virtual void setFrameRate(uint32_t frame_rate);
private:
explicit MdpRot();
bool init();
bool close();
void setRotations(uint32_t r);
bool enabled () const;
/* remap rot buffers */
bool remap(uint32_t numbufs);
bool open_i(uint32_t numbufs, uint32_t bufsz);
/* Deferred transform calculations */
void doTransform();
/* reset underlying data, basically memset 0 */
void reset();
/* save mRotImgInfo to be last known good config*/
void save();
/* Calculates the rotator's o/p buffer size post the transform calcs and
* knowing the o/p format depending on whether fastYuv is enabled or not */
uint32_t calcOutputBufSize();
/* Applies downscale by taking areas
* Returns a log(downscale)
* Constraints applied:
* - downscale should be a power of 2
* - Max downscale is 1/8
*/
static int getDownscaleFactor(const int& srcW, const int& srcH,
const int& dstW, const int& dstH, const uint32_t& mdpFormat,
const bool& isInterlaced);
/* rot info*/
msm_rotator_img_info mRotImgInfo;
/* Last saved rot info*/
msm_rotator_img_info mLSRotImgInfo;
/* rot data */
msm_rotator_data_info mRotDataInfo;
/* Orientation */
utils::eTransform mOrientation;
/* rotator fd */
OvFD mFd;
friend Rotator* Rotator::getRotator();
friend int Rotator::getDownscaleFactor(const int& srcW, const int& srcH,
const int& dstW, const int& dstH, const uint32_t& mdpFormat,
const bool& isInterlaced);
};
/*
+* MDSS Rot holds MDSS's rotation related structures.
+*
+* */
class MdssRot : public Rotator {
public:
virtual ~MdssRot();
virtual void setSource(const utils::Whf& wfh);
virtual void setCrop(const utils::Dim& crop);
virtual void setFlags(const utils::eMdpFlags& flags);
virtual void setTransform(const utils::eTransform& rot);
virtual bool commit();
virtual bool rotConfChanged() const;
virtual void setDownscale(int ds);
virtual int getSrcMemId() const;
virtual int getDstMemId() const;
virtual uint32_t getSrcOffset() const;
virtual uint32_t getDstOffset() const;
virtual uint32_t getDstFormat() const;
virtual utils::Whf getDstWhf() const;
virtual utils::Dim getDstDimensions() const;
virtual uint32_t getSessId() const;
virtual bool queueBuffer(int fd, uint32_t offset);
virtual void dump() const;
virtual void getDump(char *buf, size_t len) const;
virtual void setFrameRate(uint32_t frame_rate);
private:
explicit MdssRot();
bool init();
bool close();
void setRotations(uint32_t r);
bool enabled () const;
/* remap rot buffers */
bool remap(uint32_t numbufs);
bool open_i(uint32_t numbufs, uint32_t bufsz);
/* Deferred transform calculations */
void doTransform();
/* reset underlying data, basically memset 0 */
void reset();
/* save mRotInfo to be last known good config*/
void save();
/* Calculates the rotator's o/p buffer size post the transform calcs and
* knowing the o/p format depending on whether fastYuv is enabled or not */
uint32_t calcOutputBufSize();
// Calculate the compressed o/p buffer size for BWC
uint32_t calcCompressedBufSize(const utils::Whf& destWhf);
/* Caller's responsibility to swap srcW, srcH if there is a 90 transform
* Returns actual downscale (not a log value)
* Constraints applied:
* - downscale should be a power of 2
* - Max downscale is 1/32
* - Equal downscale is applied in both directions
* - {srcW, srcH} mod downscale = 0
* - Interlaced content is not supported
*/
static int getDownscaleFactor(const int& srcW, const int& srcH,
const int& dstW, const int& dstH, const uint32_t& mdpFormat,
const bool& isInterlaced);
static utils::Dim getFormatAdjustedCrop(const utils::Dim& crop,
const uint32_t& mdpFormat, const bool& isInterlaced);
static utils::Dim getDownscaleAdjustedCrop(const utils::Dim& crop,
const uint32_t& downscale);
/* MdssRot info structure */
mdp_overlay mRotInfo;
/* Last saved MdssRot info structure*/
mdp_overlay mLSRotInfo;
/* MdssRot data structure */
msmfb_overlay_data mRotData;
/* Orientation */
utils::eTransform mOrientation;
/* rotator fd */
OvFD mFd;
/* Enable/Disable Mdss Rot*/
bool mEnabled;
int mDownscale;
friend Rotator* Rotator::getRotator();
friend int Rotator::getDownscaleFactor(const int& srcW, const int& srcH,
const int& dstW, const int& dstH, const uint32_t& mdpFormat,
const bool& isInterlaced);
};
// Holder of rotator objects. Manages lifetimes
class RotMgr {
public:
//Virtually we can support as many rotator sessions as possible, However
// more number of rotator sessions leads to performance issues, so
// restricting the max rotator session to 4
enum { MAX_ROT_SESS = 4 };
~RotMgr();
void configBegin();
void configDone();
overlay::Rotator *getNext();
void clear(); //Removes all instances
//Resets the usage of top count objects, making them available for reuse
void markUnusedTop(const uint32_t& count) { mUseCount -= count; }
/* Returns rot dump.
* Expects a NULL terminated buffer of big enough size.
*/
void getDump(char *buf, size_t len);
int getRotDevFd();
int getNumActiveSessions() { return mUseCount; }
static RotMgr *getInstance();
private:
RotMgr();
static RotMgr *sRotMgr;
overlay::Rotator *mRot[MAX_ROT_SESS];
uint32_t mUseCount;
int mRotDevFd;
};
} // overlay
#endif // OVERlAY_ROTATOR_H

View File

@@ -1,425 +0,0 @@
/*
* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <math.h>
#include <utils/Log.h>
#include <linux/msm_mdp.h>
#include <cutils/properties.h>
#include "gralloc_priv.h"
#include "overlayUtils.h"
#include "mdpWrapper.h"
#include "mdp_version.h"
#include <hardware/hwcomposer_defs.h>
// just a helper static thingy
namespace {
struct IOFile {
IOFile(const char* s, const char* mode) : fp(0) {
fp = ::fopen(s, mode);
if(!fp) {
ALOGE("Failed open %s", s);
}
}
template <class T>
size_t read(T& r, size_t elem) {
if(fp) {
return ::fread(&r, sizeof(T), elem, fp);
}
return 0;
}
size_t write(const char* s, uint32_t val) {
if(fp) {
return ::fprintf(fp, s, val);
}
return 0;
}
bool valid() const { return fp != 0; }
~IOFile() {
if(fp) ::fclose(fp);
fp=0;
}
FILE* fp;
};
}
namespace overlay {
//----------From class Res ------------------------------
const char* const Res::fbPath = "/dev/graphics/fb%u";
const char* const Res::rotPath = "/dev/msm_rotator";
//--------------------------------------------------------
namespace utils {
//--------------------------------------------------------
//Refer to graphics.h, gralloc_priv.h, msm_mdp.h
int getMdpFormat(int format) {
switch (format) {
//From graphics.h
case HAL_PIXEL_FORMAT_RGBA_8888 :
return MDP_RGBA_8888;
case HAL_PIXEL_FORMAT_RGBX_8888:
return MDP_RGBX_8888;
case HAL_PIXEL_FORMAT_RGB_888:
return MDP_RGB_888;
case HAL_PIXEL_FORMAT_RGB_565:
return MDP_RGB_565;
case HAL_PIXEL_FORMAT_RGBA_5551:
return MDP_RGBA_5551;
case HAL_PIXEL_FORMAT_RGBA_4444:
return MDP_RGBA_4444;
case HAL_PIXEL_FORMAT_BGRA_8888:
return MDP_BGRA_8888;
case HAL_PIXEL_FORMAT_BGRX_8888:
return MDP_BGRX_8888;
case HAL_PIXEL_FORMAT_YV12:
return MDP_Y_CR_CB_GH2V2;
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
return MDP_Y_CBCR_H2V1;
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
return MDP_Y_CRCB_H2V2;
//From gralloc_priv.h
case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
return MDP_Y_CBCR_H2V2_TILE;
case HAL_PIXEL_FORMAT_YCbCr_420_SP:
return MDP_Y_CBCR_H2V2;
case HAL_PIXEL_FORMAT_YCrCb_422_SP:
return MDP_Y_CRCB_H2V1;
case HAL_PIXEL_FORMAT_YCbCr_422_I:
return MDP_YCBYCR_H2V1;
case HAL_PIXEL_FORMAT_YCrCb_422_I:
return MDP_YCRYCB_H2V1;
case HAL_PIXEL_FORMAT_YCbCr_444_SP:
return MDP_Y_CBCR_H1V1;
case HAL_PIXEL_FORMAT_YCrCb_444_SP:
return MDP_Y_CRCB_H1V1;
case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
//NV12 encodeable format maps to the venus format on
//B-Family targets
return MDP_Y_CBCR_H2V2_VENUS;
case HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS:
return MDP_Y_CRCB_H2V2_VENUS;
default:
//Unsupported by MDP
//---gralloc_priv.h-----
//HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO = 0x7FA30C01
//HAL_PIXEL_FORMAT_R_8 = 0x10D
//HAL_PIXEL_FORMAT_RG_88 = 0x10E
ALOGE("%s: Unsupported HAL format = 0x%x", __func__, format);
return -1;
}
// not reached
return -1;
}
int getMdpFormat(int format, int flags)
{
bool uBwcEnabled = (flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED);
bool tileEnabled = (flags & private_handle_t::PRIV_FLAGS_TILE_RENDERED);
// Use UBWC extension, if UBWC is enabled
if (uBwcEnabled) {
switch (format) {
case HAL_PIXEL_FORMAT_RGBA_8888:
return MDP_RGBA_8888_UBWC;
case HAL_PIXEL_FORMAT_RGB_565:
return MDP_RGB_565_UBWC;
case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC:
return MDP_Y_CBCR_H2V2_UBWC;
default:
ALOGE("%s: Unsupported HAL format = 0x%x", __func__, format);
break;
}
}
if(!tileEnabled) {
return getMdpFormat(format);
}
switch (format) {
case HAL_PIXEL_FORMAT_RGBA_8888 :
return MDP_RGBA_8888_TILE;
case HAL_PIXEL_FORMAT_RGBX_8888:
return MDP_RGBX_8888_TILE;
case HAL_PIXEL_FORMAT_RGB_565:
return MDP_RGB_565_TILE;
case HAL_PIXEL_FORMAT_BGRA_8888:
return MDP_BGRA_8888_TILE;
case HAL_PIXEL_FORMAT_BGRX_8888:
return MDP_BGRX_8888_TILE;
default:
return getMdpFormat(format);
}
}
//Takes mdp format as input and translates to equivalent HAL format
//Refer to graphics.h, gralloc_priv.h, msm_mdp.h for formats.
int getHALFormat(int mdpFormat) {
switch (mdpFormat) {
//From graphics.h
case MDP_RGBA_8888:
return HAL_PIXEL_FORMAT_RGBA_8888;
case MDP_RGBX_8888:
return HAL_PIXEL_FORMAT_RGBX_8888;
case MDP_RGB_888:
return HAL_PIXEL_FORMAT_RGB_888;
case MDP_RGB_565:
return HAL_PIXEL_FORMAT_RGB_565;
case MDP_RGBA_5551:
return HAL_PIXEL_FORMAT_RGBA_5551;
case MDP_RGBA_4444:
return HAL_PIXEL_FORMAT_RGBA_4444;
case MDP_BGRA_8888:
return HAL_PIXEL_FORMAT_BGRA_8888;
case MDP_Y_CR_CB_GH2V2:
return HAL_PIXEL_FORMAT_YV12;
case MDP_Y_CBCR_H2V1:
return HAL_PIXEL_FORMAT_YCbCr_422_SP;
case MDP_Y_CRCB_H2V2:
return HAL_PIXEL_FORMAT_YCrCb_420_SP;
//From gralloc_priv.h
case MDP_Y_CBCR_H2V2_TILE:
return HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED;
case MDP_Y_CBCR_H2V2:
return HAL_PIXEL_FORMAT_YCbCr_420_SP;
case MDP_Y_CRCB_H2V1:
return HAL_PIXEL_FORMAT_YCrCb_422_SP;
case MDP_YCBYCR_H2V1:
return HAL_PIXEL_FORMAT_YCbCr_422_I;
case MDP_YCRYCB_H2V1:
return HAL_PIXEL_FORMAT_YCrCb_422_I;
case MDP_Y_CBCR_H1V1:
return HAL_PIXEL_FORMAT_YCbCr_444_SP;
case MDP_Y_CRCB_H1V1:
return HAL_PIXEL_FORMAT_YCrCb_444_SP;
case MDP_Y_CBCR_H2V2_VENUS:
return HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS;
case MDP_Y_CRCB_H2V2_VENUS:
return HAL_PIXEL_FORMAT_YCrCb_420_SP_VENUS;
default:
ALOGE("%s: Unsupported MDP format = 0x%x", __func__, mdpFormat);
return -1;
}
// not reached
return -1;
}
int getMdpOrient(eTransform rotation) {
int retTrans = 0;
bool trans90 = false;
int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion();
bool aFamily = (mdpVersion < qdutils::MDSS_V5);
ALOGD_IF(DEBUG_OVERLAY, "%s: In rotation = %d", __FUNCTION__, rotation);
if(rotation & OVERLAY_TRANSFORM_ROT_90) {
retTrans |= MDP_ROT_90;
trans90 = true;
}
if(rotation & OVERLAY_TRANSFORM_FLIP_H) {
if(trans90 && aFamily) {
//Swap for a-family, since its driver does 90 first
retTrans |= MDP_FLIP_UD;
} else {
retTrans |= MDP_FLIP_LR;
}
}
if(rotation & OVERLAY_TRANSFORM_FLIP_V) {
if(trans90 && aFamily) {
//Swap for a-family, since its driver does 90 first
retTrans |= MDP_FLIP_LR;
} else {
retTrans |= MDP_FLIP_UD;
}
}
ALOGD_IF(DEBUG_OVERLAY, "%s: Out rotation = %d", __FUNCTION__, retTrans);
return retTrans;
}
void getDecimationFactor(const int& src_w, const int& src_h,
const int& dst_w, const int& dst_h, uint8_t& horzDeci,
uint8_t& vertDeci) {
horzDeci = 0;
vertDeci = 0;
float horDscale = ceilf((float)src_w / (float)dst_w);
float verDscale = ceilf((float)src_h / (float)dst_h);
qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance();
//Next power of 2, if not already
horDscale = powf(2.0f, ceilf(log2f(horDscale)));
verDscale = powf(2.0f, ceilf(log2f(verDscale)));
//Since MDP can do downscale and has better quality, split the task
//between decimator and MDP downscale
horDscale /= (float)mdpHw.getMaxMDPDownscale();
verDscale /= (float)mdpHw.getMaxMDPDownscale();
if((int)horDscale)
horzDeci = (uint8_t)log2f(horDscale);
if((int)verDscale)
vertDeci = (uint8_t)log2f(verDscale);
if(src_w > (int) mdpHw.getMaxPipeWidth()) {
//If the client sends us something > what a layer mixer supports
//then it means it doesn't want to use split-pipe but wants us to
//decimate. A minimum decimation of 1 will ensure that the width is
//always within layer mixer limits.
const uint8_t minDeci = 1;
if(horzDeci < minDeci)
horzDeci = minDeci;
}
}
static inline int compute(const uint32_t& x, const uint32_t& y,
const uint32_t& z) {
return x - ( y + z );
}
void preRotateSource(const eTransform& tr, Whf& whf, Dim& srcCrop) {
if(tr & OVERLAY_TRANSFORM_FLIP_H) {
srcCrop.x = compute(whf.w, srcCrop.x, srcCrop.w);
}
if(tr & OVERLAY_TRANSFORM_FLIP_V) {
srcCrop.y = compute(whf.h, srcCrop.y, srcCrop.h);
}
if(tr & OVERLAY_TRANSFORM_ROT_90) {
int tmp = srcCrop.x;
srcCrop.x = compute(whf.h,
srcCrop.y,
srcCrop.h);
srcCrop.y = tmp;
swap(whf.w, whf.h);
swap(srcCrop.w, srcCrop.h);
}
}
void getDump(char *buf, size_t len, const char *prefix,
const mdp_overlay& ov) {
char str[256] = {'\0'};
snprintf(str, 256,
"%s id=%d z=%d alpha=%d mask=%d flags=0x%x H.Deci=%d,"
"V.Deci=%d\n",
prefix, ov.id, ov.z_order, ov.alpha,
ov.transp_mask, ov.flags, ov.horz_deci, ov.vert_deci);
strlcat(buf, str, len);
getDump(buf, len, "\tsrc", ov.src);
getDump(buf, len, "\tsrc_rect", ov.src_rect);
getDump(buf, len, "\tdst_rect", ov.dst_rect);
}
void getDump(char *buf, size_t len, const char *prefix,
const msmfb_img& ov) {
char str_src[256] = {'\0'};
snprintf(str_src, 256,
"%s w=%d h=%d format=%d %s\n",
prefix, ov.width, ov.height, ov.format,
overlay::utils::getFormatString(ov.format));
strlcat(buf, str_src, len);
}
void getDump(char *buf, size_t len, const char *prefix,
const mdp_rect& ov) {
char str_rect[256] = {'\0'};
snprintf(str_rect, 256,
"%s x=%d y=%d w=%d h=%d\n",
prefix, ov.x, ov.y, ov.w, ov.h);
strlcat(buf, str_rect, len);
}
void getDump(char *buf, size_t len, const char *prefix,
const msmfb_overlay_data& ov) {
char str[256] = {'\0'};
snprintf(str, 256,
"%s id=%d\n",
prefix, ov.id);
strlcat(buf, str, len);
getDump(buf, len, "\tdata", ov.data);
}
void getDump(char *buf, size_t len, const char *prefix,
const msmfb_data& ov) {
char str_data[256] = {'\0'};
snprintf(str_data, 256,
"%s offset=%d memid=%d id=%d flags=0x%x\n",
prefix, ov.offset, ov.memory_id, ov.id, ov.flags);
strlcat(buf, str_data, len);
}
void getDump(char *buf, size_t len, const char *prefix,
const msm_rotator_img_info& rot) {
char str[256] = {'\0'};
snprintf(str, 256, "%s sessid=%u rot=%d, enable=%d downscale=%d\n",
prefix, rot.session_id, rot.rotations, rot.enable,
rot.downscale_ratio);
strlcat(buf, str, len);
getDump(buf, len, "\tsrc", rot.src);
getDump(buf, len, "\tdst", rot.dst);
getDump(buf, len, "\tsrc_rect", rot.src_rect);
}
void getDump(char *buf, size_t len, const char *prefix,
const msm_rotator_data_info& rot) {
char str[256] = {'\0'};
snprintf(str, 256,
"%s sessid=%u\n",
prefix, rot.session_id);
strlcat(buf, str, len);
getDump(buf, len, "\tsrc", rot.src);
getDump(buf, len, "\tdst", rot.dst);
}
//Helper to even out x,w and y,h pairs
//x,y are always evened to ceil and w,h are evened to floor
void normalizeCrop(uint32_t& xy, uint32_t& wh) {
if(xy & 1) {
even_ceil(xy);
if(wh & 1)
even_floor(wh);
else
wh -= 2;
} else {
even_floor(wh);
}
}
} // utils
} // overlay

View File

@@ -1,692 +0,0 @@
/*
* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OVERLAY_UTILS_H
#define OVERLAY_UTILS_H
#include <cutils/log.h> // ALOGE, etc
#include <errno.h>
#include <fcntl.h> // open, O_RDWR, etc
#include <hardware/hardware.h>
#include <hardware/gralloc.h> // buffer_handle_t
#include <linux/msm_mdp.h> // flags
#include <linux/msm_rotator.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <utils/Log.h>
#include "gralloc_priv.h" //for interlace
// Older platforms do not support Venus
#ifndef VENUS_COLOR_FORMAT
#define MDP_Y_CBCR_H2V2_VENUS MDP_IMGTYPE_LIMIT
#endif
/*
*
* Collection of utilities functions/structs/enums etc...
*
* */
// comment that out if you want to remove asserts
// or put it as -D in Android.mk. your choice.
#define OVERLAY_HAS_ASSERT
#ifdef OVERLAY_HAS_ASSERT
# define OVASSERT(x, ...) if(!(x)) { ALOGE(__VA_ARGS__); abort(); }
#else
# define OVASSERT(x, ...) ALOGE_IF(!(x), __VA_ARGS__)
#endif // OVERLAY_HAS_ASSERT
#define DEBUG_OVERLAY 0
#define PROFILE_OVERLAY 0
#ifndef MDSS_MDP_RIGHT_MIXER
#define MDSS_MDP_RIGHT_MIXER 0x100
#endif
#ifndef MDP_OV_PIPE_FORCE_DMA
#define MDP_OV_PIPE_FORCE_DMA 0x4000
#endif
#ifndef MDSS_MDP_DUAL_PIPE
#define MDSS_MDP_DUAL_PIPE 0x200
#endif
#define FB_DEVICE_TEMPLATE "/dev/graphics/fb%u"
namespace overlay {
// fwd
class Overlay;
class OvFD;
/* helper function to open by using fbnum */
bool open(OvFD& fd, uint32_t fbnum, const char* const dev,
int flags = O_RDWR);
namespace utils {
struct Whf;
struct Dim;
inline uint32_t setBit(uint32_t x, uint32_t mask) {
return (x | mask);
}
inline uint32_t clrBit(uint32_t x, uint32_t mask) {
return (x & ~mask);
}
/* Utility class to help avoid copying instances by making the copy ctor
* and assignment operator private
*
* Usage:
* class SomeClass : utils::NoCopy {...};
*/
class NoCopy {
protected:
NoCopy(){}
~NoCopy() {}
private:
NoCopy(const NoCopy&);
const NoCopy& operator=(const NoCopy&);
};
bool isMdssRotator();
void normalizeCrop(uint32_t& xy, uint32_t& wh);
template <class Type>
void swapWidthHeight(Type& width, Type& height);
struct Dim {
Dim () : x(0), y(0),
w(0), h(0),
o(0) {}
Dim(uint32_t _x, uint32_t _y, uint32_t _w, uint32_t _h) :
x(_x), y(_y),
w(_w), h(_h) {}
Dim(uint32_t _x, uint32_t _y, uint32_t _w, uint32_t _h, uint32_t _o) :
x(_x), y(_y),
w(_w), h(_h),
o(_o) {}
bool check(uint32_t _w, uint32_t _h) const {
return (x+w <= _w && y+h <= _h);
}
bool operator==(const Dim& d) const {
return d.x == x && d.y == y &&
d.w == w && d.h == h &&
d.o == o;
}
bool operator!=(const Dim& d) const {
return !operator==(d);
}
void dump() const;
uint32_t x;
uint32_t y;
uint32_t w;
uint32_t h;
uint32_t o;
};
// TODO have Whfz
struct Whf {
Whf() : w(0), h(0), format(0), size(0) {}
Whf(uint32_t wi, uint32_t he, uint32_t f) :
w(wi), h(he), format(f), size(0) {}
Whf(uint32_t wi, uint32_t he, uint32_t f, uint32_t s) :
w(wi), h(he), format(f), size(s) {}
// FIXME not comparing size at the moment
bool operator==(const Whf& whf) const {
return whf.w == w && whf.h == h &&
whf.format == format;
}
bool operator!=(const Whf& whf) const {
return !operator==(whf);
}
void dump() const;
uint32_t w;
uint32_t h;
uint32_t format;
uint32_t size;
};
enum { MAX_PATH_LEN = 256 };
enum { DEFAULT_PLANE_ALPHA = 0xFF };
/**
* Rotator flags: not to be confused with orientation flags.
* Usually, you want to open the rotator to make sure it is
* ready for business.
* */
enum eRotFlags {
ROT_FLAGS_NONE = 0,
//Use rotator for 0 rotation. It is used anyway for others.
ROT_0_ENABLED = 1 << 0,
//Enable rotator downscale optimization for hardware bugs not handled in
//driver. If downscale optimizatation is required,
//then rotator will be used even if its 0 rotation case.
ROT_DOWNSCALE_ENABLED = 1 << 1,
ROT_PREROTATED = 1 << 2,
};
enum eRotDownscale {
ROT_DS_NONE = 0,
ROT_DS_HALF = 1,
ROT_DS_FOURTH = 2,
ROT_DS_EIGHTH = 3,
};
/*
* Various mdp flags like PIPE SHARE, DEINTERLACE etc...
* kernel/common/linux/msm_mdp.h
* INTERLACE_MASK: hardware/qcom/display/libgralloc/badger/fb_priv.h
* */
enum eMdpFlags {
OV_MDP_FLAGS_NONE = 0,
OV_MDP_PIPE_SHARE = MDP_OV_PIPE_SHARE,
OV_MDP_PIPE_FORCE_DMA = MDP_OV_PIPE_FORCE_DMA,
OV_MDP_DEINTERLACE = MDP_DEINTERLACE,
OV_MDP_SECURE_OVERLAY_SESSION = MDP_SECURE_OVERLAY_SESSION,
OV_MDP_SECURE_DISPLAY_OVERLAY_SESSION = MDP_SECURE_DISPLAY_OVERLAY_SESSION,
OV_MDP_SOURCE_ROTATED_90 = MDP_SOURCE_ROTATED_90,
OV_MDP_BLEND_FG_PREMULT = MDP_BLEND_FG_PREMULT,
OV_MDP_FLIP_H = MDP_FLIP_LR,
OV_MDP_FLIP_V = MDP_FLIP_UD,
OV_MDSS_MDP_RIGHT_MIXER = MDSS_MDP_RIGHT_MIXER,
OV_MDP_PP_EN = MDP_OVERLAY_PP_CFG_EN,
OV_MDSS_MDP_BWC_EN = MDP_BWC_EN,
OV_MDSS_MDP_DUAL_PIPE = MDSS_MDP_DUAL_PIPE,
OV_MDP_SOLID_FILL = MDP_SOLID_FILL,
OV_MDP_SMP_FORCE_ALLOC = MDP_SMP_FORCE_ALLOC,
};
enum eZorder {
ZORDER_0 = 0,
ZORDER_1,
ZORDER_2,
ZORDER_3,
ZORDER_4,
ZORDER_5,
ZORDER_6,
Z_SYSTEM_ALLOC = 0xFFFF
};
enum eMdpPipeType {
OV_MDP_PIPE_RGB = 0,
OV_MDP_PIPE_VG,
OV_MDP_PIPE_DMA,
OV_MDP_PIPE_ANY, //Any
};
// Identify destination pipes
// TODO Names useless, replace with int and change all interfaces
enum eDest {
OV_P0 = 0,
OV_P1,
OV_P2,
OV_P3,
OV_P4,
OV_P5,
OV_P6,
OV_P7,
OV_P8,
OV_P9,
OV_INVALID,
OV_MAX = OV_INVALID,
};
/* Used when a buffer is split over 2 pipes and sent to display */
enum {
OV_LEFT_SPLIT = 0,
OV_RIGHT_SPLIT,
};
/* values for copybit_set_parameter(OVERLAY_TRANSFORM) */
enum eTransform {
/* No rot */
OVERLAY_TRANSFORM_0 = 0x0,
/* flip source image horizontally 0x1 */
OVERLAY_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H,
/* flip source image vertically 0x2 */
OVERLAY_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
/* rotate source image 180 degrees
* It is basically bit-or-ed H | V == 0x3 */
OVERLAY_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
/* rotate source image 90 degrees 0x4 */
OVERLAY_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
/* rotate source image 90 degrees and flip horizontally 0x5 */
OVERLAY_TRANSFORM_ROT_90_FLIP_H = HAL_TRANSFORM_ROT_90 |
HAL_TRANSFORM_FLIP_H,
/* rotate source image 90 degrees and flip vertically 0x6 */
OVERLAY_TRANSFORM_ROT_90_FLIP_V = HAL_TRANSFORM_ROT_90 |
HAL_TRANSFORM_FLIP_V,
/* rotate source image 270 degrees
* Basically 180 | 90 == 0x7 */
OVERLAY_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
/* rotate invalid like in Transform.h */
OVERLAY_TRANSFORM_INV = 0x80
};
enum eBlending {
OVERLAY_BLENDING_UNDEFINED = 0x0,
/* No blending */
OVERLAY_BLENDING_OPAQUE,
/* src.rgb + dst.rgb*(1-src_alpha) */
OVERLAY_BLENDING_PREMULT,
/* src.rgb * src_alpha + dst.rgb (1 - src_alpha) */
OVERLAY_BLENDING_COVERAGE,
};
// Used to consolidate pipe params
struct PipeArgs {
PipeArgs() : mdpFlags(OV_MDP_FLAGS_NONE),
zorder(Z_SYSTEM_ALLOC),
rotFlags(ROT_FLAGS_NONE),
planeAlpha(DEFAULT_PLANE_ALPHA),
blending(OVERLAY_BLENDING_COVERAGE){
}
PipeArgs(eMdpFlags f, Whf _whf,
eZorder z, eRotFlags r,
int pA = DEFAULT_PLANE_ALPHA, eBlending b = OVERLAY_BLENDING_COVERAGE) :
mdpFlags(f),
whf(_whf),
zorder(z),
rotFlags(r),
planeAlpha(pA),
blending(b){
}
eMdpFlags mdpFlags; // for mdp_overlay flags
Whf whf;
eZorder zorder; // stage number
eRotFlags rotFlags;
int planeAlpha;
eBlending blending;
};
// Cannot use HW_OVERLAY_MAGNIFICATION_LIMIT, since at the time
// of integration, HW_OVERLAY_MAGNIFICATION_LIMIT was a define
enum { HW_OV_MAGNIFICATION_LIMIT = 20,
HW_OV_MINIFICATION_LIMIT = 8
};
inline void setMdpFlags(eMdpFlags& f, eMdpFlags v) {
f = static_cast<eMdpFlags>(setBit(f, v));
}
inline void clearMdpFlags(eMdpFlags& f, eMdpFlags v) {
f = static_cast<eMdpFlags>(clrBit(f, v));
}
enum { FB0, FB1, FB2 };
struct ScreenInfo {
ScreenInfo() : mFBWidth(0),
mFBHeight(0),
mFBbpp(0),
mFBystride(0) {}
void dump(const char* const s) const;
uint32_t mFBWidth;
uint32_t mFBHeight;
uint32_t mFBbpp;
uint32_t mFBystride;
};
int getMdpFormat(int format);
int getMdpFormat(int format, int flags);
int getHALFormat(int mdpFormat);
void getDecimationFactor(const int& src_w, const int& src_h,
const int& dst_w, const int& dst_h, uint8_t& horzDeci,
uint8_t& vertDeci);
/* flip is upside down and such. V, H flip
* rotation is 90, 180 etc
* It returns MDP related enum/define that match rot+flip*/
int getMdpOrient(eTransform rotation);
const char* getFormatString(int format);
template <class T>
inline void memset0(T& t) { ::memset(&t, 0, sizeof(t)); }
template <class T> inline void swap ( T& a, T& b )
{
T c(a); a=b; b=c;
}
template<typename T> inline T max(T a, T b) { return (a > b) ? a : b; }
template<typename T> inline T min(T a, T b) { return (a < b) ? a : b; }
inline int alignup(int value, int a) {
//if align = 0, return the value. Else, do alignment.
return a ? ((((value - 1) / a) + 1) * a) : value;
}
inline int aligndown(int value, int a) {
//if align = 0, return the value. Else, do alignment.
return a ? ((value) & ~(a-1)) : value;
}
// FIXME that align should replace the upper one.
inline int align(int value, int a) {
//if align = 0, return the value. Else, do alignment.
return a ? ((value + (a-1)) & ~(a-1)) : value;
}
inline bool isYuv(uint32_t format) {
switch(format){
case MDP_Y_CBCR_H2V1:
case MDP_Y_CBCR_H2V2:
case MDP_Y_CRCB_H2V2:
case MDP_Y_CRCB_H1V1:
case MDP_Y_CRCB_H2V1:
case MDP_Y_CRCB_H2V2_TILE:
case MDP_Y_CBCR_H2V2_TILE:
case MDP_Y_CR_CB_H2V2:
case MDP_Y_CR_CB_GH2V2:
case MDP_Y_CBCR_H2V2_VENUS:
case MDP_Y_CRCB_H2V2_VENUS:
case MDP_YCBYCR_H2V1:
case MDP_YCRYCB_H2V1:
return true;
default:
return false;
}
return false;
}
inline bool isRgb(uint32_t format) {
switch(format) {
case MDP_RGBA_8888:
case MDP_BGRA_8888:
case MDP_RGBX_8888:
case MDP_RGB_565:
case MDP_RGBA_4444:
case MDP_RGBA_5551:
return true;
default:
return false;
}
return false;
}
inline const char* getFormatString(int format){
#define STR(f) #f;
static const char* formats[MDP_IMGTYPE_LIMIT + 1] = {0};
formats[MDP_RGB_565] = STR(MDP_RGB_565);
formats[MDP_RGBA_5551] = STR(MDP_RGBA_5551);
formats[MDP_RGBA_4444] = STR(MDP_RGBA_4444);
formats[MDP_XRGB_8888] = STR(MDP_XRGB_8888);
formats[MDP_Y_CBCR_H2V2] = STR(MDP_Y_CBCR_H2V2);
formats[MDP_Y_CBCR_H2V2_ADRENO] = STR(MDP_Y_CBCR_H2V2_ADRENO);
formats[MDP_ARGB_8888] = STR(MDP_ARGB_8888);
formats[MDP_RGB_888] = STR(MDP_RGB_888);
formats[MDP_Y_CRCB_H2V2] = STR(MDP_Y_CRCB_H2V2);
formats[MDP_YCBYCR_H2V1] = STR(MDP_YCBYCR_H2V1);
formats[MDP_YCRYCB_H2V1] = STR(MDP_YCRYCB_H2V1);
formats[MDP_CBYCRY_H2V1] = STR(MDP_CBYCRY_H2V1);
formats[MDP_Y_CRCB_H2V1] = STR(MDP_Y_CRCB_H2V1);
formats[MDP_Y_CBCR_H2V1] = STR(MDP_Y_CBCR_H2V1);
formats[MDP_Y_CRCB_H1V2] = STR(MDP_Y_CRCB_H1V2);
formats[MDP_Y_CBCR_H1V2] = STR(MDP_Y_CBCR_H1V2);
formats[MDP_RGBA_8888] = STR(MDP_RGBA_8888);
formats[MDP_BGRA_8888] = STR(MDP_BGRA_8888);
formats[MDP_RGBX_8888] = STR(MDP_RGBX_8888);
formats[MDP_Y_CRCB_H2V2_TILE] = STR(MDP_Y_CRCB_H2V2_TILE);
formats[MDP_Y_CBCR_H2V2_TILE] = STR(MDP_Y_CBCR_H2V2_TILE);
formats[MDP_Y_CR_CB_H2V2] = STR(MDP_Y_CR_CB_H2V2);
formats[MDP_Y_CR_CB_GH2V2] = STR(MDP_Y_CR_CB_GH2V2);
formats[MDP_Y_CB_CR_H2V2] = STR(MDP_Y_CB_CR_H2V2);
formats[MDP_Y_CRCB_H1V1] = STR(MDP_Y_CRCB_H1V1);
formats[MDP_Y_CBCR_H1V1] = STR(MDP_Y_CBCR_H1V1);
formats[MDP_YCRCB_H1V1] = STR(MDP_YCRCB_H1V1);
formats[MDP_YCBCR_H1V1] = STR(MDP_YCBCR_H1V1);
formats[MDP_BGR_565] = STR(MDP_BGR_565);
formats[MDP_BGR_888] = STR(MDP_BGR_888);
formats[MDP_Y_CBCR_H2V2_VENUS] = STR(MDP_Y_CBCR_H2V2_VENUS);
formats[MDP_Y_CRCB_H2V2_VENUS] = STR(MDP_Y_CRCB_H2V2_VENUS);
formats[MDP_BGRX_8888] = STR(MDP_BGRX_8888);
formats[MDP_RGBA_8888_TILE] = STR(MDP_RGBA_8888_TILE);
formats[MDP_ARGB_8888_TILE] = STR(MDP_ARGB_8888_TILE);
formats[MDP_ABGR_8888_TILE] = STR(MDP_ABGR_8888_TILE);
formats[MDP_BGRA_8888_TILE] = STR(MDP_BGRA_8888_TILE);
formats[MDP_RGBX_8888_TILE] = STR(MDP_RGBX_8888_TILE);
formats[MDP_XRGB_8888_TILE] = STR(MDP_XRGB_8888_TILE);
formats[MDP_XBGR_8888_TILE] = STR(MDP_XBGR_8888_TILE);
formats[MDP_BGRX_8888_TILE] = STR(MDP_BGRX_8888_TILE);
formats[MDP_RGB_565_TILE] = STR(MDP_RGB_565_TILE);
formats[MDP_IMGTYPE_LIMIT] = STR(MDP_IMGTYPE_LIMIT);
if(format < 0 || format >= MDP_IMGTYPE_LIMIT) {
ALOGE("%s wrong fmt %d", __FUNCTION__, format);
return "Unsupported format";
}
if(formats[format] == 0) {
ALOGE("%s: table missing format %d from header", __FUNCTION__, format);
return "";
}
return formats[format];
}
inline void Whf::dump() const {
ALOGE("== Dump WHF w=%d h=%d f=%d s=%d start/end ==",
w, h, format, size);
}
inline void Dim::dump() const {
ALOGE("== Dump Dim x=%d y=%d w=%d h=%d start/end ==", x, y, w, h);
}
template <class Type>
void swapWidthHeight(Type& width, Type& height) {
Type tmp = width;
width = height;
height = tmp;
}
inline void ScreenInfo::dump(const char* const s) const {
ALOGE("== Dump %s ScreenInfo w=%d h=%d"
" bpp=%d stride=%d start/end ==",
s, mFBWidth, mFBHeight, mFBbpp, mFBystride);
}
inline bool openDev(OvFD& fd, int fbnum,
const char* const devpath, int flags) {
return overlay::open(fd, fbnum, devpath, flags);
}
template <class T>
inline void even_ceil(T& value) {
if(value & 1)
value++;
}
template <class T>
inline void even_floor(T& value) {
if(value & 1)
value--;
}
/* Prerotation adjusts crop co-ordinates to the new transformed values within
* destination buffer. This is necessary only when the entire buffer is rotated
* irrespective of crop (A-family). If only the crop portion of the buffer is
* rotated into a destination buffer matching the size of crop, we don't need to
* use this helper (B-family).
* @Deprecated as of now, retained for the case where a full buffer needs
* transform and also as a reference.
*/
void preRotateSource(const eTransform& tr, Whf& whf, Dim& srcCrop);
void getDump(char *buf, size_t len, const char *prefix, const mdp_overlay& ov);
void getDump(char *buf, size_t len, const char *prefix, const msmfb_img& ov);
void getDump(char *buf, size_t len, const char *prefix, const mdp_rect& ov);
void getDump(char *buf, size_t len, const char *prefix,
const msmfb_overlay_data& ov);
void getDump(char *buf, size_t len, const char *prefix, const msmfb_data& ov);
void getDump(char *buf, size_t len, const char *prefix,
const msm_rotator_img_info& ov);
void getDump(char *buf, size_t len, const char *prefix,
const msm_rotator_data_info& ov);
} // namespace utils ends
//--------------------Class Res stuff (namespace overlay only) -----------
class Res {
public:
// /dev/graphics/fb%u
static const char* const fbPath;
// /dev/msm_rotator
static const char* const rotPath;
};
//--------------------Class OvFD stuff (namespace overlay only) -----------
/*
* Holds one FD
* Dtor will NOT close the underlying FD.
* That enables us to copy that object around
* */
class OvFD {
public:
/* Ctor */
explicit OvFD();
/* dtor will NOT close the underlying FD */
~OvFD();
/* Open fd using the path given by dev.
* return false in failure */
bool open(const char* const dev,
int flags = O_RDWR);
/* populate path */
void setPath(const char* const dev);
/* Close fd if we have a valid fd. */
bool close();
/* returns underlying fd.*/
int getFD() const;
/* returns true if fd is valid */
bool valid() const;
/* like operator= */
void copy(int fd);
/* dump the state of the instance */
void dump() const;
private:
/* helper enum for determine valid/invalid fd */
enum { INVAL = -1 };
/* actual os fd */
int mFD;
/* path, for debugging */
char mPath[utils::MAX_PATH_LEN];
};
//-------------------Inlines--------------------------
inline bool open(OvFD& fd, uint32_t fbnum, const char* const dev, int flags)
{
char dev_name[64] = {0};
snprintf(dev_name, sizeof(dev_name), dev, fbnum);
return fd.open(dev_name, flags);
}
inline OvFD::OvFD() : mFD (INVAL) {
mPath[0] = 0;
}
inline OvFD::~OvFD() {
//no op since copy() can be used to share fd, in 3d cases.
}
inline bool OvFD::open(const char* const dev, int flags)
{
mFD = ::open(dev, flags, 0);
if (mFD < 0) {
// FIXME errno, strerror in bionic?
ALOGE("Cant open device %s err=%d", dev, errno);
return false;
}
setPath(dev);
return true;
}
inline void OvFD::setPath(const char* const dev)
{
::strlcpy(mPath, dev, sizeof(mPath));
}
inline bool OvFD::close()
{
int ret = 0;
if(valid()) {
ret = ::close(mFD);
mFD = INVAL;
}
return (ret == 0);
}
inline bool OvFD::valid() const
{
return (mFD != INVAL);
}
inline int OvFD::getFD() const { return mFD; }
inline void OvFD::copy(int fd) {
mFD = fd;
}
inline void OvFD::dump() const
{
ALOGE("== Dump OvFD fd=%d path=%s start/end ==",
mFD, mPath);
}
//--------------- class OvFD stuff ends ---------------------
} // overlay
#endif // OVERLAY_UTILS_H

View File

@@ -1,280 +0,0 @@
/*
* Copyright (c) 2013 The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "overlay.h"
#include "overlayWriteback.h"
#include "mdpWrapper.h"
#define SIZE_1M 0x00100000
namespace overlay {
//=========== class WritebackMem ==============================================
bool WritebackMem::manageMem(uint32_t size, bool isSecure) {
if(mBuf.bufSz() == size) {
return true;
}
if(mBuf.valid()) {
if(!mBuf.close()) {
ALOGE("%s error closing mem", __func__);
return false;
}
}
return alloc(size, isSecure);
}
bool WritebackMem::alloc(uint32_t size, bool isSecure) {
if(!mBuf.open(NUM_BUFS, size, isSecure)){
ALOGE("%s: Failed to open", __func__);
mBuf.close();
return false;
}
OVASSERT(MAP_FAILED != mBuf.addr(), "MAP failed");
OVASSERT(mBuf.getFD() != -1, "getFd is -1");
mCurrOffsetIndex = 0;
for (uint32_t i = 0; i < NUM_BUFS; i++) {
mOffsets[i] = i * size;
}
return true;
}
bool WritebackMem::dealloc() {
bool ret = true;
if(mBuf.valid()) {
ret = mBuf.close();
}
return ret;
}
//=========== class Writeback =================================================
Writeback::Writeback() : mXres(0), mYres(0), mOpFmt(-1), mSecure(false) {
int fbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
if(!utils::openDev(mFd, fbNum, Res::fbPath, O_RDWR)) {
ALOGE("%s failed to init %s", __func__, Res::fbPath);
return;
}
startSession();
}
Writeback::~Writeback() {
stopSession();
if (!mFd.close()) {
ALOGE("%s error closing fd", __func__);
}
}
bool Writeback::startSession() {
if(!mdp_wrapper::wbInitStart(mFd.getFD())) {
ALOGE("%s failed", __func__);
return false;
}
return true;
}
bool Writeback::stopSession() {
if(mFd.valid()) {
if(!Overlay::displayCommit(mFd.getFD())) {
ALOGE("%s: displayCommit failed", __func__);
return false;
}
if(!mdp_wrapper::wbStopTerminate(mFd.getFD())) {
ALOGE("%s: wbStopTerminate failed", __func__);
return false;
}
} else {
ALOGE("%s Invalid fd", __func__);
return false;
}
return true;
}
bool Writeback::configureDpyInfo(int xres, int yres) {
if(mXres != xres || mYres != yres) {
fb_var_screeninfo vinfo;
memset(&vinfo, 0, sizeof(fb_var_screeninfo));
if(!mdp_wrapper::getVScreenInfo(mFd.getFD(), vinfo)) {
ALOGE("%s failed", __func__);
return false;
}
vinfo.xres = xres;
vinfo.yres = yres;
vinfo.xres_virtual = xres;
vinfo.yres_virtual = yres;
vinfo.xoffset = 0;
vinfo.yoffset = 0;
if(!mdp_wrapper::setVScreenInfo(mFd.getFD(), vinfo)) {
ALOGE("%s failed", __func__);
return false;
}
mXres = xres;
mYres = yres;
}
return true;
}
bool Writeback::configureMemory(uint32_t size) {
if(!mWbMem.manageMem(size, mSecure)) {
ALOGE("%s failed, memory failure", __func__);
return false;
}
return true;
}
bool Writeback::queueBuffer(int opFd, uint32_t opOffset) {
memset(&mFbData, 0, sizeof(struct msmfb_data));
//Queue
mFbData.offset = opOffset;
mFbData.memory_id = opFd;
mFbData.id = 0;
mFbData.flags = 0;
if(!mdp_wrapper::wbQueueBuffer(mFd.getFD(), mFbData)) {
ALOGE("%s: queuebuffer failed", __func__);
return false;
}
return true;
}
bool Writeback::dequeueBuffer() {
//Dequeue
mFbData.flags = MSMFB_WRITEBACK_DEQUEUE_BLOCKING;
if(!mdp_wrapper::wbDequeueBuffer(mFd.getFD(), mFbData)) {
ALOGE("%s: dequeuebuffer failed", __func__);
return false;
}
return true;
}
bool Writeback::writeSync(int opFd, uint32_t opOffset) {
if(!queueBuffer(opFd, opOffset)) {
return false;
}
if(!Overlay::displayCommit(mFd.getFD())) {
return false;
}
if(!dequeueBuffer()) {
return false;
}
return true;
}
bool Writeback::writeSync() {
mWbMem.useNextBuffer();
return writeSync(mWbMem.getDstFd(), mWbMem.getOffset());
}
bool Writeback::setOutputFormat(int mdpFormat) {
if(mdpFormat != mOpFmt) {
struct msmfb_metadata metadata;
memset(&metadata, 0 , sizeof(metadata));
metadata.op = metadata_op_wb_format;
metadata.data.mixer_cfg.writeback_format = mdpFormat;
if (ioctl(mFd.getFD(), MSMFB_METADATA_SET, &metadata) < 0) {
ALOGE("Error setting MDP Writeback format");
return false;
}
mOpFmt = mdpFormat;
}
return true;
}
int Writeback::getOutputFormat() {
if(mOpFmt < 0) {
struct msmfb_metadata metadata;
memset(&metadata, 0 , sizeof(metadata));
metadata.op = metadata_op_wb_format;
if (ioctl(mFd.getFD(), MSMFB_METADATA_GET, &metadata) < 0) {
ALOGE("Error retrieving MDP Writeback format");
return -1;
}
mOpFmt = metadata.data.mixer_cfg.writeback_format;
}
return mOpFmt;
}
bool Writeback::setSecure(bool isSecure) {
if(isSecure != mSecure) {
// Call IOCTL to set WB interface as secure
struct msmfb_metadata metadata;
memset(&metadata, 0 , sizeof(metadata));
metadata.op = metadata_op_wb_secure;
metadata.data.secure_en = isSecure;
if (ioctl(mFd.getFD(), MSMFB_METADATA_SET, &metadata) < 0) {
ALOGE("Error setting MDP WB secure");
return false;
}
mSecure = isSecure;
}
return true;
}
//static
Writeback *Writeback::getInstance() {
if(sWb == NULL) {
sWb = new Writeback();
}
sUsed = true;
return sWb;
}
void Writeback::configDone() {
if(sUsed == false && sWb) {
delete sWb;
sWb = NULL;
}
}
void Writeback::clear() {
sUsed = false;
if(sWb) {
delete sWb;
sWb = NULL;
}
}
bool Writeback::getDump(char *buf, size_t len) {
if(sWb) {
utils::getDump(buf, len, "WBData", sWb->mFbData);
char outputBufferInfo[256];
snprintf(outputBufferInfo, sizeof(outputBufferInfo),
"OutputBuffer xres=%d yres=%d format=%s\n\n",
sWb->getWidth(), sWb->getHeight(),
utils::getFormatString(sWb->getOutputFormat()));
strlcat(buf, outputBufferInfo, len);
return true;
}
return false;
}
Writeback *Writeback::sWb = 0;
bool Writeback::sUsed = false;
} //namespace overlay

View File

@@ -1,122 +0,0 @@
/*
* Copyright (c) 2013 The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OVERLAY_WRITEBACK_H
#define OVERLAY_WRITEBACK_H
#include "overlayMem.h"
namespace overlay {
class WritebackMgr;
class WritebackMem {
public:
explicit WritebackMem() : mCurrOffsetIndex(0) {
memset(&mOffsets, 0, sizeof(mOffsets));
}
~WritebackMem() { dealloc(); }
bool manageMem(uint32_t size, bool isSecure);
void useNextBuffer() {
mCurrOffsetIndex = (mCurrOffsetIndex + 1) % NUM_BUFS;
}
uint32_t getOffset() const { return mOffsets[mCurrOffsetIndex]; }
int getDstFd() const { return mBuf.getFD(); }
private:
bool alloc(uint32_t size, bool isSecure);
bool dealloc();
enum { NUM_BUFS = 2 };
OvMem mBuf;
uint32_t mOffsets[NUM_BUFS];
uint32_t mCurrOffsetIndex;
};
//Abstracts the WB2 interface of MDP
//Has modes to either manage memory or work with memory allocated elsewhere
class Writeback {
public:
~Writeback();
bool configureDpyInfo(int xres, int yres);
bool configureMemory(uint32_t size);
/* Blocking write. (queue, commit, dequeue)
* This class will do writeback memory management.
* This class will call display-commit on writeback mixer.
*/
bool writeSync();
/* Blocking write. (queue, commit, dequeue)
* Client must do writeback memory management.
* Client must not call display-commit on writeback mixer.
*/
bool writeSync(int opFd, uint32_t opOffset);
/* Async queue. (Does not write)
* Client must do writeback memory management.
* Client must call display-commit on their own.
* Client must use sync mechanism e.g sync pt.
*/
bool queueBuffer(int opFd, uint32_t opOffset);
uint32_t getOffset() const { return mWbMem.getOffset(); }
int getDstFd() const { return mWbMem.getDstFd(); }
int getWidth() const { return mXres; }
int getHeight() const { return mYres; }
/* Subject to GC if writeback isnt used for a drawing round.
* Get always if caching the value.
*/
int getFbFd() const { return mFd.getFD(); }
int getOutputFormat();
bool setOutputFormat(int mdpFormat);
bool setSecure(bool isSecure);
static Writeback* getInstance();
static void configBegin() { sUsed = false; }
static void configDone();
static void clear();
//Will take a dump of data structure only if there is an instance existing
//Returns true if dump is added to the input buffer, false otherwise
static bool getDump(char *buf, size_t len);
private:
explicit Writeback();
bool startSession();
bool stopSession();
//Actually block_until_write_done for the usage here.
bool dequeueBuffer();
OvFD mFd;
WritebackMem mWbMem;
struct msmfb_data mFbData;
int mXres;
int mYres;
int mOpFmt;
bool mSecure;
static bool sUsed;
static Writeback *sWb;
};
}
#endif

View File

@@ -1,124 +0,0 @@
/*
* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "overlayGenPipe.h"
#include "mdp_version.h"
namespace overlay {
GenericPipe::GenericPipe(const int& dpy) : mDpy(dpy),
mCtrl(new Ctrl(dpy)), mData(new Data(dpy)) {
}
GenericPipe::~GenericPipe() {
delete mCtrl;
delete mData;
}
void GenericPipe::setSource(const utils::PipeArgs& args) {
mCtrl->setSource(args);
}
void GenericPipe::setCrop(const overlay::utils::Dim& d) {
mCtrl->setCrop(d);
}
void GenericPipe::setColor(const uint32_t color) {
mCtrl->setColor(color);
}
void GenericPipe::setTransform(const utils::eTransform& orient) {
mCtrl->setTransform(orient);
}
void GenericPipe::setPosition(const utils::Dim& d) {
mCtrl->setPosition(d);
}
bool GenericPipe::setVisualParams(const MetaData_t &metadata)
{
return mCtrl->setVisualParams(metadata);
}
void GenericPipe::setPipeType(const utils::eMdpPipeType& pType) {
mCtrl->setPipeType(pType);
}
bool GenericPipe::commit() {
return mCtrl->commit();
}
bool GenericPipe::queueBuffer(int fd, uint32_t offset) {
int pipeId = mCtrl->getPipeId();
OVASSERT(-1 != pipeId, "Ctrl ID should not be -1");
// set pipe id from ctrl to data
mData->setPipeId(pipeId);
return mData->queueBuffer(fd, offset);
}
utils::Dim GenericPipe::getCrop() const
{
return mCtrl->getCrop();
}
uint8_t GenericPipe::getPriority() const {
return mCtrl->getPriority();
}
void GenericPipe::dump() const
{
ALOGE("== Dump Generic pipe start ==");
mCtrl->dump();
mData->dump();
ALOGE("== Dump Generic pipe end ==");
}
void GenericPipe::getDump(char *buf, size_t len) {
mCtrl->getDump(buf, len);
mData->getDump(buf, len);
}
int GenericPipe::getPipeId() {
return mCtrl->getPipeId();
}
bool GenericPipe::validateAndSet(GenericPipe* pipeArray[], const int& count,
const int& fbFd) {
Ctrl* ctrlArray[count];
memset(&ctrlArray, 0, sizeof(ctrlArray));
for(int i = 0; i < count; i++) {
ctrlArray[i] = pipeArray[i]->mCtrl;
}
return Ctrl::validateAndSet(ctrlArray, count, fbFd);
}
} //namespace overlay

View File

@@ -1,86 +0,0 @@
/*
* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OVERLAY_GENERIC_PIPE_H
#define OVERLAY_GENERIC_PIPE_H
#include "overlayUtils.h"
#include "overlayCtrlData.h"
namespace overlay {
class GenericPipe : utils::NoCopy {
public:
/* ctor */
explicit GenericPipe(const int& dpy);
/* dtor */
~GenericPipe();
/* Control APIs */
/* set source using whf, orient and wait flag */
void setSource(const utils::PipeArgs& args);
/* set crop a.k.a the region of interest */
void setCrop(const utils::Dim& d);
/* set color for mdp pipe */
void setColor(const uint32_t color);
/* set orientation*/
void setTransform(const utils::eTransform& param);
/* set mdp posision using dim */
void setPosition(const utils::Dim& dim);
/* set visual param */
bool setVisualParams(const MetaData_t &metadata);
/* set pipe type RGB/DMA/VG */
void setPipeType(const utils::eMdpPipeType& pType);
/* commit changes to the overlay "set"*/
bool commit();
/* Data APIs */
/* queue buffer to the overlay */
bool queueBuffer(int fd, uint32_t offset);
/* return cached startup args */
const utils::PipeArgs& getArgs() const;
/* retrieve cached crop data */
utils::Dim getCrop() const;
/* return pipe priority */
uint8_t getPriority() const;
/* dump the state of the object */
void dump() const;
/* Return the dump in the specified buffer */
void getDump(char *buf, size_t len);
int getPipeId();
static bool validateAndSet(GenericPipe* pipeArray[], const int& count,
const int& fbFd);
private:
int mDpy;
Ctrl *mCtrl;
Data *mData;
};
} //namespace overlay
#endif // OVERLAY_GENERIC_PIPE_H

View File

@@ -9,12 +9,10 @@ LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdutils\"
LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
LOCAL_COPY_HEADERS_TO := $(common_header_export_path)
LOCAL_COPY_HEADERS := display_config.h mdp_version.h
LOCAL_SRC_FILES := profiler.cpp mdp_version.cpp \
idle_invalidator.cpp \
comptype.cpp qd_utils.cpp \
cb_utils.cpp display_config.cpp \
cb_swap_rect.cpp
LOCAL_COPY_HEADERS := display_config.h
LOCAL_SRC_FILES := profiler.cpp \
qd_utils.cpp \
display_config.cpp
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)

View File

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

View File

@@ -1,51 +0,0 @@
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* * modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyrigh
* notice, this list of conditions and the following disclaimer
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CB_SWAP_RECT
#define CB_SWAP_RECT
#include <stdint.h>
#include <utils/Singleton.h>
#include <cutils/log.h>
using namespace android;
namespace qdutils {
enum {
HWC_SKIP_HWC_COMPOSITION = 0x00040000,
};
class cb_swap_rect : public Singleton <cb_swap_rect>
{
bool swap_rect_feature_on;
public :
cb_swap_rect();
void setSwapRectFeature_on( bool value);
bool checkSwapRectFeature_on();
};
} // namespace qdutils
#endif

View File

@@ -1,133 +0,0 @@
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* * modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyrigh
* notice, this list of conditions and the following disclaimer
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "cb_utils.h"
#include "cb_swap_rect.h"
/* get union of two rects into 3rd rect */
void getUnion(hwc_rect_t& rect1,hwc_rect_t& rect2, hwc_rect_t& irect) {
irect.left = min(rect1.left, rect2.left);
irect.top = min(rect1.top, rect2.top);
irect.right = max(rect1.right, rect2.right);
irect.bottom = max(rect1.bottom, rect2.bottom);
}
int clear (copybit_device_t *copybit, private_handle_t* hnd, hwc_rect_t& rect)
{
int ret = 0;
copybit_rect_t clear_rect = {rect.left, rect.top,rect.right,rect.bottom};
copybit_image_t buf;
buf.w = ALIGN(getWidth(hnd),32);
buf.h = getHeight(hnd);
buf.format = hnd->format;
buf.base = (void *)hnd->base;
buf.handle = (native_handle_t *)hnd;
ret = copybit->clear(copybit, &buf, &clear_rect);
return ret;
}
using namespace android;
using namespace qhwc;
namespace qdutils {
int CBUtils::uiClearRegion(hwc_display_contents_1_t* list,
int version, LayerProp *layerProp, hwc_rect_t dirtyRect,
copybit_device_t *copybit, private_handle_t *renderBuffer) {
size_t last = list->numHwLayers - 1;
hwc_rect_t fbFrame = list->hwLayers[last].displayFrame;
Rect fbFrameRect(fbFrame.left,fbFrame.top,fbFrame.right,fbFrame.bottom);
Region wormholeRegion(fbFrameRect);
if ((dirtyRect.right - dirtyRect.left > 0) &&
(dirtyRect.bottom - dirtyRect.top > 0)) {
#ifdef QCOM_BSP
Rect tmpRect(dirtyRect.left,dirtyRect.top,dirtyRect.right,
dirtyRect.bottom);
Region tmpRegion(tmpRect);
wormholeRegion = wormholeRegion.intersect(tmpRegion);
#endif
}
if(cb_swap_rect::getInstance().checkSwapRectFeature_on() == true){
wormholeRegion.set(0,0);
for(size_t i = 0 ; i < last; i++) {
if(((list->hwLayers[i].blending == HWC_BLENDING_NONE) &&
(list->hwLayers[i].planeAlpha == 0xFF)) ||
!(layerProp[i].mFlags & HWC_COPYBIT) ||
(list->hwLayers[i].flags & HWC_SKIP_HWC_COMPOSITION))
continue ;
hwc_rect_t displayFrame = list->hwLayers[i].displayFrame;
Rect tmpRect(displayFrame.left,displayFrame.top,
displayFrame.right,displayFrame.bottom);
wormholeRegion.set(tmpRect);
}
}else{
for (size_t i = 0 ; i < last; i++) {
// need to take care only in per pixel blending.
// Restrict calculation only for copybit layers.
if((list->hwLayers[i].blending != HWC_BLENDING_NONE) ||
(list->hwLayers[i].planeAlpha != 0xFF) ||
!(layerProp[i].mFlags & HWC_COPYBIT))
continue ;
hwc_rect_t displayFrame = list->hwLayers[i].displayFrame;
Rect tmpRect(displayFrame.left,displayFrame.top,displayFrame.right,
displayFrame.bottom);
Region tmpRegion(tmpRect);
wormholeRegion.subtractSelf(wormholeRegion.intersect(tmpRegion));
}
}
if(wormholeRegion.isEmpty()){
return 1;
}
//TO DO :- 1. remove union and call clear for each rect.
Region::const_iterator it = wormholeRegion.begin();
Region::const_iterator const end = wormholeRegion.end();
while (it != end) {
const Rect& r = *it++;
hwc_rect_t tmpWormRect = {r.left,r.top,r.right,r.bottom};
if (version == qdutils::MDP_V3_0_4 ||
version == qdutils::MDP_V3_0_5) {
int clear_w = tmpWormRect.right - tmpWormRect.left;
int clear_h = tmpWormRect.bottom - tmpWormRect.top;
//mdp can't handle solid fill for one line
//making solid fill as full in this case
//disable swap rect if presents
if ((clear_w == 1) || (clear_h ==1)) {
clear(copybit, renderBuffer, fbFrame);
return 0;
} else {
clear(copybit, renderBuffer, tmpWormRect);
}
} else {
clear(copybit, renderBuffer, tmpWormRect);
}
}
return 1;
}
}//namespace qdutils

View File

@@ -1,46 +0,0 @@
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* * modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyrigh
* notice, this list of conditions and the following disclaimer
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CB_UTIL_H
#define CB_UTIL_H
#include <ui/Region.h>
#include "hwc_utils.h"
#include "copybit.h"
using namespace qhwc;
namespace qdutils {
class CBUtils {
public:
static int uiClearRegion(hwc_display_contents_1_t* list,
int version, LayerProp *layerProp, hwc_rect_t dirtyIndex,
copybit_device_t *copybit, private_handle_t *renderBuffer);
};
}//namespace qdutils
#endif /* end of include guard: CB_UTIL_H*/

View File

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

View File

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

View File

@@ -280,172 +280,4 @@ int setPanelMode(int mode) {
return err;
}
//=============================================================================
// The functions/methods below run in the context of HWC and
// are called in response to binder calls from clients
Configs* Configs::getInstance() {
if(sConfigs == NULL) {
sConfigs = new Configs();
if(sConfigs->init() == false) {
ALOGE("%s(): Configs initialization failed", __FUNCTION__);
delete sConfigs;
sConfigs = NULL;
}
}
return sConfigs;
}
Configs::Configs() : mActiveConfig(0), mConfigsSupported(0) {}
bool Configs::init() {
DisplayAttributes dpyAttr;
if(not getCurrentMode(dpyAttr)) {
ALOGE("%s(): Mode switch is disabled", __FUNCTION__);
return false;
}
FILE *fHnd;
size_t len = PAGE_SIZE;
ssize_t read = 0;
uint32_t configCount = 0;
char sysfsPath[MAX_SYSFS_FILE_PATH];
memset(sysfsPath, '\0', sizeof(sysfsPath));
snprintf(sysfsPath , sizeof(sysfsPath),
"/sys/class/graphics/fb0/modes");
fHnd = fopen(sysfsPath, "r");
if (fHnd == NULL) {
ALOGE("%s(): Opening file %s failed with error %s", __FUNCTION__,
sysfsPath, strerror(errno));
return false;
}
memset(mModeStr, 0, sizeof(mModeStr));
while((configCount < CONFIGS_MAX) and
((read = getline(&mModeStr[configCount], &len, fHnd)) > 0)) {
//String is of form "U:1600x2560p-0". Documentation/fb/modedb.txt in the
//kernel has more info on the format.
char *xptr = strcasestr(mModeStr[configCount], ":");
char *yptr = strcasestr(mModeStr[configCount], "x");
if(xptr && yptr) {
mConfigs[configCount].xres = atoi(xptr + 1);
mConfigs[configCount].yres = atoi(yptr + 1);
ALOGI("%s(): Parsed Config %s", __FUNCTION__,
mModeStr[configCount]);
ALOGI("%s(): Config %u: %u x %u", __FUNCTION__, configCount,
mConfigs[configCount].xres, mConfigs[configCount].yres);
if(mConfigs[configCount].xres == dpyAttr.xres and
mConfigs[configCount].yres == dpyAttr.yres) {
mActiveConfig = configCount;
}
} else {
ALOGE("%s(): Tokenizing str %s failed", __FUNCTION__,
mModeStr[configCount]);
//Free memory allocated internally by getline()
for(uint32_t i = 0; i <= configCount; i++) {
free(mModeStr[i]);
}
fclose(fHnd);
return false;
}
configCount++;
}
fclose(fHnd);
if(configCount == 0) {
ALOGE("%s No configs found", __FUNCTION__);
return false;
}
mConfigsSupported = configCount;
return true;
}
bool Configs::getCurrentMode(DisplayAttributes& dpyAttr) {
bool ret = false;
FILE *fHnd = fopen("/sys/class/graphics/fb0/mode", "r");
if(fHnd) {
char *buffer = NULL; //getline will allocate
size_t len = PAGE_SIZE;
if(getline(&buffer, &len, fHnd) > 0) {
//String is of form "U:1600x2560p-0". Documentation/fb/modedb.txt in
//kernel has more info on the format.
char *xptr = strcasestr(buffer, ":");
char *yptr = strcasestr(buffer, "x");
if(xptr && yptr) {
dpyAttr.xres = atoi(xptr + 1);
dpyAttr.yres = atoi(yptr + 1);
ALOGI("%s(): Parsed Current Config Str %s", __FUNCTION__,
buffer);
ALOGI("%s(): Current Config: %u x %u", __FUNCTION__,
dpyAttr.xres, dpyAttr.yres);
ret = true;
}
}
if(buffer)
free(buffer);
fclose(fHnd);
}
return ret;
}
bool Configs::setActiveConfig(const uint32_t& index) {
if(index >= mConfigsSupported) {
ALOGE("%s(): Invalid Index %u", __FUNCTION__, index);
return false;
}
bool ret = true;
int fd = -1;
size_t len = PAGE_SIZE;
char sysfsPath[MAX_SYSFS_FILE_PATH];
memset(sysfsPath, '\0', sizeof(sysfsPath));
snprintf(sysfsPath , sizeof(sysfsPath),
"/sys/class/graphics/fb0/mode");
fd = open(sysfsPath, O_WRONLY);
if (fd < 0) {
ALOGE("%s(): Opening file %s failed", __FUNCTION__, sysfsPath);
return false;
}
ssize_t written = pwrite(fd, mModeStr[index], strlen(mModeStr[index]), 0);
if(written <= 0) {
ALOGE("%s(): Writing config %s to %s failed with error: %s",
__FUNCTION__, mModeStr[index], sysfsPath, strerror(errno));
close(fd);
return false;
}
ALOGI("%s(): Successfully set config %u", __FUNCTION__, index);
mActiveConfig = index;
MDPVersion::getInstance().updateSplitInfo();
close(fd);
return true;
}
Configs* Configs::sConfigs = NULL;
}; //namespace
// ----------------------------------------------------------------------------
// Screen refresh for native daemons linking dynamically to libqdutils
// ----------------------------------------------------------------------------
extern "C" int refreshScreen() {
int ret = 0;
ret = screenRefresh();
return ret;
}
// ----------------------------------------------------------------------------
// Native daemons needs to send enable partial update ack for PU to enable
// ----------------------------------------------------------------------------
extern "C" int setPartialUpdateState() {
int ret = 0;
ret = setPartialUpdate(IQService::ENABLE_PARTIAL_UPDATE);
return ret;
}
}// namespace

View File

@@ -28,7 +28,6 @@
*/
#include <gralloc_priv.h>
#include <qdMetaData.h>
#include <mdp_version.h>
#include <hardware/hwcomposer.h>
// This header is for clients to use to set/get global display configuration.

View File

@@ -1,149 +0,0 @@
/*
* Copyright (c) 2012, The Linux Foundation. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "idle_invalidator.h"
#include <unistd.h>
#include <poll.h>
#include <string.h>
#include <fcntl.h>
#include <cutils/properties.h>
#define II_DEBUG 0
#define IDLE_NOTIFY_PATH "/sys/devices/virtual/graphics/fb0/idle_notify"
#define IDLE_TIME_PATH "/sys/devices/virtual/graphics/fb0/idle_time"
static const char *threadName = "IdleInvalidator";
InvalidatorHandler IdleInvalidator::mHandler = NULL;
android::sp<IdleInvalidator> IdleInvalidator::sInstance(0);
IdleInvalidator::IdleInvalidator(): Thread(false), mHwcContext(0),
mTimeoutEventFd(-1) {
ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
}
IdleInvalidator::~IdleInvalidator() {
if(mTimeoutEventFd >= 0) {
close(mTimeoutEventFd);
}
}
int IdleInvalidator::init(InvalidatorHandler reg_handler, void* user_data) {
mHandler = reg_handler;
mHwcContext = user_data;
// Open a sysfs node to receive the timeout notification from driver.
mTimeoutEventFd = open(IDLE_NOTIFY_PATH, O_RDONLY);
if (mTimeoutEventFd < 0) {
ALOGE ("%s:not able to open %s node %s",
__FUNCTION__, IDLE_NOTIFY_PATH, strerror(errno));
return -1;
}
int defaultIdleTime = 70; //ms
char property[PROPERTY_VALUE_MAX] = {0};
if((property_get("debug.mdpcomp.idletime", property, NULL) > 0)) {
defaultIdleTime = atoi(property);
}
if(not setIdleTimeout(defaultIdleTime)) {
close(mTimeoutEventFd);
mTimeoutEventFd = -1;
return -1;
}
//Triggers the threadLoop to run, if not already running.
run(threadName, android::PRIORITY_LOWEST);
return 0;
}
bool IdleInvalidator::setIdleTimeout(const uint32_t& timeout) {
ALOGD_IF(II_DEBUG, "IdleInvalidator::%s timeout %d",
__FUNCTION__, timeout);
// Open a sysfs node to send the timeout value to driver.
int fd = open(IDLE_TIME_PATH, O_WRONLY);
if (fd < 0) {
ALOGE ("%s:Unable to open %s node %s",
__FUNCTION__, IDLE_TIME_PATH, strerror(errno));
return false;
}
char strSleepTime[64];
snprintf(strSleepTime, sizeof(strSleepTime), "%d", timeout);
// Notify driver about the timeout value
ssize_t len = pwrite(fd, strSleepTime, strlen(strSleepTime), 0);
if(len < -1) {
ALOGE ("%s:Unable to write into %s node %s",
__FUNCTION__, IDLE_TIME_PATH, strerror(errno));
close(fd);
return false;
}
close(fd);
return true;
}
bool IdleInvalidator::threadLoop() {
ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
struct pollfd pFd;
pFd.fd = mTimeoutEventFd;
if (pFd.fd >= 0)
pFd.events = POLLPRI | POLLERR;
// Poll for an timeout event from driver
int err = poll(&pFd, 1, -1);
if(err > 0) {
if (pFd.revents & POLLPRI) {
char data[64];
// Consume the node by reading it
ssize_t len = pread(pFd.fd, data, 64, 0);
ALOGD_IF(II_DEBUG, "IdleInvalidator::%s Idle Timeout fired len %zd",
__FUNCTION__, len);
mHandler((void*)mHwcContext);
}
}
return true;
}
int IdleInvalidator::readyToRun() {
ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
return 0; /*NO_ERROR*/
}
void IdleInvalidator::onFirstRef() {
ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
}
IdleInvalidator *IdleInvalidator::getInstance() {
ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
if(sInstance.get() == NULL)
sInstance = new IdleInvalidator();
return sInstance.get();
}

View File

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

View File

@@ -1,534 +0,0 @@
/*
* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cutils/log.h>
#include <linux/msm_mdp.h>
#include "mdp_version.h"
#include "qd_utils.h"
#define DEBUG 0
ANDROID_SINGLETON_STATIC_INSTANCE(qdutils::MDPVersion);
namespace qdutils {
#define TOKEN_PARAMS_DELIM "="
// chip variants have same major number and minor numbers usually vary
// for e.g., MDSS_MDP_HW_REV_101 is 0x10010000
// 1001 - major number
// 0000 - minor number
// 8x26 v1 minor number is 0000
// v2 minor number is 0001 etc..
#ifndef MDSS_MDP_HW_REV_100
#define MDSS_MDP_HW_REV_100 0x10000000 //8974 v1
#endif
#ifndef MDSS_MDP_HW_REV_101
#define MDSS_MDP_HW_REV_101 0x10010000 //8x26
#endif
#ifndef MDSS_MDP_HW_REV_102
#define MDSS_MDP_HW_REV_102 0x10020000 //8974 v2
#endif
#ifndef MDSS_MDP_HW_REV_103
#define MDSS_MDP_HW_REV_103 0x10030000 //8084
#endif
#ifndef MDSS_MDP_HW_REV_104
#define MDSS_MDP_HW_REV_104 0x10040000 //Unused
#endif
#ifndef MDSS_MDP_HW_REV_105
#define MDSS_MDP_HW_REV_105 0x10050000 //8994
#endif
#ifndef MDSS_MDP_HW_REV_106
#define MDSS_MDP_HW_REV_106 0x10060000 //8x16
#endif
#ifndef MDSS_MDP_HW_REV_107
#define MDSS_MDP_HW_REV_107 0x10070000 //Unused
#endif
#ifndef MDSS_MDP_HW_REV_108
#define MDSS_MDP_HW_REV_108 0x10080000 //8x39 & 8x36
#endif
#ifndef MDSS_MDP_HW_REV_109
#define MDSS_MDP_HW_REV_109 0x10090000 //8994 v2
#endif
#ifndef MDSS_MDP_HW_REV_110
#define MDSS_MDP_HW_REV_110 0x100a0000 //8992
#endif
#ifndef MDSS_MDP_HW_REV_111
#define MDSS_MDP_HW_REV_111 0x100b0000 //Unused or Next version
#endif
#ifndef MDSS_MDP_HW_REV_112
#define MDSS_MDP_HW_REV_112 0x100c0000 // 8x52
#endif
#ifndef MDSS_MDP_HW_REV_113
#define MDSS_MDP_HW_REV_113 0x100d0000 //Unused Next version
#endif
#ifndef MDSS_MDP_HW_REV_200
#define MDSS_MDP_HW_REV_200 0x20000000 //8092
#endif
#ifndef MDSS_MDP_HW_REV_206
#define MDSS_MDP_HW_REV_206 0x20060000 //Future
#endif
MDPVersion::MDPVersion()
{
mMDPVersion = MDSS_V5;
mMdpRev = 0;
mRGBPipes = 0;
mVGPipes = 0;
mDMAPipes = 0;
mCursorPipes = 0;
mFeatures = 0;
mMDPUpscale = 1;
mMDPDownscale = 1;
mMacroTileEnabled = false;
mLowBw = 0;
mHighBw = 0;
mSourceSplit = false;
mSourceSplitAlways = false;
mRGBHasNoScalar = false;
mRotDownscale = false;
mBlendStages = 4; //min no. of stages supported by MDP.
// this is the default limit of mixer unless driver reports it.
// For resolutions beyond this, we use dual mixer/ping pong split.
mMaxMixerWidth = 2048;
// Default width of MDSS SSPP. For layer resolutions beyond this, we drive
// using two SSPP's.
mMaxPipeWidth = 2048;
mMaxCursorSize = 0;
updatePanelInfo();
if(!updateSysFsInfo()) {
ALOGE("Unable to read display sysfs node");
}
if (mMdpRev == MDP_V3_0_4){
mMDPVersion = MDP_V3_0_4;
}
else if (mMdpRev == MDP_V3_0_5){
mMDPVersion = MDP_V3_0_5;
}
mHasOverlay = false;
if((mMDPVersion >= MDP_V4_0) ||
(mMDPVersion == MDP_V_UNKNOWN) ||
(mMDPVersion == MDP_V3_0_4) ||
(mMDPVersion == MDP_V3_0_5))
mHasOverlay = true;
if(!updateSplitInfo()) {
ALOGE("Unable to read display split node");
}
}
MDPVersion::~MDPVersion() {
close(mFd);
}
int MDPVersion::tokenizeParams(char *inputParams, const char *delim,
char* tokenStr[], int *idx) {
char *tmp_token = NULL;
char *temp_ptr;
int index = 0;
if (!inputParams) {
return -1;
}
tmp_token = strtok_r(inputParams, delim, &temp_ptr);
while (tmp_token != NULL) {
tokenStr[index++] = tmp_token;
tmp_token = strtok_r(NULL, " ", &temp_ptr);
}
*idx = index;
return 0;
}
// This function reads the sysfs node to read the primary panel type
// and updates information accordingly
void MDPVersion::updatePanelInfo() {
FILE *displayDeviceFP = NULL;
FILE *panelInfoNodeFP = NULL;
char fbType[MAX_FRAME_BUFFER_NAME_SIZE];
const char *strCmdPanel = "mipi dsi cmd panel";
const char *strVideoPanel = "mipi dsi video panel";
const char *strLVDSPanel = "lvds panel";
const char *strEDPPanel = "edp panel";
displayDeviceFP = fopen("/sys/class/graphics/fb0/msm_fb_type", "r");
if(displayDeviceFP){
fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE,
displayDeviceFP);
if(strncmp(fbType, strCmdPanel, strlen(strCmdPanel)) == 0) {
mPanelInfo.mType = MIPI_CMD_PANEL;
}
else if(strncmp(fbType, strVideoPanel, strlen(strVideoPanel)) == 0) {
mPanelInfo.mType = MIPI_VIDEO_PANEL;
}
else if(strncmp(fbType, strLVDSPanel, strlen(strLVDSPanel)) == 0) {
mPanelInfo.mType = LVDS_PANEL;
}
else if(strncmp(fbType, strEDPPanel, strlen(strEDPPanel)) == 0) {
mPanelInfo.mType = EDP_PANEL;
}
fclose(displayDeviceFP);
} else {
ALOGE("Unable to read Primary Panel Information");
}
panelInfoNodeFP = fopen("/sys/class/graphics/fb0/msm_fb_panel_info", "r");
if(panelInfoNodeFP){
size_t len = PAGE_SIZE;
ssize_t read;
char *readLine = (char *) malloc (len);
char property[PROPERTY_VALUE_MAX];
while((read = getline((char **)&readLine, &len,
panelInfoNodeFP)) != -1) {
int token_ct=0;
char *tokens[10];
memset(tokens, 0, sizeof(tokens));
if(!tokenizeParams(readLine, TOKEN_PARAMS_DELIM, tokens,
&token_ct)) {
if(!strncmp(tokens[0], "pu_en", strlen("pu_en"))) {
mPanelInfo.mPartialUpdateEnable = atoi(tokens[1]);
ALOGI("PartialUpdate status: %s",
mPanelInfo.mPartialUpdateEnable? "Enabled" :
"Disabled");
}
if(!strncmp(tokens[0], "xstart", strlen("xstart"))) {
mPanelInfo.mLeftAlign = atoi(tokens[1]);
ALOGI("Left Align: %d", mPanelInfo.mLeftAlign);
}
if(!strncmp(tokens[0], "walign", strlen("walign"))) {
mPanelInfo.mWidthAlign = atoi(tokens[1]);
ALOGI("Width Align: %d", mPanelInfo.mWidthAlign);
}
if(!strncmp(tokens[0], "ystart", strlen("ystart"))) {
mPanelInfo.mTopAlign = atoi(tokens[1]);
ALOGI("Top Align: %d", mPanelInfo.mTopAlign);
}
if(!strncmp(tokens[0], "halign", strlen("halign"))) {
mPanelInfo.mHeightAlign = atoi(tokens[1]);
ALOGI("Height Align: %d", mPanelInfo.mHeightAlign);
}
if(!strncmp(tokens[0], "min_w", strlen("min_w"))) {
mPanelInfo.mMinROIWidth = atoi(tokens[1]);
ALOGI("Min ROI Width: %d", mPanelInfo.mMinROIWidth);
}
if(!strncmp(tokens[0], "min_h", strlen("min_h"))) {
mPanelInfo.mMinROIHeight = atoi(tokens[1]);
ALOGI("Min ROI Height: %d", mPanelInfo.mMinROIHeight);
}
if(!strncmp(tokens[0], "roi_merge", strlen("roi_merge"))) {
mPanelInfo.mNeedsROIMerge = atoi(tokens[1]);
ALOGI("Needs ROI Merge: %d", mPanelInfo.mNeedsROIMerge);
}
if(!strncmp(tokens[0], "dyn_fps_en", strlen("dyn_fps_en"))) {
mPanelInfo.mDynFpsSupported = atoi(tokens[1]);
ALOGI("Dynamic Fps: %s", mPanelInfo.mDynFpsSupported ?
"Enabled" : "Disabled");
}
if(!strncmp(tokens[0], "min_fps", strlen("min_fps"))) {
mPanelInfo.mMinFps = atoi(tokens[1]);
ALOGI("Min Panel fps: %d", mPanelInfo.mMinFps);
}
if(!strncmp(tokens[0], "max_fps", strlen("max_fps"))) {
mPanelInfo.mMaxFps = atoi(tokens[1]);
ALOGI("Max Panel fps: %d", mPanelInfo.mMaxFps);
}
}
}
if((property_get("persist.hwc.pubypass", property, 0) > 0) &&
(!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
(!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
mPanelInfo.mPartialUpdateEnable = 0;
ALOGI("PartialUpdate disabled by property");
}
fclose(panelInfoNodeFP);
free(readLine);
} else {
ALOGE("Failed to open msm_fb_panel_info node");
}
}
// This function reads the sysfs node to read MDP capabilities
// and parses and updates information accordingly.
bool MDPVersion::updateSysFsInfo() {
FILE *sysfsFd;
size_t len = PAGE_SIZE;
ssize_t read;
char *line = NULL;
char sysfsPath[255];
memset(sysfsPath, 0, sizeof(sysfsPath));
snprintf(sysfsPath , sizeof(sysfsPath),
"/sys/class/graphics/fb0/mdp/caps");
char property[PROPERTY_VALUE_MAX];
bool enableMacroTile = false;
if((property_get("persist.hwc.macro_tile_enable", property, NULL) > 0) &&
(!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
(!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
enableMacroTile = true;
}
sysfsFd = fopen(sysfsPath, "rb");
if (sysfsFd == NULL) {
ALOGE("%s: sysFsFile file '%s' not found",
__FUNCTION__, sysfsPath);
return false;
} else {
line = (char *) malloc(len);
while((read = getline(&line, &len, sysfsFd)) != -1) {
int index=0;
char *tokens[10];
memset(tokens, 0, sizeof(tokens));
// parse the line and update information accordingly
if(!tokenizeParams(line, TOKEN_PARAMS_DELIM, tokens, &index)) {
if(!strncmp(tokens[0], "hw_rev", strlen("hw_rev"))) {
mMdpRev = atoi(tokens[1]);
}
else if(!strncmp(tokens[0], "rgb_pipes", strlen("rgb_pipes"))) {
mRGBPipes = (uint8_t)atoi(tokens[1]);
}
else if(!strncmp(tokens[0], "vig_pipes", strlen("vig_pipes"))) {
mVGPipes = (uint8_t)atoi(tokens[1]);
}
else if(!strncmp(tokens[0], "dma_pipes", strlen("dma_pipes"))) {
mDMAPipes = (uint8_t)atoi(tokens[1]);
}
else if(!strncmp(tokens[0], "cursor_pipes",
strlen("cursor_pipes"))) {
mCursorPipes = (uint8_t)atoi(tokens[1]);
}
else if(!strncmp(tokens[0], "blending_stages",
strlen("blending_stages"))) {
mBlendStages = (uint8_t)atoi(tokens[1]);
}
else if(!strncmp(tokens[0], "max_downscale_ratio",
strlen("max_downscale_ratio"))) {
mMDPDownscale = atoi(tokens[1]);
}
else if(!strncmp(tokens[0], "max_upscale_ratio",
strlen("max_upscale_ratio"))) {
mMDPUpscale = atoi(tokens[1]);
} else if(!strncmp(tokens[0], "max_bandwidth_low",
strlen("max_bandwidth_low"))) {
mLowBw = atol(tokens[1]);
} else if(!strncmp(tokens[0], "max_bandwidth_high",
strlen("max_bandwidth_high"))) {
mHighBw = atol(tokens[1]);
} else if(!strncmp(tokens[0], "max_mixer_width",
strlen("max_mixer_width"))) {
mMaxMixerWidth = atoi(tokens[1]);
} else if(!strncmp(tokens[0], "max_pipe_width",
strlen("max_pipe_width"))) {
mMaxPipeWidth = atoi(tokens[1]);
} else if(!strncmp(tokens[0], "features", strlen("features"))) {
for(int i=1; i<index;i++) {
if(!strncmp(tokens[i], "bwc", strlen("bwc"))) {
mFeatures |= MDP_BWC_EN;
} else if(!strncmp(tokens[i], "decimation",
strlen("decimation"))) {
mFeatures |= MDP_DECIMATION_EN;
} else if(!strncmp(tokens[i], "tile_format",
strlen("tile_format"))) {
if(enableMacroTile)
mMacroTileEnabled = true;
} else if(!strncmp(tokens[i], "src_split",
strlen("src_split"))) {
mSourceSplit = true;
} else if(!strncmp(tokens[i], "non_scalar_rgb",
strlen("non_scalar_rgb"))) {
mRGBHasNoScalar = true;
} else if(!strncmp(tokens[i], "rotator_downscale",
strlen("rotator_downscale"))) {
mRotDownscale = true;
}
}
} else if(!strncmp(tokens[0], "max_cursor_size",
strlen("max_cursor_size"))) {
mMaxCursorSize = atoi(tokens[1]);
}
}
}
free(line);
fclose(sysfsFd);
}
if(mMDPVersion >= qdutils::MDP_V4_2 and mMDPVersion < qdutils::MDSS_V5) {
mRotDownscale = true;
}
if(mSourceSplit) {
memset(sysfsPath, 0, sizeof(sysfsPath));
snprintf(sysfsPath , sizeof(sysfsPath),
"/sys/class/graphics/fb0/msm_fb_src_split_info");
sysfsFd = fopen(sysfsPath, "rb");
if (sysfsFd == NULL) {
ALOGE("%s: Opening file %s failed with error %s", __FUNCTION__,
sysfsPath, strerror(errno));
return false;
} else {
line = (char *) malloc(len);
if((read = getline(&line, &len, sysfsFd)) != -1) {
if(!strncmp(line, "src_split_always",
strlen("src_split_always"))) {
mSourceSplitAlways = true;
}
}
free(line);
fclose(sysfsFd);
}
}
ALOGD_IF(DEBUG, "%s: mMDPVersion: %d mMdpRev: %x mRGBPipes:%d,"
"mVGPipes:%d mCursorPipes:%d", __FUNCTION__, mMDPVersion,
mMdpRev, mRGBPipes, mVGPipes, mCursorPipes);
ALOGD_IF(DEBUG, "%s:mDMAPipes:%d \t mMDPDownscale:%d, mFeatures:%d",
__FUNCTION__, mDMAPipes, mMDPDownscale, mFeatures);
ALOGD_IF(DEBUG, "%s:mLowBw: %lu mHighBw: %lu", __FUNCTION__, mLowBw,
mHighBw);
return true;
}
// This function reads the sysfs node to read MDP capabilities
// and parses and updates information accordingly.
bool MDPVersion::updateSplitInfo() {
if(mMDPVersion >= MDSS_V5) {
char split[64] = {0};
FILE* fp = fopen("/sys/class/graphics/fb0/msm_fb_split", "r");
if(fp){
//Format "left right" space as delimiter
if(fread(split, sizeof(char), 64, fp)) {
split[sizeof(split) - 1] = '\0';
mSplit.mLeft = atoi(split);
ALOGI_IF(mSplit.mLeft, "Left Split=%d", mSplit.mLeft);
char *rght = strpbrk(split, " ");
if(rght)
mSplit.mRight = atoi(rght + 1);
ALOGI_IF(mSplit.mRight, "Right Split=%d", mSplit.mRight);
}
} else {
ALOGE("Failed to open mdss_fb_split node");
return false;
}
if(fp)
fclose(fp);
}
return true;
}
bool MDPVersion::hasMinCropWidthLimitation() const {
return mMdpRev <= MDSS_MDP_HW_REV_102;
}
bool MDPVersion::supportsDecimation() {
return mFeatures & MDP_DECIMATION_EN;
}
uint32_t MDPVersion::getMaxMDPDownscale() {
return mMDPDownscale;
}
uint32_t MDPVersion::getMaxMDPUpscale() {
return mMDPUpscale;
}
bool MDPVersion::supportsBWC() {
// BWC - Bandwidth Compression
return (mFeatures & MDP_BWC_EN);
}
bool MDPVersion::supportsMacroTile() {
// MACRO TILE support
return mMacroTileEnabled;
}
bool MDPVersion::isSrcSplit() const {
return mSourceSplit;
}
bool MDPVersion::isSrcSplitAlways() const {
return mSourceSplitAlways;
}
bool MDPVersion::isRGBScalarSupported() const {
return (!mRGBHasNoScalar);
}
bool MDPVersion::is8x26() {
return (mMdpRev >= MDSS_MDP_HW_REV_101 and
mMdpRev < MDSS_MDP_HW_REV_102);
}
bool MDPVersion::is8x74v2() {
return (mMdpRev >= MDSS_MDP_HW_REV_102 and
mMdpRev < MDSS_MDP_HW_REV_103);
}
bool MDPVersion::is8084() {
return (mMdpRev >= MDSS_MDP_HW_REV_103 and
mMdpRev < MDSS_MDP_HW_REV_104);
}
bool MDPVersion::is8092() {
return (mMdpRev >= MDSS_MDP_HW_REV_200 and
mMdpRev < MDSS_MDP_HW_REV_206);
}
bool MDPVersion::is8994() {
return ((mMdpRev >= MDSS_MDP_HW_REV_105 and
mMdpRev < MDSS_MDP_HW_REV_106) or
(mMdpRev >= MDSS_MDP_HW_REV_109 and
mMdpRev < MDSS_MDP_HW_REV_110));
}
bool MDPVersion::is8x16() {
return (mMdpRev >= MDSS_MDP_HW_REV_106 and
mMdpRev < MDSS_MDP_HW_REV_107);
}
bool MDPVersion::is8x39() {
return (mMdpRev >= MDSS_MDP_HW_REV_108 and
mMdpRev < MDSS_MDP_HW_REV_109);
}
bool MDPVersion::is8992() {
return ((mMdpRev >= MDSS_MDP_HW_REV_110 and
mMdpRev < MDSS_MDP_HW_REV_200));
}
bool MDPVersion::is8x52() {
return (mMdpRev >= MDSS_MDP_HW_REV_112 and
mMdpRev < MDSS_MDP_HW_REV_113);
}
}; //namespace qdutils

View File

@@ -1,192 +0,0 @@
/*
* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef INCLUDE_LIBQCOMUTILS_MDPVER
#define INCLUDE_LIBQCOMUTILS_MDPVER
#include <stdint.h>
#include <utils/Singleton.h>
#include <cutils/properties.h>
/* This class gets the MSM type from the soc info
*/
using namespace android;
namespace qdutils {
// These panel definitions are available at mdss_mdp.h which is internal header
// file and is not available at <linux/mdss_mdp.h>.
// ToDo: once it is available at linux/mdss_mdp.h, these below definitions can
// be removed.
enum mdp_version {
MDP_V_UNKNOWN = 0,
MDP_V2_2 = 220,
MDP_V3_0 = 300,
MDP_V3_0_3 = 303,
MDP_V3_0_4 = 304,
MDP_V3_0_5 = 305,
MDP_V3_1 = 310,
MDP_V4_0 = 400,
MDP_V4_1 = 410,
MDP_V4_2 = 420,
MDP_V4_3 = 430,
MDP_V4_4 = 440,
MDSS_V5 = 500,
};
#define NO_PANEL '0'
#define MDDI_PANEL '1'
#define EBI2_PANEL '2'
#define LCDC_PANEL '3'
#define EXT_MDDI_PANEL '4'
#define TV_PANEL '5'
#define DTV_PANEL '7'
#define MIPI_VIDEO_PANEL '8'
#define MIPI_CMD_PANEL '9'
#define WRITEBACK_PANEL 'a'
#define LVDS_PANEL 'b'
#define EDP_PANEL 'c'
class MDPVersion;
struct Split {
int mLeft;
int mRight;
Split() : mLeft(0), mRight(0){}
int left() { return mLeft; }
int right() { return mRight; }
friend class MDPVersion;
};
struct PanelInfo {
char mType; // Smart or Dumb
int mPartialUpdateEnable; // Partial update feature
int mLeftAlign; // ROI left alignment restriction
int mWidthAlign; // ROI width alignment restriction
int mTopAlign; // ROI top alignment restriction
int mHeightAlign; // ROI height alignment restriction
int mMinROIWidth; // Min width needed for ROI
int mMinROIHeight; // Min height needed for ROI
bool mNeedsROIMerge; // Merge ROI's of both the DSI's
bool mDynFpsSupported; // Panel Supports dyn fps
uint32_t mMinFps; // Min fps supported by panel
uint32_t mMaxFps; // Max fps supported by panel
PanelInfo() : mType(NO_PANEL), mPartialUpdateEnable(0),
mLeftAlign(0), mWidthAlign(0), mTopAlign(0), mHeightAlign(0),
mMinROIWidth(0), mMinROIHeight(0), mNeedsROIMerge(false),
mDynFpsSupported(0), mMinFps(0), mMaxFps(0) {}
friend class MDPVersion;
};
class MDPVersion : public Singleton <MDPVersion>
{
public:
MDPVersion();
~MDPVersion();
int getMDPVersion() {return mMDPVersion;}
char getPanelType() {return mPanelInfo.mType;}
bool hasOverlay() {return mHasOverlay;}
uint8_t getTotalPipes() {
return (uint8_t)(mRGBPipes + mVGPipes + mDMAPipes);
}
uint8_t getRGBPipes() { return mRGBPipes; }
uint8_t getVGPipes() { return mVGPipes; }
uint8_t getDMAPipes() { return mDMAPipes; }
uint8_t getCursorPipes() { return mCursorPipes; }
uint8_t getBlendStages() { return mBlendStages; }
bool supportsDecimation();
uint32_t getMaxMDPDownscale();
uint32_t getMaxMDPUpscale();
bool supportsBWC();
bool supportsMacroTile();
int getLeftSplit() { return mSplit.left(); }
int getRightSplit() { return mSplit.right(); }
bool isPartialUpdateEnabled() { return mPanelInfo.mPartialUpdateEnable; }
int getLeftAlign() { return mPanelInfo.mLeftAlign; }
int getWidthAlign() { return mPanelInfo.mWidthAlign; }
int getTopAlign() { return mPanelInfo.mTopAlign; }
int getHeightAlign() { return mPanelInfo.mHeightAlign; }
int getMinROIWidth() { return mPanelInfo.mMinROIWidth; }
int getMinROIHeight() { return mPanelInfo.mMinROIHeight; }
bool needsROIMerge() { return mPanelInfo.mNeedsROIMerge; }
unsigned long getLowBw() { return mLowBw; }
unsigned long getHighBw() { return mHighBw; }
bool isRotDownscaleEnabled() { return mRotDownscale; }
bool isDynFpsSupported() { return mPanelInfo.mDynFpsSupported; }
uint32_t getMinFpsSupported() { return mPanelInfo.mMinFps; }
uint32_t getMaxFpsSupported() { return mPanelInfo.mMaxFps; }
uint32_t getMaxMixerWidth() const { return mMaxMixerWidth; }
uint32_t getMaxPipeWidth() const { return mMaxPipeWidth; }
uint32_t getMaxCursorSize() const { return mMaxCursorSize; }
bool hasMinCropWidthLimitation() const;
bool isSrcSplit() const;
bool isSrcSplitAlways() const;
bool isRGBScalarSupported() const;
bool is8x26();
bool is8x74v2();
bool is8084();
bool is8092();
bool is8994();
bool is8x16();
bool is8x39();
bool is8x52();
bool is8992();
bool updateSplitInfo();
private:
bool updateSysFsInfo();
void updatePanelInfo();
int tokenizeParams(char *inputParams, const char *delim,
char* tokenStr[], int *idx);
int mFd;
int mMDPVersion;
bool mHasOverlay;
uint32_t mMdpRev;
uint8_t mRGBPipes;
uint8_t mVGPipes;
uint8_t mDMAPipes;
uint8_t mCursorPipes;
uint8_t mBlendStages;
uint32_t mFeatures;
uint32_t mMDPDownscale;
uint32_t mMDPUpscale;
bool mMacroTileEnabled;
Split mSplit;
PanelInfo mPanelInfo;
unsigned long mLowBw; //kbps
unsigned long mHighBw; //kbps
bool mSourceSplit;
//Additional property on top of source split
bool mSourceSplitAlways;
bool mRGBHasNoScalar;
bool mRotDownscale;
uint32_t mMaxMixerWidth; //maximum x-res of a given mdss mixer.
uint32_t mMaxPipeWidth; //maximum x-res of the mdp pipe.
uint32_t mMaxCursorSize; //maximum size supported by hw cursor
};
}; //namespace qdutils
#endif //INCLUDE_LIBQCOMUTILS_MDPVER

View File

@@ -28,10 +28,75 @@
*/
#include "qd_utils.h"
#define QD_UTILS_DEBUG 0
namespace qdutils {
int parseLine(char *input, char *tokens[], const uint32_t maxToken, uint32_t *count) {
char *tmpToken = NULL;
char *tmpPtr;
uint32_t index = 0;
const char *delim = ", =\n";
if (!input) {
return -1;
}
tmpToken = strtok_r(input, delim, &tmpPtr);
while (tmpToken && index < maxToken) {
tokens[index++] = tmpToken;
tmpToken = strtok_r(NULL, delim, &tmpPtr);
}
*count = index;
return 0;
}
int querySDEInfo(HWQueryType type, int *value) {
FILE *fileptr = NULL;
const char *featureName;
char stringBuffer[MAX_STRING_LENGTH];
uint32_t tokenCount = 0;
const uint32_t maxCount = 10;
char *tokens[maxCount] = { NULL };
switch(type) {
case HAS_MACRO_TILE:
featureName = "tile_format";
break;
default:
ALOGE("Invalid query type %d", type);
return -EINVAL;
}
fileptr = fopen("/sys/devices/virtual/graphics/fb0/mdp/caps", "rb");
if (!fileptr) {
ALOGE("File '%s' not found", stringBuffer);
return -EINVAL;
}
size_t len = MAX_STRING_LENGTH;
ssize_t read;
char *line = stringBuffer;
while ((read = getline(&line, &len, fileptr)) != -1) {
// parse the line and update information accordingly
if (parseLine(line, tokens, maxCount, &tokenCount)) {
continue;
}
if (strncmp(tokens[0], "features", strlen("features"))) {
continue;
}
for (uint32_t i = 0; i < tokenCount; i++) {
if (!strncmp(tokens[i], featureName, strlen(featureName))) {
*value = 1;
}
}
}
fclose(fileptr);
return 0;
}
int getHDMINode(void)
{
FILE *displayDeviceFP = NULL;
@@ -92,32 +157,4 @@ int getEdidRawData(char *buffer)
return size;
}
/* Calculates the aspect ratio for based on src & dest */
void getAspectRatioPosition(int destWidth, int destHeight, int srcWidth,
int srcHeight, hwc_rect_t& rect) {
int x =0, y =0;
if (srcWidth * destHeight > destWidth * srcHeight) {
srcHeight = destWidth * srcHeight / srcWidth;
srcWidth = destWidth;
} else if (srcWidth * destHeight < destWidth * srcHeight) {
srcWidth = destHeight * srcWidth / srcHeight;
srcHeight = destHeight;
} else {
srcWidth = destWidth;
srcHeight = destHeight;
}
if (srcWidth > destWidth) srcWidth = destWidth;
if (srcHeight > destHeight) srcHeight = destHeight;
x = (destWidth - srcWidth) / 2;
y = (destHeight - srcHeight) / 2;
ALOGD_IF(QD_UTILS_DEBUG, "%s: AS Position: x = %d, y = %d w = %d h = %d",
__FUNCTION__, x, y, srcWidth , srcHeight);
// Convert it back to hwc_rect_t
rect.left = x;
rect.top = y;
rect.right = srcWidth + rect.left;
rect.bottom = srcHeight + rect.top;
}
}; //namespace qdutils

View File

@@ -45,18 +45,22 @@
#include <hardware/hwcomposer.h>
namespace qdutils {
#define EDID_RAW_DATA_SIZE 640
enum qd_utils {
MAX_FRAME_BUFFER_NAME_SIZE = 128,
MAX_SYSFS_FILE_PATH = 255,
SUPPORTED_DOWNSCALE_AREA = (1920*1080)
enum HWQueryType {
HAS_MACRO_TILE = 0,
};
int getHDMINode(void);
int getEdidRawData(char *buffer);
enum {
EDID_RAW_DATA_SIZE = 640,
MAX_FRAME_BUFFER_NAME_SIZE = 128,
MAX_SYSFS_FILE_PATH = 255,
MAX_STRING_LENGTH = 1024,
};
int parseLine(char *input, char *tokens[], const uint32_t maxToken, uint32_t *count);
int querySDEInfo(HWQueryType type, int *value);
int getEdidRawData(char *buffer);
int getHDMINode(void);
void getAspectRatioPosition(int destWidth, int destHeight, int srcWidth,
int srcHeight, hwc_rect_t& rect);
}; //namespace qdutils
#endif