Whenever there is a change in the buffer geometry, set a flag in the gralloc handle stating that the buffer geometry has changed. In the HWC, whenever we encounter an update in the geometry, if the channel is already open, we just call the necessary ioctls to update the overlay information and not unnecessarily open/close channels. Change-Id: I27db8fc497ebc514e262d6b7854739f312644714
1419 lines
42 KiB
C++
1419 lines
42 KiB
C++
/*
|
|
* Copyright (C) 2008 The Android Open Source Project
|
|
* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "overlayLib.h"
|
|
#include "gralloc_priv.h"
|
|
|
|
#define INTERLACE_MASK 0x80
|
|
/* Helper functions */
|
|
|
|
static int get_mdp_format(int format) {
|
|
switch (format) {
|
|
case HAL_PIXEL_FORMAT_RGBA_8888 :
|
|
return MDP_RGBA_8888;
|
|
case HAL_PIXEL_FORMAT_BGRA_8888:
|
|
return MDP_BGRA_8888;
|
|
case HAL_PIXEL_FORMAT_RGB_565:
|
|
return MDP_RGB_565;
|
|
case HAL_PIXEL_FORMAT_RGBX_8888:
|
|
return MDP_RGBX_8888;
|
|
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
|
|
return MDP_Y_CBCR_H2V1;
|
|
case HAL_PIXEL_FORMAT_YCbCr_420_SP:
|
|
return MDP_Y_CBCR_H2V2;
|
|
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
|
|
return MDP_Y_CRCB_H2V2;
|
|
case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
|
|
return MDP_Y_CRCB_H2V2_TILE;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int get_size(int format, int w, int h) {
|
|
int size, aligned_height, pitch;
|
|
|
|
size = w * h;
|
|
switch (format) {
|
|
case MDP_RGBA_8888:
|
|
case MDP_BGRA_8888:
|
|
case MDP_RGBX_8888:
|
|
size *= 4;
|
|
break;
|
|
case MDP_RGB_565:
|
|
case MDP_Y_CBCR_H2V1:
|
|
size *= 2;
|
|
break;
|
|
case MDP_Y_CBCR_H2V2:
|
|
case MDP_Y_CRCB_H2V2:
|
|
size = (size * 3) / 2;
|
|
break;
|
|
case MDP_Y_CRCB_H2V2_TILE:
|
|
aligned_height = (h + 31) & ~31;
|
|
pitch = (w + 127) & ~127;
|
|
size = pitch * aligned_height;
|
|
size = (size + 8191) & ~8191;
|
|
|
|
aligned_height = ((h >> 1) + 31) & ~31;
|
|
size += pitch * aligned_height;
|
|
size = (size + 8191) & ~8191;
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
static int get_mdp_orientation(int rotation, int flip) {
|
|
switch(flip) {
|
|
case HAL_TRANSFORM_FLIP_V:
|
|
switch(rotation) {
|
|
case 0: return MDP_FLIP_UD;
|
|
case HAL_TRANSFORM_ROT_90: return (MDP_ROT_90 | MDP_FLIP_UD);
|
|
default: return -1;
|
|
break;
|
|
}
|
|
break;
|
|
case HAL_TRANSFORM_FLIP_H:
|
|
switch(rotation) {
|
|
case 0: return MDP_FLIP_LR;
|
|
case HAL_TRANSFORM_ROT_90: return (MDP_ROT_90 | MDP_FLIP_LR);
|
|
default: return -1;
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
switch(rotation) {
|
|
case 0: return MDP_ROT_NOP;
|
|
case HAL_TRANSFORM_ROT_90: return MDP_ROT_90;
|
|
case HAL_TRANSFORM_ROT_180: return MDP_ROT_180;
|
|
case HAL_TRANSFORM_ROT_270: return MDP_ROT_270;
|
|
default: return -1;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static bool isRGBType(int format) {
|
|
switch (format) {
|
|
case MDP_RGBA_8888:
|
|
case MDP_BGRA_8888:
|
|
case MDP_RGBX_8888:
|
|
case MDP_RGB_565:
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static int getRGBBpp(int format) {
|
|
switch (format) {
|
|
case MDP_RGBA_8888:
|
|
case MDP_BGRA_8888:
|
|
case MDP_RGBX_8888:
|
|
return 4;
|
|
case MDP_RGB_565:
|
|
return 2;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
#define LOG_TAG "OverlayLIB"
|
|
static void reportError(const char* message) {
|
|
LOGE( "%s", message);
|
|
}
|
|
|
|
using namespace overlay;
|
|
|
|
Overlay::Overlay() : mChannelUP(false), mHDMIConnected(false),
|
|
mCloseChannel(false), mS3DFormat(0) {
|
|
}
|
|
|
|
Overlay::~Overlay() {
|
|
closeChannel();
|
|
}
|
|
|
|
int Overlay::getFBWidth(int channel) const {
|
|
return objOvCtrlChannel[channel].getFBWidth();
|
|
}
|
|
|
|
int Overlay::getFBHeight(int channel) const {
|
|
return objOvCtrlChannel[channel].getFBHeight();
|
|
}
|
|
|
|
bool Overlay::startChannel(int w, int h, int format, int fbnum,
|
|
bool norot, bool uichannel,
|
|
unsigned int format3D, int channel,
|
|
bool ignoreFB, int num_buffers) {
|
|
int zorder = 0;
|
|
|
|
if (format3D)
|
|
zorder = channel;
|
|
mChannelUP = objOvCtrlChannel[channel].startControlChannel(w, h, format, fbnum,
|
|
norot, uichannel, format3D, zorder, ignoreFB);
|
|
if (!mChannelUP) {
|
|
LOGE("startChannel for fb%d failed", fbnum);
|
|
return mChannelUP;
|
|
}
|
|
return objOvDataChannel[channel].startDataChannel(objOvCtrlChannel[channel], fbnum,
|
|
norot, uichannel, num_buffers);
|
|
}
|
|
|
|
bool Overlay::startChannelHDMI(int w, int h, int format, bool norot) {
|
|
|
|
bool ret = startChannel(w, h, format, FRAMEBUFFER_0, norot);
|
|
if(ret) {
|
|
ret = startChannel(w, h, format, FRAMEBUFFER_1, true, 0, 0, VG1_PIPE);
|
|
overlay_rect rect;
|
|
if(ret && objOvCtrlChannel[VG1_PIPE].getAspectRatioPosition(w, h, format, &rect)) {
|
|
if(!setChannelPosition(rect.x, rect.y, rect.width, rect.height, VG1_PIPE)) {
|
|
LOGE("Failed to upscale for framebuffer 1");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool Overlay::startChannelS3D(int w, int h, int format, bool norot, int s3DFormat) {
|
|
|
|
if (!mHDMIConnected) {
|
|
// S3D without HDMI is not supported yet
|
|
return true;
|
|
}
|
|
// Start both the channels for the S3D content
|
|
bool ret = startChannel(w, h, format, FRAMEBUFFER_1, norot, 0, mS3DFormat, VG0_PIPE);
|
|
if (ret) {
|
|
ret = startChannel(w, h, format, FRAMEBUFFER_1, norot, 0, mS3DFormat, VG1_PIPE);
|
|
}
|
|
if (ret) {
|
|
FILE *fp = fopen(FORMAT_3D_FILE, "wb");
|
|
if (fp) {
|
|
fprintf(fp, "%d", mS3DFormat & OUTPUT_MASK_3D);
|
|
fclose(fp);
|
|
fp = NULL;
|
|
}
|
|
}
|
|
|
|
if (!ret) {
|
|
closeChannel();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool Overlay::closeChannel() {
|
|
|
|
if (!mCloseChannel && !mChannelUP)
|
|
return true;
|
|
|
|
if(mS3DFormat) {
|
|
FILE *fp = fopen(FORMAT_3D_FILE, "wb");
|
|
if (fp) {
|
|
fprintf(fp, "0");
|
|
fclose(fp);
|
|
fp = NULL;
|
|
}
|
|
}
|
|
for (int i = 0; i < NUM_CHANNELS; i++) {
|
|
objOvCtrlChannel[i].closeControlChannel();
|
|
objOvDataChannel[i].closeDataChannel();
|
|
}
|
|
mChannelUP = false;
|
|
mCloseChannel = false;
|
|
mS3DFormat = 0;
|
|
return true;
|
|
}
|
|
|
|
bool Overlay::getPosition(int& x, int& y, uint32_t& w, uint32_t& h, int channel) {
|
|
return objOvCtrlChannel[channel].getPosition(x, y, w, h);
|
|
}
|
|
|
|
bool Overlay::getOrientation(int& orientation, int channel) const {
|
|
return objOvCtrlChannel[channel].getOrientation(orientation);
|
|
}
|
|
|
|
bool Overlay::setPosition(int x, int y, uint32_t w, uint32_t h) {
|
|
if(mS3DFormat && mHDMIConnected) {
|
|
return setPositionS3D(x, y, w, h);
|
|
} else {
|
|
return setChannelPosition(x, y, w, h, VG0_PIPE);
|
|
}
|
|
}
|
|
|
|
bool Overlay::setChannelPosition(int x, int y, uint32_t w, uint32_t h, int channel) {
|
|
return objOvCtrlChannel[channel].setPosition(x, y, w, h);
|
|
}
|
|
|
|
bool Overlay::setPositionS3D(int x, int y, uint32_t w, uint32_t h) {
|
|
bool ret = false;
|
|
|
|
for (int i = 0; i < NUM_CHANNELS; i++) {
|
|
overlay_rect rect;
|
|
ret = objOvCtrlChannel[i].getPositionS3D(i, mS3DFormat, &rect);
|
|
if (ret) {
|
|
setChannelPosition(rect.x, rect.y, rect.width, rect.height, i);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool Overlay::updateOverlaySource(uint32_t w, uint32_t h, int format, int orientation) {
|
|
if (hasHDMIStatusChanged()) {
|
|
return setSource(w, h, format, orientation, mHDMIConnected);
|
|
}
|
|
|
|
bool ret = true;
|
|
// Set the overlay source info
|
|
if (objOvCtrlChannel[0].isChannelUP()) {
|
|
ret = objOvCtrlChannel[0].updateOverlaySource(w, h);
|
|
if (ret && objOvCtrlChannel[1].isChannelUP())
|
|
ret = objOvCtrlChannel[1].updateOverlaySource(w, h);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int Overlay::hasHDMIStatusChanged() {
|
|
int hdmiChanged = 0;
|
|
if (mHDMIConnected) {
|
|
// If HDMI is connected and both channels are not up, set the status
|
|
if (!objOvCtrlChannel[0].isChannelUP() || !objOvCtrlChannel[1].isChannelUP()) {
|
|
hdmiChanged = 0x1;
|
|
}
|
|
} else {
|
|
// HDMI is disconnected and both channels are up, set the status
|
|
if (objOvCtrlChannel[0].isChannelUP() && objOvCtrlChannel[1].isChannelUP()) {
|
|
hdmiChanged = 0x1;
|
|
}
|
|
}
|
|
return hdmiChanged;
|
|
}
|
|
|
|
bool Overlay::setSource(uint32_t w, uint32_t h, int format, int orientation,
|
|
bool hdmiConnected, bool ignoreFB, int num_buffers) {
|
|
if (mCloseChannel)
|
|
closeChannel();
|
|
|
|
// Separate the color format from the 3D format.
|
|
// If there is 3D content; the effective format passed by the client is:
|
|
// effectiveFormat = 3D_IN | 3D_OUT | ColorFormat
|
|
unsigned int format3D = FORMAT_3D(format);
|
|
int colorFormat = COLOR_FORMAT(format);
|
|
int fIn3D = FORMAT_3D_INPUT(format3D); // MSB 2 bytes are input format
|
|
int fOut3D = FORMAT_3D_OUTPUT(format3D); // LSB 2 bytes are output format
|
|
format3D = fIn3D | fOut3D;
|
|
// Use the same in/out format if not mentioned
|
|
if (!fIn3D) {
|
|
format3D |= fOut3D << SHIFT_3D; //Set the input format
|
|
}
|
|
if (!fOut3D) {
|
|
format3D |= fIn3D >> SHIFT_3D; //Set the output format
|
|
}
|
|
|
|
int stateChanged = 0;
|
|
int hw_format = get_mdp_format(colorFormat);
|
|
int s3dChanged =0, hdmiChanged = 0;
|
|
|
|
if (format3D != mS3DFormat)
|
|
s3dChanged = 0x10;
|
|
|
|
stateChanged = s3dChanged|hasHDMIStatusChanged();
|
|
if (stateChanged || !objOvCtrlChannel[0].setSource(w, h, colorFormat, orientation, ignoreFB)) {
|
|
if (mChannelUP && isRGBType(hw_format) && (stateChanged != 0x10)) {
|
|
mCloseChannel = true;
|
|
return false;
|
|
}
|
|
closeChannel();
|
|
mS3DFormat = format3D;
|
|
|
|
if (mHDMIConnected) {
|
|
if (format3D) {
|
|
// Start both the VG pipes
|
|
return startChannelS3D(w, h, colorFormat, !orientation, format3D);
|
|
} else {
|
|
return startChannelHDMI(w, h, colorFormat, !orientation);
|
|
}
|
|
} else {
|
|
return startChannel(w, h, colorFormat, 0, !orientation,
|
|
false, 0, VG0_PIPE, ignoreFB, num_buffers);
|
|
}
|
|
}
|
|
else
|
|
return true;
|
|
}
|
|
|
|
bool Overlay::setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h) {
|
|
if (!mChannelUP)
|
|
return false;
|
|
bool ret;
|
|
|
|
if (mHDMIConnected) {
|
|
if (mS3DFormat) {
|
|
overlay_rect rect;
|
|
overlay_rect inRect;
|
|
inRect.x = x; inRect.y = y; inRect.width = w; inRect.height = h;
|
|
|
|
// Set the crop for both VG pipes
|
|
for (int i = 0; i < NUM_CHANNELS; i++) {
|
|
objOvDataChannel[i].getCropS3D(&inRect, i, mS3DFormat, &rect);
|
|
ret = setChannelCrop(rect.x, rect.y, rect.width, rect.height, i);
|
|
}
|
|
return ret;
|
|
} else {
|
|
setChannelCrop(x, y, w, h, VG1_PIPE);
|
|
}
|
|
}
|
|
return setChannelCrop(x, y, w, h, VG0_PIPE);
|
|
}
|
|
|
|
bool Overlay::setChannelCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h, int channel) {
|
|
return objOvDataChannel[channel].setCrop(x, y, w, h);
|
|
}
|
|
|
|
bool Overlay::setParameter(int param, int value) {
|
|
if (mS3DFormat && mHDMIConnected)
|
|
return setParameterS3D(param, value);
|
|
else {
|
|
return objOvCtrlChannel[VG0_PIPE].setParameter(param, value);
|
|
}
|
|
}
|
|
|
|
bool Overlay::setParameterS3D(int param, int value) {
|
|
bool ret = false;
|
|
if (mHDMIConnected) {
|
|
// Set the S3D parameter for both VG pipes
|
|
ret = objOvCtrlChannel[VG0_PIPE].setParameter(param, value);
|
|
if (ret)
|
|
ret = objOvCtrlChannel[VG1_PIPE].setParameter(param, value);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool Overlay::setOrientation(int value, int channel) {
|
|
return objOvCtrlChannel[channel].setParameter(OVERLAY_TRANSFORM, value);
|
|
}
|
|
|
|
bool Overlay::setFd(int fd, int channel) {
|
|
return objOvDataChannel[channel].setFd(fd);
|
|
}
|
|
|
|
bool Overlay::queueBuffer(uint32_t offset, int channel) {
|
|
return objOvDataChannel[channel].queueBuffer(offset);
|
|
}
|
|
|
|
bool Overlay::queueBuffer(buffer_handle_t buffer) {
|
|
private_handle_t const* hnd = reinterpret_cast
|
|
<private_handle_t const*>(buffer);
|
|
const size_t offset = hnd->offset;
|
|
const int fd = hnd->fd;
|
|
bool ret = true;
|
|
|
|
if (mHDMIConnected) {
|
|
if (mS3DFormat) {
|
|
// Queue the buffer on VG1 pipe
|
|
if ((mS3DFormat & HAL_3D_OUT_SIDE_BY_SIDE_HALF_MASK) ||
|
|
(mS3DFormat & HAL_3D_OUT_TOP_BOTTOM_MASK)) {
|
|
ret = queueBuffer(fd, offset, VG1_PIPE);
|
|
}
|
|
} else {
|
|
ret = queueBuffer(fd, offset, VG1_PIPE);
|
|
}
|
|
}
|
|
if (ret && setFd(fd)) {
|
|
return queueBuffer(offset);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Overlay::queueBuffer(int fd, uint32_t offset, int channel) {
|
|
bool ret = false;
|
|
ret = setFd(fd, channel);
|
|
if(!ret) {
|
|
LOGE("Overlay::queueBuffer channel %d setFd failed", channel);
|
|
return false;
|
|
}
|
|
ret = queueBuffer(offset, channel);
|
|
if(!ret) {
|
|
LOGE("Overlay::queueBuffer channel %d queueBuffer failed", channel);
|
|
return false;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
OverlayControlChannel::OverlayControlChannel() : mNoRot(false), mFD(-1), mRotFD(-1), mFormat3D(0) {
|
|
memset(&mOVInfo, 0, sizeof(mOVInfo));
|
|
memset(&mRotInfo, 0, sizeof(mRotInfo));
|
|
}
|
|
|
|
|
|
OverlayControlChannel::~OverlayControlChannel() {
|
|
closeControlChannel();
|
|
}
|
|
|
|
bool OverlayControlChannel::getAspectRatioPosition(int w, int h, int format, overlay_rect *rect)
|
|
{
|
|
int width = w, height = h, x, y;
|
|
int fbWidthHDMI = getFBWidth();
|
|
int fbHeightHDMI = getFBHeight();
|
|
// width and height for YUV TILE format
|
|
int tempWidth = w, tempHeight = h;
|
|
/* Calculate the width and height if it is YUV TILE format*/
|
|
if(format == HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED) {
|
|
tempWidth = w - ( (((w-1)/64 +1)*64) - w);
|
|
tempHeight = h - ((((h-1)/32 +1)*32) - h);
|
|
}
|
|
if (width * fbHeightHDMI > fbWidthHDMI * height) {
|
|
height = fbWidthHDMI * height / width;
|
|
EVEN_OUT(height);
|
|
width = fbWidthHDMI;
|
|
} else if (width * fbHeightHDMI < fbWidthHDMI * height) {
|
|
width = fbHeightHDMI * width / height;
|
|
EVEN_OUT(width);
|
|
height = fbHeightHDMI;
|
|
} else {
|
|
width = fbWidthHDMI;
|
|
height = fbHeightHDMI;
|
|
}
|
|
/* Scaling of upto a max of 8 times supported */
|
|
if(width >(tempWidth * HW_OVERLAY_MAGNIFICATION_LIMIT)){
|
|
width = HW_OVERLAY_MAGNIFICATION_LIMIT * tempWidth;
|
|
}
|
|
if(height >(tempHeight*HW_OVERLAY_MAGNIFICATION_LIMIT)) {
|
|
height = HW_OVERLAY_MAGNIFICATION_LIMIT * tempHeight;
|
|
}
|
|
if (width > fbWidthHDMI) width = fbWidthHDMI;
|
|
if (height > fbHeightHDMI) height = fbHeightHDMI;
|
|
x = (fbWidthHDMI - width) / 2;
|
|
y = (fbHeightHDMI - height) / 2;
|
|
rect->x = x;
|
|
rect->y = y;
|
|
rect->width = width;
|
|
rect->height = height;
|
|
return true;
|
|
}
|
|
|
|
bool OverlayControlChannel::getPositionS3D(int channel, int format, overlay_rect *rect) {
|
|
int wHDMI = getFBWidth();
|
|
int hHDMI = getFBHeight();
|
|
|
|
if (format & HAL_3D_OUT_SIDE_BY_SIDE_HALF_MASK) {
|
|
if (channel == VG0_PIPE) {
|
|
rect->x = 0;
|
|
rect->y = 0;
|
|
rect->width = wHDMI/2;
|
|
rect->height = hHDMI;
|
|
} else {
|
|
rect->x = wHDMI/2;
|
|
rect->y = 0;
|
|
rect->width = wHDMI/2;
|
|
rect->height = hHDMI;
|
|
}
|
|
} else if (format & HAL_3D_OUT_TOP_BOTTOM_MASK) {
|
|
if (channel == VG0_PIPE) {
|
|
rect->x = 0;
|
|
rect->y = 0;
|
|
rect->width = wHDMI;
|
|
rect->height = hHDMI/2;
|
|
} else {
|
|
rect->x = 0;
|
|
rect->y = hHDMI/2;
|
|
rect->width = wHDMI;
|
|
rect->height = hHDMI/2;
|
|
}
|
|
} else if (format & HAL_3D_OUT_INTERLEAVE_MASK) {
|
|
//TBD
|
|
} else if (format & HAL_3D_OUT_SIDE_BY_SIDE_FULL_MASK) {
|
|
//TBD
|
|
} else {
|
|
reportError("Unsupported 3D output format");
|
|
}
|
|
return true;
|
|
}
|
|
bool OverlayControlChannel::openDevices(int fbnum) {
|
|
if (fbnum < 0)
|
|
return false;
|
|
|
|
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) {
|
|
reportError("Cant open framebuffer ");
|
|
return false;
|
|
}
|
|
|
|
fb_fix_screeninfo finfo;
|
|
if (ioctl(mFD, FBIOGET_FSCREENINFO, &finfo) == -1) {
|
|
reportError("FBIOGET_FSCREENINFO on fb1 failed");
|
|
close(mFD);
|
|
mFD = -1;
|
|
return false;
|
|
}
|
|
|
|
fb_var_screeninfo vinfo;
|
|
if (ioctl(mFD, FBIOGET_VSCREENINFO, &vinfo) == -1) {
|
|
reportError("FBIOGET_VSCREENINFO on fb1 failed");
|
|
close(mFD);
|
|
mFD = -1;
|
|
return false;
|
|
}
|
|
mFBWidth = vinfo.xres;
|
|
mFBHeight = vinfo.yres;
|
|
mFBbpp = vinfo.bits_per_pixel;
|
|
mFBystride = finfo.line_length;
|
|
|
|
if (!mNoRot) {
|
|
mRotFD = open("/dev/msm_rotator", O_RDWR, 0);
|
|
if (mRotFD < 0) {
|
|
reportError("Cant open rotator device");
|
|
close(mFD);
|
|
mFD = -1;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool OverlayControlChannel::setOverlayInformation(int w, int h,
|
|
int format, int flags, int zorder,
|
|
bool ignoreFB) {
|
|
int origW, origH, xoff, yoff;
|
|
|
|
mOVInfo.id = MSMFB_NEW_REQUEST;
|
|
mOVInfo.src.width = w;
|
|
mOVInfo.src.height = h;
|
|
mOVInfo.src_rect.x = 0;
|
|
mOVInfo.src_rect.y = 0;
|
|
mOVInfo.dst_rect.x = 0;
|
|
mOVInfo.dst_rect.y = 0;
|
|
mOVInfo.dst_rect.w = w;
|
|
mOVInfo.dst_rect.h = h;
|
|
if(format == MDP_Y_CRCB_H2V2_TILE) {
|
|
if (mNoRot) {
|
|
mOVInfo.src_rect.w = w - ( (((w-1)/64 +1)*64) - w);
|
|
mOVInfo.src_rect.h = h - ((((h-1)/32 +1)*32) - h);
|
|
mOVInfo.src.format = MDP_Y_CRCB_H2V2_TILE;
|
|
} else {
|
|
mOVInfo.src_rect.w = w;
|
|
mOVInfo.src_rect.h = h;
|
|
mOVInfo.src.width = (((w-1)/64 +1)*64);
|
|
mOVInfo.src.height = (((h-1)/32 +1)*32);
|
|
mOVInfo.src_rect.x = mOVInfo.src.width - w;
|
|
mOVInfo.src_rect.y = mOVInfo.src.height - h;
|
|
mOVInfo.src.format = MDP_Y_CRCB_H2V2;
|
|
}
|
|
} else {
|
|
mOVInfo.src_rect.w = w;
|
|
mOVInfo.src_rect.h = h;
|
|
mOVInfo.src.format = format;
|
|
}
|
|
|
|
if (w > mFBWidth)
|
|
mOVInfo.dst_rect.w = mFBWidth;
|
|
if (h > mFBHeight)
|
|
mOVInfo.dst_rect.h = mFBHeight;
|
|
mOVInfo.z_order = zorder;
|
|
mOVInfo.alpha = 0xff;
|
|
mOVInfo.transp_mask = 0xffffffff;
|
|
mOVInfo.flags = flags;
|
|
if (!ignoreFB)
|
|
mOVInfo.flags |= MDP_OV_PLAY_NOWAIT;
|
|
mSize = get_size(format, w, h);
|
|
return true;
|
|
}
|
|
|
|
bool OverlayControlChannel::startOVRotatorSessions(int w, int h,
|
|
int format) {
|
|
bool ret = true;
|
|
|
|
if (!mNoRot) {
|
|
if (isRGBType(format) && mOVInfo.is_fg) {
|
|
w = (w + 31) & ~31;
|
|
h = (h + 31) & ~31;
|
|
}
|
|
mRotInfo.src.format = format;
|
|
mRotInfo.src.width = w;
|
|
mRotInfo.src.height = h;
|
|
mRotInfo.src_rect.w = w;
|
|
mRotInfo.src_rect.h = h;
|
|
mRotInfo.dst.width = w;
|
|
mRotInfo.dst.height = h;
|
|
if(format == MDP_Y_CRCB_H2V2_TILE) {
|
|
mRotInfo.src.width = (((w-1)/64 +1)*64);
|
|
mRotInfo.src.height = (((h-1)/32 +1)*32);
|
|
mRotInfo.src_rect.w = (((w-1)/64 +1)*64);
|
|
mRotInfo.src_rect.h = (((h-1)/32 +1)*32);
|
|
mRotInfo.dst.width = (((w-1)/64 +1)*64);
|
|
mRotInfo.dst.height = (((h-1)/32 +1)*32);
|
|
mRotInfo.dst.format = MDP_Y_CRCB_H2V2;
|
|
} else {
|
|
mRotInfo.dst.format = format;
|
|
}
|
|
mRotInfo.dst_x = 0;
|
|
mRotInfo.dst_y = 0;
|
|
mRotInfo.src_rect.x = 0;
|
|
mRotInfo.src_rect.y = 0;
|
|
mRotInfo.rotations = 0;
|
|
mRotInfo.enable = 0;
|
|
if(mUIChannel)
|
|
mRotInfo.enable = 1;
|
|
mRotInfo.session_id = 0;
|
|
int result = ioctl(mRotFD, MSM_ROTATOR_IOCTL_START, &mRotInfo);
|
|
if (result) {
|
|
reportError("Rotator session failed");
|
|
ret = false;
|
|
}
|
|
}
|
|
|
|
if (!mNoRot && isRGBType(format) && mOrientation && mOVInfo.is_fg) {
|
|
mOVInfo.dst_rect.w = mFBWidth;
|
|
mOVInfo.dst_rect.h = mFBHeight;
|
|
ret = setParameter(OVERLAY_TRANSFORM, mOrientation, false);
|
|
if (!ret) {
|
|
reportError("Overlay set failed.. ");
|
|
return false;
|
|
}
|
|
}
|
|
else if (ioctl(mFD, MSMFB_OVERLAY_SET, &mOVInfo)) {
|
|
reportError("startOVRotatorSessions, Overlay set failed");
|
|
ret = false;
|
|
}
|
|
|
|
if (!ret)
|
|
closeControlChannel();
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool OverlayControlChannel::updateOverlaySource(uint32_t w, uint32_t h)
|
|
{
|
|
// Set Rotator info
|
|
if (mRotFD >=0) {
|
|
if(mRotInfo.src.format == MDP_Y_CRCB_H2V2_TILE) {
|
|
if ((mRotInfo.src.width == (((w-1)/64 +1)*64)) &&
|
|
(mRotInfo.src.height == (((h-1)/32 +1)*32)))
|
|
return true;
|
|
|
|
mRotInfo.src.width = (((w-1)/64 +1)*64);
|
|
mRotInfo.src.height = (((h-1)/32 +1)*32);
|
|
mRotInfo.src_rect.w = (((w-1)/64 +1)*64);
|
|
mRotInfo.src_rect.h = (((h-1)/32 +1)*32);
|
|
mRotInfo.dst.height = (((w-1)/64 +1)*64);
|
|
mRotInfo.dst.width = (((h-1)/32 +1)*32);
|
|
mRotInfo.dst.format = MDP_Y_CRCB_H2V2;
|
|
} else {
|
|
if ((mRotInfo.src.width == w) &&
|
|
(mRotInfo.src.height == h))
|
|
return true;
|
|
|
|
mRotInfo.src.width = w;
|
|
mRotInfo.src.height = h;
|
|
mRotInfo.src_rect.w = w;
|
|
mRotInfo.src_rect.h = h;
|
|
mRotInfo.dst.width = h;
|
|
mRotInfo.dst.height = w;
|
|
}
|
|
|
|
if (mOVInfo.user_data[0] == MDP_ROT_NOP)
|
|
mRotInfo.enable = 0;
|
|
|
|
if (ioctl(mRotFD, MSM_ROTATOR_IOCTL_START, &mRotInfo)) {
|
|
LOGE("updateOverlaySource MSM_ROTATOR_IOCTL_START failed");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Set overlay info
|
|
switch (mOVInfo.user_data[0]) {
|
|
case MDP_ROT_90:
|
|
case (MDP_ROT_90 | MDP_FLIP_UD):
|
|
case (MDP_ROT_90 | MDP_FLIP_LR):
|
|
case MDP_ROT_270: {
|
|
if ((mOVInfo.src.height == (((w-1)/64 +1)*64)) &&
|
|
(mOVInfo.src.width == (((h-1)/32 +1)*32)))
|
|
return true;
|
|
|
|
mOVInfo.src_rect.w = h;
|
|
mOVInfo.src_rect.h = w;
|
|
mOVInfo.src.height = (((w-1)/64 +1)*64);
|
|
mOVInfo.src.width = (((h-1)/32 +1)*32);
|
|
mOVInfo.src_rect.x = 0;
|
|
mOVInfo.src_rect.y = 0;;
|
|
} break;
|
|
case MDP_ROT_180:
|
|
case MDP_ROT_NOP: {
|
|
if ((mOVInfo.src.width == w) &&
|
|
(mOVInfo.src.height == h))
|
|
return true;
|
|
|
|
mOVInfo.src.width = w;
|
|
mOVInfo.src.height = h;
|
|
mOVInfo.src_rect.x = 0;
|
|
mOVInfo.src_rect.y = 0;
|
|
if(mOVInfo.src.format == MDP_Y_CRCB_H2V2_TILE) {
|
|
mOVInfo.src_rect.w = w - ( (((w-1)/64 +1)*64) - w);
|
|
mOVInfo.src_rect.h = h - ((((h-1)/32 +1)*32) - h);
|
|
} else {
|
|
mOVInfo.src_rect.w = w;
|
|
mOVInfo.src_rect.h = h;
|
|
}
|
|
} break;
|
|
default:
|
|
LOGE("updateOverlaySource: Invalid rotation parameter");
|
|
return false;
|
|
}
|
|
|
|
if (ioctl(mFD, MSMFB_OVERLAY_SET, &mOVInfo)) {
|
|
LOGE("updateOverlaySource MSMFB_OVERLAY_SET failed");
|
|
return true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool OverlayControlChannel::startControlChannel(int w, int h,
|
|
int format, int fbnum, bool norot,
|
|
bool uichannel,
|
|
unsigned int format3D, int zorder,
|
|
bool ignoreFB) {
|
|
mNoRot = norot;
|
|
mUIChannel = uichannel;
|
|
fb_fix_screeninfo finfo;
|
|
fb_var_screeninfo vinfo;
|
|
int hw_format;
|
|
int flags = 0;
|
|
int colorFormat = format;
|
|
if (format & INTERLACE_MASK) {
|
|
flags |= MDP_DEINTERLACE;
|
|
|
|
// Get the actual format
|
|
colorFormat = format ^ HAL_PIXEL_FORMAT_INTERLACE;
|
|
}
|
|
hw_format = get_mdp_format(colorFormat);
|
|
if (hw_format < 0) {
|
|
reportError("Unsupported format");
|
|
return false;
|
|
}
|
|
|
|
mFormat3D = format3D;
|
|
if (!mFormat3D) {
|
|
// Set the share bit for sharing the VG pipe
|
|
flags |= MDP_OV_PIPE_SHARE;
|
|
}
|
|
if (!openDevices(fbnum))
|
|
return false;
|
|
|
|
if (!setOverlayInformation(w, h, hw_format, flags, zorder, ignoreFB))
|
|
return false;
|
|
|
|
return startOVRotatorSessions(w, h, hw_format);
|
|
}
|
|
|
|
bool OverlayControlChannel::closeControlChannel() {
|
|
if (!isChannelUP())
|
|
return true;
|
|
|
|
if (!mNoRot && mRotFD > 0) {
|
|
ioctl(mRotFD, MSM_ROTATOR_IOCTL_FINISH, &(mRotInfo.session_id));
|
|
close(mRotFD);
|
|
mRotFD = -1;
|
|
}
|
|
|
|
int ovid = mOVInfo.id;
|
|
int ret = ioctl(mFD, MSMFB_OVERLAY_UNSET, &ovid);
|
|
close(mFD);
|
|
memset(&mOVInfo, 0, sizeof(mOVInfo));
|
|
memset(&mRotInfo, 0, sizeof(mRotInfo));
|
|
mFD = -1;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool OverlayControlChannel::setSource(uint32_t w, uint32_t h,
|
|
int cFormat, int orientation, bool ignoreFB) {
|
|
int format = cFormat & INTERLACE_MASK ?
|
|
(cFormat ^ HAL_PIXEL_FORMAT_INTERLACE) : cFormat;
|
|
format = get_mdp_format(format);
|
|
if ((orientation == mOrientation)
|
|
&& ((orientation == OVERLAY_TRANSFORM_ROT_90)
|
|
|| (orientation == OVERLAY_TRANSFORM_ROT_270))) {
|
|
if (format == MDP_Y_CRCB_H2V2_TILE) {
|
|
format = MDP_Y_CRCB_H2V2;
|
|
w = (((w-1)/64 +1)*64);
|
|
h = (((h-1)/32 +1)*32);
|
|
}
|
|
int tmp = w;
|
|
w = h;
|
|
h = tmp;
|
|
}
|
|
if (w == mOVInfo.src.width && h == mOVInfo.src.height
|
|
&& format == mOVInfo.src.format && orientation == mOrientation) {
|
|
mdp_overlay ov;
|
|
ov.id = mOVInfo.id;
|
|
if (ioctl(mFD, MSMFB_OVERLAY_GET, &ov))
|
|
return false;
|
|
mOVInfo = ov;
|
|
int flags = mOVInfo.flags;
|
|
|
|
if (!ignoreFB)
|
|
mOVInfo.flags |= MDP_OV_PLAY_NOWAIT;
|
|
else
|
|
mOVInfo.flags &= ~MDP_OV_PLAY_NOWAIT;
|
|
|
|
if (flags != mOVInfo.flags) {
|
|
if (ioctl(mFD, MSMFB_OVERLAY_SET, &mOVInfo))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
mOrientation = orientation;
|
|
return false;
|
|
}
|
|
|
|
bool OverlayControlChannel::setPosition(int x, int y, uint32_t w, uint32_t h) {
|
|
|
|
int width = w, height = h;
|
|
if (!isChannelUP() ||
|
|
(x < 0) || (y < 0) || ((x + w) > mFBWidth) ||
|
|
((y + h) > mFBHeight)) {
|
|
reportError("setPosition failed");
|
|
return false;
|
|
}
|
|
|
|
mdp_overlay ov;
|
|
ov.id = mOVInfo.id;
|
|
if (ioctl(mFD, MSMFB_OVERLAY_GET, &ov)) {
|
|
reportError("setPosition, overlay GET failed");
|
|
return false;
|
|
}
|
|
|
|
/* Scaling of upto a max of 8 times supported */
|
|
if(w >(ov.src_rect.w * HW_OVERLAY_MAGNIFICATION_LIMIT)){
|
|
w = HW_OVERLAY_MAGNIFICATION_LIMIT * ov.src_rect.w;
|
|
x = (mFBWidth - w) / 2;
|
|
}
|
|
if(h >(ov.src_rect.h * HW_OVERLAY_MAGNIFICATION_LIMIT)) {
|
|
h = HW_OVERLAY_MAGNIFICATION_LIMIT * ov.src_rect.h;
|
|
y = (mFBHeight - h) / 2;
|
|
}
|
|
ov.dst_rect.x = x;
|
|
ov.dst_rect.y = y;
|
|
ov.dst_rect.w = w;
|
|
ov.dst_rect.h = h;
|
|
|
|
if (ioctl(mFD, MSMFB_OVERLAY_SET, &ov)) {
|
|
reportError("setPosition, Overlay SET failed");
|
|
return false;
|
|
}
|
|
mOVInfo = ov;
|
|
|
|
return true;
|
|
}
|
|
|
|
void OverlayControlChannel::swapOVRotWidthHeight() {
|
|
int tmp = mOVInfo.src.width;
|
|
mOVInfo.src.width = mOVInfo.src.height;
|
|
mOVInfo.src.height = tmp;
|
|
|
|
tmp = mOVInfo.src_rect.h;
|
|
mOVInfo.src_rect.h = mOVInfo.src_rect.w;
|
|
mOVInfo.src_rect.w = tmp;
|
|
|
|
tmp = mRotInfo.dst.width;
|
|
mRotInfo.dst.width = mRotInfo.dst.height;
|
|
mRotInfo.dst.height = tmp;
|
|
}
|
|
|
|
bool OverlayControlChannel::setParameter(int param, int value, bool fetch) {
|
|
if (!isChannelUP())
|
|
return false;
|
|
|
|
mdp_overlay ov = mOVInfo;
|
|
if (fetch && ioctl(mFD, MSMFB_OVERLAY_GET, &ov)) {
|
|
reportError("setParameter, overlay GET failed");
|
|
return false;
|
|
}
|
|
mOVInfo = ov;
|
|
|
|
switch (param) {
|
|
case OVERLAY_DITHER:
|
|
break;
|
|
case OVERLAY_TRANSFORM:
|
|
{
|
|
int val = mOVInfo.user_data[0];
|
|
if (value && mNoRot)
|
|
return true;
|
|
|
|
int rot = value;
|
|
int flip = 0;
|
|
|
|
switch(rot) {
|
|
case 0:
|
|
case HAL_TRANSFORM_FLIP_H:
|
|
case HAL_TRANSFORM_FLIP_V:
|
|
{
|
|
if (val == MDP_ROT_90) {
|
|
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();
|
|
}
|
|
else if (val == MDP_ROT_270) {
|
|
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();
|
|
}
|
|
rot = 0;
|
|
flip = value & (HAL_TRANSFORM_FLIP_H|HAL_TRANSFORM_FLIP_V);
|
|
break;
|
|
}
|
|
case HAL_TRANSFORM_ROT_90:
|
|
case (HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_H):
|
|
case (HAL_TRANSFORM_ROT_90|HAL_TRANSFORM_FLIP_V):
|
|
{
|
|
if (val == MDP_ROT_270) {
|
|
mOVInfo.src_rect.x = mOVInfo.src.width - (
|
|
mOVInfo.src_rect.x + mOVInfo.src_rect.w);
|
|
mOVInfo.src_rect.y = mOVInfo.src.height - (
|
|
mOVInfo.src_rect.y + mOVInfo.src_rect.h);
|
|
}
|
|
else if (val == MDP_ROT_NOP || val == MDP_ROT_180) {
|
|
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();
|
|
}
|
|
rot = HAL_TRANSFORM_ROT_90;
|
|
flip = value & (HAL_TRANSFORM_FLIP_H|HAL_TRANSFORM_FLIP_V);
|
|
break;
|
|
}
|
|
case HAL_TRANSFORM_ROT_180:
|
|
{
|
|
if (val == MDP_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();
|
|
}
|
|
else if (val == MDP_ROT_90) {
|
|
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();
|
|
}
|
|
break;
|
|
}
|
|
case HAL_TRANSFORM_ROT_270:
|
|
{
|
|
if (val == MDP_ROT_90) {
|
|
mOVInfo.src_rect.y = mOVInfo.src.height -
|
|
(mOVInfo.src_rect.y + mOVInfo.src_rect.h);
|
|
mOVInfo.src_rect.x = mOVInfo.src.width -
|
|
(mOVInfo.src_rect.x + mOVInfo.src_rect.w);
|
|
}
|
|
else if (val == MDP_ROT_NOP || val == MDP_ROT_180) {
|
|
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();
|
|
}
|
|
break;
|
|
}
|
|
default: return false;
|
|
}
|
|
int mdp_rotation = get_mdp_orientation(rot, flip);
|
|
if (mdp_rotation == -1)
|
|
return false;
|
|
|
|
mOVInfo.user_data[0] = mdp_rotation;
|
|
mRotInfo.rotations = mOVInfo.user_data[0];
|
|
|
|
if (mOVInfo.user_data[0])
|
|
mRotInfo.enable = 1;
|
|
else {
|
|
if(mRotInfo.src.format == MDP_Y_CRCB_H2V2_TILE)
|
|
mOVInfo.src.format = MDP_Y_CRCB_H2V2_TILE;
|
|
mRotInfo.enable = 0;
|
|
if(mUIChannel)
|
|
mRotInfo.enable = 1;
|
|
}
|
|
if (ioctl(mRotFD, MSM_ROTATOR_IOCTL_START, &mRotInfo)) {
|
|
reportError("setParameter, rotator start failed");
|
|
return false;
|
|
}
|
|
|
|
if ((mOVInfo.user_data[0] == MDP_ROT_90) ||
|
|
(mOVInfo.user_data[0] == MDP_ROT_270))
|
|
mOVInfo.flags |= MDP_SOURCE_ROTATED_90;
|
|
|
|
if (ioctl(mFD, MSMFB_OVERLAY_SET, &mOVInfo)) {
|
|
reportError("setParameter, overlay set failed");
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
reportError("Unsupproted param");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool OverlayControlChannel::getPosition(int& x, int& y,
|
|
uint32_t& w, uint32_t& h) {
|
|
if (!isChannelUP())
|
|
return false;
|
|
//mOVInfo has the current Overlay Position
|
|
x = mOVInfo.dst_rect.x;
|
|
y = mOVInfo.dst_rect.y;
|
|
w = mOVInfo.dst_rect.w;
|
|
h = mOVInfo.dst_rect.h;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool OverlayControlChannel::getOrientation(int& orientation) const {
|
|
if (!isChannelUP())
|
|
return false;
|
|
|
|
mdp_overlay ov;
|
|
ov.id = mOVInfo.id;
|
|
if (ioctl(mFD, MSMFB_OVERLAY_GET, &ov)) {
|
|
reportError("getOrientation, overlay GET failed");
|
|
return false;
|
|
}
|
|
orientation = ov.user_data[0];
|
|
return true;
|
|
}
|
|
bool OverlayControlChannel::getOvSessionID(int& sessionID) const {
|
|
if (!isChannelUP())
|
|
return false;
|
|
sessionID = mOVInfo.id;
|
|
return true;
|
|
}
|
|
|
|
bool OverlayControlChannel::getRotSessionID(int& sessionID) const {
|
|
if (!isChannelUP())
|
|
return false;
|
|
sessionID = mRotInfo.session_id;
|
|
return true;
|
|
}
|
|
|
|
bool OverlayControlChannel::getSize(int& size) const {
|
|
if (!isChannelUP())
|
|
return false;
|
|
size = mSize;
|
|
return true;
|
|
}
|
|
|
|
OverlayDataChannel::OverlayDataChannel() : mNoRot(false), mFD(-1), mRotFD(-1),
|
|
mPmemFD(-1), mPmemAddr(0) {
|
|
}
|
|
|
|
OverlayDataChannel::~OverlayDataChannel() {
|
|
closeDataChannel();
|
|
}
|
|
|
|
bool OverlayDataChannel::startDataChannel(
|
|
const OverlayControlChannel& objOvCtrlChannel,
|
|
int fbnum, bool norot, bool uichannel, int num_buffers) {
|
|
int ovid, rotid, size;
|
|
mNoRot = norot;
|
|
memset(&mOvData, 0, sizeof(mOvData));
|
|
memset(&mOvDataRot, 0, sizeof(mOvDataRot));
|
|
memset(&mRotData, 0, sizeof(mRotData));
|
|
if (objOvCtrlChannel.getOvSessionID(ovid) &&
|
|
objOvCtrlChannel.getRotSessionID(rotid) &&
|
|
objOvCtrlChannel.getSize(size)) {
|
|
return startDataChannel(ovid, rotid, size, fbnum,
|
|
norot, uichannel, num_buffers);
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
bool OverlayDataChannel::openDevices(int fbnum, bool uichannel, int num_buffers) {
|
|
if (fbnum < 0)
|
|
return false;
|
|
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) {
|
|
reportError("Cant open framebuffer ");
|
|
return false;
|
|
}
|
|
if (!mNoRot) {
|
|
mRotFD = open("/dev/msm_rotator", O_RDWR, 0);
|
|
if (mRotFD < 0) {
|
|
reportError("Cant open rotator device");
|
|
close(mFD);
|
|
mFD = -1;
|
|
return false;
|
|
}
|
|
|
|
mPmemAddr = MAP_FAILED;
|
|
|
|
if(!uichannel) {
|
|
mPmemFD = open("/dev/pmem_smipool", O_RDWR | O_SYNC);
|
|
if(mPmemFD >= 0)
|
|
mPmemAddr = (void *) mmap(NULL, mPmemOffset * num_buffers, PROT_READ | PROT_WRITE,
|
|
MAP_SHARED, mPmemFD, 0);
|
|
}
|
|
|
|
if (mPmemAddr == MAP_FAILED) {
|
|
mPmemFD = open("/dev/pmem_adsp", O_RDWR | O_SYNC);
|
|
if (mPmemFD < 0) {
|
|
reportError("Cant open pmem_adsp ");
|
|
close(mFD);
|
|
mFD = -1;
|
|
close(mRotFD);
|
|
mRotFD = -1;
|
|
return false;
|
|
} else {
|
|
mPmemAddr = (void *) mmap(NULL, mPmemOffset * num_buffers, PROT_READ | PROT_WRITE,
|
|
MAP_SHARED, mPmemFD, 0);
|
|
if (mPmemAddr == MAP_FAILED) {
|
|
reportError("Cant map pmem_adsp ");
|
|
close(mFD);
|
|
mFD = -1;
|
|
close(mPmemFD);
|
|
mPmemFD = -1;
|
|
close(mRotFD);
|
|
mRotFD = -1;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
mOvDataRot.data.memory_id = mPmemFD;
|
|
mRotData.dst.memory_id = mPmemFD;
|
|
mRotData.dst.offset = 0;
|
|
mNumBuffers = num_buffers;
|
|
mCurrentItem = 0;
|
|
for (int i = 0; i < num_buffers; i++)
|
|
mRotOffset[i] = i * mPmemOffset;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool OverlayDataChannel::startDataChannel(int ovid, int rotid, int size,
|
|
int fbnum, bool norot,
|
|
bool uichannel, int num_buffers) {
|
|
memset(&mOvData, 0, sizeof(mOvData));
|
|
memset(&mOvDataRot, 0, sizeof(mOvDataRot));
|
|
memset(&mRotData, 0, sizeof(mRotData));
|
|
mNoRot = norot;
|
|
mOvData.data.memory_id = -1;
|
|
mOvData.id = ovid;
|
|
mOvDataRot = mOvData;
|
|
mPmemOffset = size;
|
|
mRotData.session_id = rotid;
|
|
mNumBuffers = 0;
|
|
mCurrentItem = 0;
|
|
|
|
return openDevices(fbnum, uichannel, num_buffers);
|
|
}
|
|
|
|
bool OverlayDataChannel::closeDataChannel() {
|
|
if (!isChannelUP())
|
|
return true;
|
|
|
|
if (!mNoRot && mRotFD > 0) {
|
|
munmap(mPmemAddr, mPmemOffset * mNumBuffers);
|
|
close(mPmemFD);
|
|
mPmemFD = -1;
|
|
close(mRotFD);
|
|
mRotFD = -1;
|
|
}
|
|
close(mFD);
|
|
mFD = -1;
|
|
memset(&mOvData, 0, sizeof(mOvData));
|
|
memset(&mOvDataRot, 0, sizeof(mOvDataRot));
|
|
memset(&mRotData, 0, sizeof(mRotData));
|
|
|
|
mNumBuffers = 0;
|
|
mCurrentItem = 0;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool OverlayDataChannel::setFd(int fd) {
|
|
mOvData.data.memory_id = fd;
|
|
return true;
|
|
}
|
|
|
|
bool OverlayDataChannel::queueBuffer(uint32_t offset) {
|
|
if ((!isChannelUP()) || mOvData.data.memory_id < 0) {
|
|
reportError("QueueBuffer failed, either channel is not set or no file descriptor to read from");
|
|
return false;
|
|
}
|
|
|
|
msmfb_overlay_data *odPtr;
|
|
mOvData.data.offset = offset;
|
|
odPtr = &mOvData;
|
|
|
|
if (!mNoRot) {
|
|
mRotData.src.memory_id = mOvData.data.memory_id;
|
|
mRotData.src.offset = offset;
|
|
mRotData.dst.offset = (mRotData.dst.offset) ? 0 : mPmemOffset;
|
|
mRotData.dst.offset = mRotOffset[mCurrentItem];
|
|
mCurrentItem = (mCurrentItem + 1) % mNumBuffers;
|
|
|
|
int result = ioctl(mRotFD,
|
|
MSM_ROTATOR_IOCTL_ROTATE, &mRotData);
|
|
|
|
if (!result) {
|
|
mOvDataRot.data.offset = (uint32_t) mRotData.dst.offset;
|
|
odPtr = &mOvDataRot;
|
|
}
|
|
else if (max_num_buffers == mNumBuffers) {
|
|
reportError("Rotator failed..");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (ioctl(mFD, MSMFB_OVERLAY_PLAY, odPtr)) {
|
|
reportError("overlay play failed.");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool OverlayDataChannel::getCropS3D(overlay_rect *inRect, int channel, int format,
|
|
overlay_rect *rect) {
|
|
|
|
bool ret;
|
|
// for the 3D usecase extract L and R channels from a frame
|
|
if ( (format & HAL_3D_IN_SIDE_BY_SIDE_HALF_L_R) ||
|
|
(format & HAL_3D_IN_SIDE_BY_SIDE_HALF_R_L) ) {
|
|
if(channel == 0) {
|
|
rect->x = 0;
|
|
rect->y = 0;
|
|
rect->width = inRect->width/2;
|
|
rect->height = inRect->height;
|
|
} else {
|
|
rect->x = inRect->width/2;
|
|
rect->y = 0;
|
|
rect->width = inRect->width/2;
|
|
rect->height = inRect->height;
|
|
}
|
|
} else if (format & HAL_3D_IN_TOP_BOTTOM) {
|
|
if(channel == 0) {
|
|
rect->x = 0;
|
|
rect->y = 0;
|
|
rect->width = inRect->width;
|
|
rect->height = inRect->height/2;
|
|
} else {
|
|
rect->x = 0;
|
|
rect->y = inRect->height/2;
|
|
rect->width = inRect->width;
|
|
rect->height = inRect->height/2;
|
|
}
|
|
} else if (format & HAL_3D_IN_INTERLEAVE) {
|
|
//TBD
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool OverlayDataChannel::setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h) {
|
|
if (!isChannelUP()) {
|
|
reportError("Channel not set");
|
|
return false;
|
|
}
|
|
|
|
mdp_overlay ov;
|
|
ov.id = mOvData.id;
|
|
if (ioctl(mFD, MSMFB_OVERLAY_GET, &ov)) {
|
|
reportError("setCrop, overlay GET failed");
|
|
return false;
|
|
}
|
|
|
|
if (ov.user_data[0] == MDP_ROT_90) {
|
|
if (ov.src.width < (y + h))
|
|
return false;
|
|
|
|
uint32_t tmp = x;
|
|
x = ov.src.width - (y + h);
|
|
y = tmp;
|
|
|
|
tmp = w;
|
|
w = h;
|
|
h = tmp;
|
|
}
|
|
else if (ov.user_data[0] == MDP_ROT_270) {
|
|
if (ov.src.height < (x + w))
|
|
return false;
|
|
|
|
uint32_t tmp = y;
|
|
y = ov.src.height - (x + w);
|
|
x = tmp;
|
|
|
|
tmp = w;
|
|
w = h;
|
|
h = tmp;
|
|
}
|
|
else if(ov.user_data[0] == MDP_ROT_180) {
|
|
if ((ov.src.height < (y + h)) || (ov.src.width < ( x + w)))
|
|
return false;
|
|
|
|
x = ov.src.width - (x + w);
|
|
y = ov.src.height - (y + h);
|
|
}
|
|
|
|
|
|
if ((ov.src_rect.x == x) &&
|
|
(ov.src_rect.y == y) &&
|
|
(ov.src_rect.w == w) &&
|
|
(ov.src_rect.h == h))
|
|
return true;
|
|
|
|
ov.src_rect.x = x;
|
|
ov.src_rect.y = y;
|
|
ov.src_rect.w = w;
|
|
ov.src_rect.h = h;
|
|
|
|
/* Scaling of upto a max of 8 times supported */
|
|
if(ov.dst_rect.w >(ov.src_rect.w * HW_OVERLAY_MAGNIFICATION_LIMIT)){
|
|
ov.dst_rect.w = HW_OVERLAY_MAGNIFICATION_LIMIT * ov.src_rect.w;
|
|
}
|
|
if(ov.dst_rect.h >(ov.src_rect.h * HW_OVERLAY_MAGNIFICATION_LIMIT)) {
|
|
ov.dst_rect.h = HW_OVERLAY_MAGNIFICATION_LIMIT * ov.src_rect.h;
|
|
}
|
|
if (ioctl(mFD, MSMFB_OVERLAY_SET, &ov)) {
|
|
reportError("setCrop, overlay set error");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|