diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp index 1029ac4..81ccad2 100644 --- a/libhwcomposer/hwc.cpp +++ b/libhwcomposer/hwc.cpp @@ -29,6 +29,7 @@ #include "hwc_video.h" #include "hwc_uimirror.h" #include "hwc_copybit.h" +#include "hwc_external.h" using namespace qhwc; @@ -107,6 +108,10 @@ static int hwc_eventControl(struct hwc_composer_device* dev, case HWC_EVENT_VSYNC: if(ioctl(m->framebuffer->fd, MSMFB_OVERLAY_VSYNC_CTRL, &enabled) < 0) ret = -errno; + + if(ctx->mExtDisplay->getExternalDisplay()) { + ret = ctx->mExtDisplay->enableHDMIVsync(enabled); + } break; default: ret = -EINVAL; @@ -149,6 +154,8 @@ static int hwc_set(hwc_composer_device_t *dev, CopyBit::draw(ctx, list, (EGLDisplay)dpy, (EGLSurface)sur); EGLBoolean sucess = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur); UIMirrorOverlay::draw(ctx); + if(ctx->mExtDisplay->getExternalDisplay()) + ctx->mExtDisplay->commit(); } else { ctx->mOverlay->setState(ovutils::OV_CLOSED); ctx->qbuf->unlockAllPrevious(); diff --git a/libhwcomposer/hwc_external.cpp b/libhwcomposer/hwc_external.cpp index 3507134..b5e1e89 100644 --- a/libhwcomposer/hwc_external.cpp +++ b/libhwcomposer/hwc_external.cpp @@ -42,22 +42,21 @@ namespace qhwc { #define DEVICE_ROOT "/sys/devices/virtual/graphics" #define DEVICE_NODE "fb1" -#define SYSFS_CONNECTED DEVICE_ROOT "/" DEVICE_NODE "/connected" #define SYSFS_EDID_MODES DEVICE_ROOT "/" DEVICE_NODE "/edid_modes" #define SYSFS_HPD DEVICE_ROOT "/" DEVICE_NODE "/hpd" -ExternalDisplay::ExternalDisplay(hwc_context_t* ctx):fd(-1), - mCurrentID(-1), mHwcContext(ctx) +ExternalDisplay::ExternalDisplay(hwc_context_t* ctx):mFd(-1), + mCurrentMode(-1), mHwcContext(ctx) { + memset(&mVInfo, 0, sizeof(mVInfo)); //Enable HPD for HDMI writeHPDOption(1); } ExternalDisplay::~ExternalDisplay() { - if (fd > 0) - close(fd); + closeFrameBuffer(); } struct disp_mode_timing_type { @@ -143,7 +142,7 @@ static struct disp_mode_timing_type supported_video_mode_lut[] = { {m1920x1080p30_16_9, 1920, 1080, 88, 44, 148, 4, 5, 36, 74250, false}, }; -int ExternalDisplay::parseResolution(char* edidStr, int* edidModes, int len) +int ExternalDisplay::parseResolution(char* edidStr, int* edidModes) { char delim = ','; int count = 0; @@ -152,27 +151,25 @@ int ExternalDisplay::parseResolution(char* edidStr, int* edidModes, int len) // Ex: 16,4,5,3,32,34,1 // Parse this string to get mode(int) start = (char*) edidStr; - for(int i=0; i 0) { // GEt EDID modes from the EDID strings - mModeCount = parseResolution(mEDIDs, mEDIDModes, len); + mModeCount = parseResolution(mEDIDs, mEDIDModes); ALOGD_IF(DEBUG, "%s: mModeCount = %d", __FUNCTION__, mModeCount); } @@ -202,15 +199,33 @@ bool ExternalDisplay::readResolution() bool ExternalDisplay::openFramebuffer() { - if (fd == -1) { - fd = open("/dev/graphics/fb1", O_RDWR); - if (fd < 0) - ALOGD_IF(DEBUG, "%s: /dev/graphics/fb1 not available" - "\n", __FUNCTION__); + if (mFd == -1) { + mFd = open("/dev/graphics/fb1", O_RDWR); + if (mFd < 0) + ALOGE("%s: /dev/graphics/fb1 not available", __FUNCTION__); } - return (fd > 0); + return (mFd > 0); } +bool ExternalDisplay::closeFrameBuffer() +{ + int ret = 0; + if(mFd > 0) { + ret = close(mFd); + mFd = -1; + } + return (ret == 0); +} + +// clears the vinfo, edid, best modes +void ExternalDisplay::resetInfo() +{ + memset(&mVInfo, 0, sizeof(mVInfo)); + memset(mEDIDs, 0, sizeof(mEDIDs)); + memset(mEDIDModes, 0, sizeof(mEDIDModes)); + mModeCount = 0; + mCurrentMode = -1; +} int ExternalDisplay::getModeOrder(int mode) { @@ -278,10 +293,23 @@ inline bool ExternalDisplay::isValidMode(int ID) void ExternalDisplay::setResolution(int ID) { struct fb_var_screeninfo info; + int ret = 0; if (!openFramebuffer()) return; + 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", __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); //If its a valid mode and its a new ID - update var_screeninfo - if ((isValidMode(ID)) && mCurrentID != ID) { + if ((isValidMode(ID)) && mCurrentMode != ID) { const struct disp_mode_timing_type *mode = &supported_video_mode_lut[0]; unsigned count = sizeof(supported_video_mode_lut)/sizeof @@ -292,30 +320,38 @@ void ExternalDisplay::setResolution(int ID) if (cur->video_format == ID) mode = cur; } - ioctl(fd, FBIOGET_VSCREENINFO, &info); - ALOGD_IF(DEBUG, "%s: GET Info", __FUNCTION__, - info.reserved[3], info.xres, info.yres, - info.right_margin, info.hsync_len, info.left_margin, - info.lower_margin, info.vsync_len, info.upper_margin, - info.pixclock/1000/1000); - mode->set_info(info); - ALOGD_IF(DEBUG, "%s: SET Info Infoset_info(mVInfo); + ALOGD_IF(DEBUG, "%s: SET Info Info", __FUNCTION__, ID, - info.reserved[3], info.xres, info.yres, - info.right_margin, info.hsync_len, info.left_margin, - info.lower_margin, info.vsync_len, info.upper_margin, - info.pixclock/1000/1000); - info.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_ALL | FB_ACTIVATE_FORCE; - ioctl(fd, FBIOPUT_VSCREENINFO, &info); - mCurrentID = ID; + 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); + 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)); + } + mCurrentMode = ID; } //Powerup - ioctl(fd, FBIOBLANK, FB_BLANK_UNBLANK); - ioctl(fd, FBIOGET_VSCREENINFO, &info); + ret = ioctl(mFd, FBIOBLANK, FB_BLANK_UNBLANK); + if(ret < 0) { + ALOGD("In %s: FBIOBLANK failed Err Str = %s", __FUNCTION__, + strerror(errno)); + } + ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo); + if(ret < 0) { + ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__, + strerror(errno)); + } //Pan_Display - ioctl(fd, FBIOPAN_DISPLAY, &info); - property_set("hw.hdmiON", "1"); + ret = ioctl(mFd, FBIOPAN_DISPLAY, &mVInfo); + if(ret < 0) { + ALOGD("In %s: FBIOPAN_DISPLAY failed Err Str = %s", __FUNCTION__, + strerror(errno)); + } } @@ -324,7 +360,7 @@ int ExternalDisplay::getExternalDisplay() const return mExternalDisplay; } -void ExternalDisplay::setExternalDisplayStatus(int connected) +void ExternalDisplay::setExternalDisplay(int connected) { hwc_context_t* ctx = mHwcContext; @@ -336,15 +372,23 @@ void ExternalDisplay::setExternalDisplayStatus(int connected) //Get the best mode and set // TODO: DO NOT call this for WFD setResolution(getBestMode()); + //enable hdmi vsync + enableHDMIVsync(connected); } else { - close(fd); + // Disable the hdmi vsync + enableHDMIVsync(connected); + closeFrameBuffer(); + resetInfo(); } // Store the external display mExternalDisplay = connected; + const char* prop = (connected) ? "1" : "0"; + // set system property + property_set("hw.hdmiON", prop); //Invalidate hwc_procs* proc = (hwc_procs*)ctx->device.reserved_proc[0]; if(!proc) { - ALOGD_IF(DEBUG, "%s: HWC proc not registered", + ALOGE("%s: HWC proc not registered", __FUNCTION__); } else { /* Trigger redraw */ @@ -360,8 +404,9 @@ bool ExternalDisplay::writeHPDOption(int userOption) const bool ret = true; int hdmiHPDFile = open(SYSFS_HPD,O_RDWR, 0); if (hdmiHPDFile < 0) { - ALOGD_IF(DEBUG, "%s: state file '%s' not found : ret%d" - "err str: %s", __FUNCTION__, SYSFS_HPD, hdmiHPDFile, strerror(errno)); + ALOGE("%s: state file '%s' not found : ret%d" + "err str: %s", __FUNCTION__, SYSFS_HPD, hdmiHPDFile, + strerror(errno)); ret = false; } else { int err = -1; @@ -372,7 +417,7 @@ bool ExternalDisplay::writeHPDOption(int userOption) const else err = write(hdmiHPDFile, "0" , 2); if (err <= 0) { - ALOGD_IF(DEBUG, "%s: file write failed '%s'", + ALOGE("%s: file write failed '%s'", __FUNCTION__, SYSFS_HPD); ret = false; } @@ -380,5 +425,30 @@ bool ExternalDisplay::writeHPDOption(int userOption) const } return ret; } + +bool ExternalDisplay::commit() +{ + if(mFd == -1) { + return false; + } else if(ioctl(mFd, FBIOPUT_VSCREENINFO, &mVInfo) == -1) { + ALOGE("%s: FBIOPUT_VSCREENINFO failed, str: %s", __FUNCTION__, + strerror(errno)); + return false; + } + return true; +} + +int ExternalDisplay::enableHDMIVsync(int enable) +{ + if(mFd > 0) { + int ret = ioctl(mFd, MSMFB_OVERLAY_VSYNC_CTRL, &enable); + if (ret<0) { + ALOGE("%s: enabling HDMI vsync failed, str: %s", __FUNCTION__, + strerror(errno)); + } + } + return -errno; +} + }; diff --git a/libhwcomposer/hwc_external.h b/libhwcomposer/hwc_external.h index 9e5f455..55773c0 100644 --- a/libhwcomposer/hwc_external.h +++ b/libhwcomposer/hwc_external.h @@ -21,6 +21,8 @@ #ifndef HWC_EXTERNAL_DISPLAY_H #define HWC_EXTERNAL_DISPLAY_H +#include + struct hwc_context_t; namespace qhwc { @@ -43,26 +45,31 @@ class ExternalDisplay ExternalDisplay(hwc_context_t* ctx); ~ExternalDisplay(); int getExternalDisplay() const; - void setExternalDisplayStatus(int connected); + void setExternalDisplay(int connected); + bool commit(); + int enableHDMIVsync(int enable); private: bool readResolution(); - int parseResolution(char* edidStr, int* edidModes, int len); + int parseResolution(char* edidStr, int* edidModes); void setResolution(int ID); bool openFramebuffer(); + bool closeFrameBuffer(); bool writeHPDOption(int userOption) const; bool isValidMode(int ID); void handleUEvent(char* str, int len); int getModeOrder(int mode); int getBestMode(); + void resetInfo(); - int fd; + int mFd; int mExternalDisplay; - int mCurrentID; + int mCurrentMode; char mEDIDs[128]; int mEDIDModes[64]; int mModeCount; hwc_context_t *mHwcContext; + fb_var_screeninfo mVInfo; }; }; //qhwc diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp index a1df74b..f58fbd3 100644 --- a/libhwcomposer/hwc_uevents.cpp +++ b/libhwcomposer/hwc_uevents.cpp @@ -30,21 +30,30 @@ namespace qhwc { -const char* MSMFB_DEVICE_CHANGE = "change@/devices/virtual/graphics/fb0"; +const char* MSMFB_DEVICE_FB0 = "change@/devices/virtual/graphics/fb0"; +const char* MSMFB_DEVICE_FB1 = "change@/devices/virtual/graphics/fb1"; const char* MSMFB_HDMI_NODE = "fb1"; static void handle_uevent(hwc_context_t* ctx, const char* udata, int len) { - int vsync; + int vsync = 0; char* hdmi; int64_t timestamp = 0; const char *str = udata; - hwc_procs* proc = reinterpret_cast(ctx->device.reserved_proc[0]); + hwc_procs* proc = (hwc_procs*)ctx->device.reserved_proc[0]; + int hdmiconnected = ctx->mExtDisplay->getExternalDisplay(); - vsync = !strncmp(str, MSMFB_DEVICE_CHANGE, strlen(MSMFB_DEVICE_CHANGE)); - hdmi = strcasestr(str, MSMFB_HDMI_NODE); - if(!vsync && !hdmi) + if(!strcasestr(str, "@/devices/virtual/graphics/fb")) { + ALOGD_IF(DEBUG, "%s: Not Ext Disp Event ", __FUNCTION__); return; + } + + if(hdmiconnected) + vsync = !strncmp(str, MSMFB_DEVICE_FB1, strlen(MSMFB_DEVICE_FB1)); + else + vsync = !strncmp(str, MSMFB_DEVICE_FB0, strlen(MSMFB_DEVICE_FB0)); + + hdmi = strcasestr(str, MSMFB_HDMI_NODE); if(vsync) { str += strlen(str) + 1; while(*str) { @@ -56,6 +65,7 @@ static void handle_uevent(hwc_context_t* ctx, const char* udata, int len) if(str - udata >= len) break; } + return; } if(hdmi) { @@ -72,7 +82,7 @@ static void handle_uevent(hwc_context_t* ctx, const char* udata, int len) } else if(!(strncmp(str,"offline@",strlen("offline@")))) { connected = 0; } - ctx->mExtDisplay->setExternalDisplayStatus(connected); + ctx->mExtDisplay->setExternalDisplay(connected); } } diff --git a/libhwcomposer/hwc_uimirror.cpp b/libhwcomposer/hwc_uimirror.cpp index 9cf91af..3bbe30e 100644 --- a/libhwcomposer/hwc_uimirror.cpp +++ b/libhwcomposer/hwc_uimirror.cpp @@ -33,7 +33,7 @@ namespace qhwc { int getDeviceOrientation(hwc_context_t* ctx, hwc_layer_list_t *list) { int orientation = list->hwLayers[0].transform; if(!ctx) { - ALOGD_IF(HWC_UI_MIRROR, "In %s: ctx is NULL!!", __FUNCTION__); + ALOGE("In %s: ctx is NULL!!", __FUNCTION__); return -1; } for(size_t i=0; i <= list->numHwLayers;i++ ) @@ -60,6 +60,12 @@ bool UIMirrorOverlay::sIsUiMirroringOn = false; bool UIMirrorOverlay::prepare(hwc_context_t *ctx, hwc_layer_list_t *list) { sState = ovutils::OV_CLOSED; sIsUiMirroringOn = false; + + if(!ctx->hasOverlay) { + ALOGD_IF(HWC_UI_MIRROR, "%s, this hw doesnt support mirroring", + __FUNCTION__); + return false; + } // If external display is connected if(ctx->mExtDisplay->getExternalDisplay()) { sState = ovutils::OV_UI_MIRROR; @@ -95,7 +101,7 @@ bool UIMirrorOverlay::configure(hwc_context_t *ctx, hwc_layer_list_t *list) dest = ovutils::OV_PIPE0; } - ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_MEMORY_ID_TYPE_FB; + ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE; /* - TODO: Secure content if (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) { ovutils::setMdpFlags(mdpFlags, @@ -160,20 +166,20 @@ bool UIMirrorOverlay::draw(hwc_context_t *ctx) if (!ov.queueBuffer(m->framebuffer->fd, m->currentOffset, ovutils::OV_PIPE0)) { ALOGE("%s: queueBuffer failed for external", __FUNCTION__); + ret = false; } break; case ovutils::OV_2D_TRUE_UI_MIRROR: if (!ov.queueBuffer(m->framebuffer->fd, m->currentOffset, ovutils::OV_PIPE2)) { ALOGE("%s: queueBuffer failed for external", __FUNCTION__); + ret = false; } break; default: break; } - // TODO: - // Call PANDISPLAY ioctl here to kickoff } return ret; }