android_hardware_qcom_display/liboverlay/overlayLibUI.cpp

456 lines
12 KiB
C++
Raw Normal View History

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