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