diff --git a/libgralloc/fb_priv.h b/libgralloc/fb_priv.h index 83b941a..48e5669 100644 --- a/libgralloc/fb_priv.h +++ b/libgralloc/fb_priv.h @@ -25,11 +25,6 @@ #define NO_SURFACEFLINGER_SWAPINTERVAL #define COLOR_FORMAT(x) (x & 0xFFF) // Max range for colorFormats is 0 - FFF -enum hdmi_mirroring_state { - HDMI_NO_MIRRORING, - HDMI_UI_MIRRORING, -}; - struct private_handle_t; enum { @@ -54,21 +49,11 @@ struct private_module_t { float ydpi; float fps; uint32_t swapInterval; -#if defined(__cplusplus) && defined(HDMI_DUAL_DISPLAY) - int orientation; - int videoOverlay; // VIDEO_OVERLAY - 2D or 3D - int secureVideoOverlay; // VideoOverlay is secure uint32_t currentOffset; - int enableHDMIOutput; // holds the type of external display - bool trueMirrorSupport; - bool exitHDMIUILoop; - float actionsafeWidthRatio; - float actionsafeHeightRatio; - bool hdmiStateChanged; - hdmi_mirroring_state hdmiMirroringState; - pthread_mutex_t overlayLock; - pthread_cond_t overlayPost; -#endif + bool fbPostDone; + pthread_mutex_t fbPostLock; + //Condition to inform HWC that fb_post called + pthread_cond_t fbPostCond; }; diff --git a/libgralloc/framebuffer.cpp b/libgralloc/framebuffer.cpp index 27384f1..9d974b4 100644 --- a/libgralloc/framebuffer.cpp +++ b/libgralloc/framebuffer.cpp @@ -43,9 +43,6 @@ #include #include -#include "overlay.h" -namespace ovutils = overlay::utils; - #define EVEN_OUT(x) if (x & 0x0001) {x--;} /** min of int a, b */ static inline int min(int a, int b) { @@ -101,402 +98,6 @@ static int fb_setUpdateRect(struct framebuffer_device_t* dev, return 0; } -#if defined(HDMI_DUAL_DISPLAY) -static int closeHDMIChannel(private_module_t* m) -{ - // XXX - when enabling HDMI -#if 0 - Overlay* pTemp = m->pobjOverlay; - if(pTemp != NULL) - pTemp->closeChannel(); -#endif - return 0; -} - -// XXX - Complete when enabling HDMI -#if 0 -static void getSecondaryDisplayDestinationInfo(private_module_t* m, overlay_rect& - rect, int& orientation) -{ - Overlay* pTemp = m->pobjOverlay; - int width = pTemp->getFBWidth(); - int height = pTemp->getFBHeight(); - int fbwidth = m->info.xres, fbheight = m->info.yres; - rect.x = 0; rect.y = 0; - rect.w = width; rect.h = height; - int rot = m->orientation; - switch(rot) { - // ROT_0 - case 0: - // ROT_180 - case HAL_TRANSFORM_ROT_180: - pTemp->getAspectRatioPosition(fbwidth, fbheight, - &rect); - if(rot == HAL_TRANSFORM_ROT_180) - orientation = HAL_TRANSFORM_ROT_180; - else - orientation = 0; - break; - // ROT_90 - case HAL_TRANSFORM_ROT_90: - // ROT_270 - case HAL_TRANSFORM_ROT_270: - //Calculate the Aspectratio for the UI - //in the landscape mode - //Width and height will be swapped as there - //is rotation - pTemp->getAspectRatioPosition(fbheight, fbwidth, - &rect); - - if(rot == HAL_TRANSFORM_ROT_90) - orientation = HAL_TRANSFORM_ROT_270; - else if(rot == HAL_TRANSFORM_ROT_270) - orientation = HAL_TRANSFORM_ROT_90; - break; - } - return; -} -#endif - -/* Determine overlay state based on whether hardware supports true UI - mirroring and whether video is playing or not */ -static ovutils::eOverlayState getOverlayState(struct private_module_t* module) -{ - overlay2::Overlay& ov = *(Overlay::getInstance()); - - // Default to existing state - ovutils::eOverlayState state = ov.getState(); - - // Sanity check - if (!module) { - ALOGE("%s: NULL module", __FUNCTION__); - return state; - } - - // Check if video is playing or not - if (module->videoOverlay) { - // Video is playing, check if hardware supports true UI mirroring - if (module->trueMirrorSupport) { - // True UI mirroring is supported by hardware - if (ov.getState() == ovutils::OV_2D_VIDEO_ON_PANEL) { - // Currently playing 2D video - state = ovutils::OV_2D_TRUE_UI_MIRROR; - } else if (ov.getState() == ovutils::OV_3D_VIDEO_ON_2D_PANEL) { - // Currently playing M3D video - // FIXME: Support M3D true UI mirroring - state = ovutils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV; - } - } else { - // True UI mirroring is not supported by hardware - if (ov.getState() == ovutils::OV_2D_VIDEO_ON_PANEL) { - // Currently playing 2D video - state = ovutils::OV_2D_VIDEO_ON_PANEL_TV; - } else if (ov.getState() == ovutils::OV_3D_VIDEO_ON_2D_PANEL) { - // Currently playing M3D video - state = ovutils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV; - } - } - } else { - // Video is not playing, true UI mirroring support is irrelevant - state = ovutils::OV_UI_MIRROR; - } - - return state; -} - -/* Set overlay state */ -static void setOverlayState(ovutils::eOverlayState state) -{ - overlay2::Overlay& ov = *(Overlay::getInstance()); - ov.setState(state); -} - -static void *hdmi_ui_loop(void *ptr) -{ - private_module_t* m = reinterpret_cast(ptr); - while (1) { - pthread_mutex_lock(&m->overlayLock); - while(!(m->hdmiStateChanged)) - pthread_cond_wait(&(m->overlayPost), &(m->overlayLock)); - - m->hdmiStateChanged = false; - if (m->exitHDMIUILoop) { - pthread_mutex_unlock(&m->overlayLock); - return NULL; - } - - // No need to mirror UI if HDMI is not on - if (!m->enableHDMIOutput) { - ALOGE_IF(FB_DEBUG, "%s: hdmi not ON", __FUNCTION__); - pthread_mutex_unlock(&m->overlayLock); - continue; - } - - overlay2::OverlayMgr* ovMgr = - overlay2::OverlayMgrSingleton::getOverlayMgr(); - overlay2::Overlay& ov = ovMgr->ov(); - - // Set overlay state - ovutils::eOverlayState state = getOverlayState(m); - setOverlayState(state); - - // Determine the RGB pipe for UI depending on the state - ovutils::eDest dest = ovutils::OV_PIPE_ALL; - if (state == ovutils::OV_2D_TRUE_UI_MIRROR) { - // True UI mirroring state: external RGB pipe is OV_PIPE2 - dest = ovutils::OV_PIPE2; - } else if (state == ovutils::OV_UI_MIRROR) { - // UI-only mirroring state: external RGB pipe is OV_PIPE0 - dest = ovutils::OV_PIPE0; - } else { - // No UI in this case - pthread_mutex_unlock(&m->overlayLock); - continue; - } - - if (m->hdmiMirroringState == HDMI_UI_MIRRORING) { - int alignedW = ALIGN(m->info.xres, 32); - - private_handle_t const* hnd = - reinterpret_cast(m->framebuffer); - unsigned int width = alignedW; - unsigned int height = hnd->height; - unsigned int format = hnd->format; - unsigned int size = hnd->size/m->numBuffers; - - ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE; - // External display connected during secure video playback - // Open secure UI session - // NOTE: when external display is already connected and then secure - // playback is started, we dont have to do anything - if (m->secureVideoOverlay) { - ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_SECURE_OVERLAY_SESSION); - } - - ovutils::Whf whf(width, height, format, size); - ovutils::PipeArgs parg(mdpFlags, - ovutils::OVERLAY_TRANSFORM_0, - whf, - ovutils::ZORDER_0, - ovutils::IS_FG_OFF, - ovutils::ROT_FLAG_ENABLED); - ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg }; - bool ret = ov.setSource(pargs, dest); - if (!ret) { - ALOGE("%s setSource failed", __FUNCTION__); - } - - // we need to communicate m->orientation that will get some - // modifications within setParameter func. - // FIXME that is ugly. - const ovutils::Params prms (ovutils::OVERLAY_TRANSFORM_UI, - m->orientation); - ov.setParameter(prms, dest); - if (!ret) { - ALOGE("%s setParameter failed transform", __FUNCTION__); - } - - // x,y,w,h - ovutils::Dim dcrop(0, 0, m->info.xres, m->info.yres); - ov.setMemoryId(m->framebuffer->fd, dest); - ret = ov.setCrop(dcrop, dest); - if (!ret) { - ALOGE("%s setCrop failed", __FUNCTION__); - } - - ovutils::Dim pdim (m->info.xres, - m->info.yres, - 0, - 0, - m->orientation); - ret = ov.setPosition(pdim, dest); - if (!ret) { - ALOGE("%s setPosition failed", __FUNCTION__); - } - - if (!ov.commit(dest)) { - ALOGE("%s commit fails", __FUNCTION__); - } - - ret = ov.queueBuffer(m->currentOffset, dest); - if (!ret) { - ALOGE("%s queueBuffer failed", __FUNCTION__); - } - } else { - setOverlayState(ovutils::OV_CLOSED); - } - pthread_mutex_unlock(&m->overlayLock); - } - return NULL; -} - -static int fb_videoOverlayStarted(struct framebuffer_device_t* dev, int started) -{ - ALOGE_IF(FB_DEBUG, "%s started=%d", __FUNCTION__, started); - private_module_t* m = reinterpret_cast( - dev->common.module); - pthread_mutex_lock(&m->overlayLock); - if(started != m->videoOverlay) { - m->videoOverlay = started; - m->hdmiStateChanged = true; - if (!m->trueMirrorSupport) { - if (started) { - m->hdmiMirroringState = HDMI_NO_MIRRORING; - ovutils::eOverlayState state = getOverlayState(m); - setOverlayState(state); - } else if (m->enableHDMIOutput) - m->hdmiMirroringState = HDMI_UI_MIRRORING; - } else { - if (m->videoOverlay == VIDEO_3D_OVERLAY_STARTED) { - ALOGE_IF(FB_DEBUG, "3D Video Started, stop mirroring!"); - m->hdmiMirroringState = HDMI_NO_MIRRORING; - ovutils::eOverlayState state = getOverlayState(m); - setOverlayState(state); - } - else if (m->enableHDMIOutput) { - m->hdmiMirroringState = HDMI_UI_MIRRORING; - } - } - } - pthread_mutex_unlock(&m->overlayLock); - return 0; -} - -static int fb_enableHDMIOutput(struct framebuffer_device_t* dev, int externaltype) -{ - ALOGE_IF(FB_DEBUG, "%s externaltype=%d", __FUNCTION__, externaltype); - private_module_t* m = reinterpret_cast( - dev->common.module); - pthread_mutex_lock(&m->overlayLock); - //Check if true mirroring can be supported - m->trueMirrorSupport = ovutils::FrameBufferInfo::getInstance()->supportTrueMirroring(); - m->enableHDMIOutput = externaltype; - if(externaltype) { - if (m->trueMirrorSupport) { - m->hdmiMirroringState = HDMI_UI_MIRRORING; - } else { - if(!m->videoOverlay) - m->hdmiMirroringState = HDMI_UI_MIRRORING; - } - } else if (!externaltype) { - // Either HDMI is disconnected or suspend occurred - m->hdmiMirroringState = HDMI_NO_MIRRORING; - ovutils::eOverlayState state = getOverlayState(m); - setOverlayState(state); - } - m->hdmiStateChanged = true; - pthread_cond_signal(&(m->overlayPost)); - pthread_mutex_unlock(&m->overlayLock); - return 0; -} - -static int fb_orientationChanged(struct framebuffer_device_t* dev, int orientation) -{ - private_module_t* m = reinterpret_cast( - dev->common.module); - pthread_mutex_lock(&m->overlayLock); - neworientation = orientation; - pthread_mutex_unlock(&m->overlayLock); - return 0; -} - -static int handle_open_secure_start(private_module_t* m) { - pthread_mutex_lock(&m->overlayLock); - m->hdmiMirroringState = HDMI_NO_MIRRORING; - m->secureVideoOverlay = true; - pthread_mutex_unlock(&m->overlayLock); - return 0; -} - -static int handle_open_secure_end(private_module_t* m) { - pthread_mutex_lock(&m->overlayLock); - if (m->enableHDMIOutput) { - if (m->trueMirrorSupport) { - m->hdmiMirroringState = HDMI_UI_MIRRORING; - } else if(!m->videoOverlay) { - m->hdmiMirroringState = HDMI_UI_MIRRORING; - } - m->hdmiStateChanged = true; - pthread_cond_signal(&(m->overlayPost)); - } - pthread_mutex_unlock(&m->overlayLock); - return 0; -} - -static int handle_close_secure_start(private_module_t* m) { - pthread_mutex_lock(&m->overlayLock); - m->hdmiMirroringState = HDMI_NO_MIRRORING; - m->secureVideoOverlay = false; - pthread_mutex_unlock(&m->overlayLock); - return 0; -} - -static int handle_close_secure_end(private_module_t* m) { - pthread_mutex_lock(&m->overlayLock); - if (m->enableHDMIOutput) { - if (m->trueMirrorSupport) { - m->hdmiMirroringState = HDMI_UI_MIRRORING; - } else if(!m->videoOverlay) { - m->hdmiMirroringState = HDMI_UI_MIRRORING; - } - m->hdmiStateChanged = true; - pthread_cond_signal(&(m->overlayPost)); - } - pthread_mutex_unlock(&m->overlayLock); - return 0; -} -#endif - - - -/* fb_perform - used to add custom event and handle them in fb HAL - * Used for external display related functions as of now - */ -static int fb_perform(struct framebuffer_device_t* dev, int event, int value) -{ - private_module_t* m = reinterpret_cast( - dev->common.module); - switch(event) { -#if defined(HDMI_DUAL_DISPLAY) - case EVENT_EXTERNAL_DISPLAY: - fb_enableHDMIOutput(dev, value); - break; - case EVENT_VIDEO_OVERLAY: - fb_videoOverlayStarted(dev, value); - break; - case EVENT_ORIENTATION_CHANGE: - fb_orientationChanged(dev, value); - break; - case EVENT_OVERLAY_STATE_CHANGE: - if (value == OVERLAY_STATE_CHANGE_START) { - // When state change starts, get a lock on overlay - pthread_mutex_lock(&m->overlayLock); - } else if (value == OVERLAY_STATE_CHANGE_END) { - // When state change is complete, unlock overlay - pthread_mutex_unlock(&m->overlayLock); - } - break; - case EVENT_OPEN_SECURE_START: - handle_open_secure_start(m); - break; - case EVENT_OPEN_SECURE_END: - handle_open_secure_end(m); - break; - case EVENT_CLOSE_SECURE_START: - handle_close_secure_start(m); - break; - case EVENT_CLOSE_SECURE_END: - handle_close_secure_end(m); - break; -#endif - default: - ALOGE("In %s: UNKNOWN Event = %d!!!", __FUNCTION__, event); - break; - } - return 0; -} - - static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer) { if (private_handle_t::validate(buffer) < 0) @@ -510,6 +111,7 @@ static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer) private_module_t* m = reinterpret_cast(dev->common.module); + if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { genlock_lock_buffer(hnd, GENLOCK_READ_LOCK, GENLOCK_MAX_TIMEOUT); @@ -519,6 +121,14 @@ static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer) } const size_t offset = hnd->base - m->framebuffer->base; + // frame ready to be posted, signal so that hwc can update External + // display + pthread_mutex_lock(&m->fbPostLock); + m->currentOffset = offset; + m->fbPostDone = true; + pthread_cond_signal(&m->fbPostCond); + pthread_mutex_unlock(&m->fbPostLock); + m->info.activate = FB_ACTIVATE_VBL; m->info.yoffset = offset / m->finfo.line_length; if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) { @@ -579,11 +189,12 @@ int mapFrameBufferLocked(struct private_module_t* module) info.yoffset = 0; info.activate = FB_ACTIVATE_NOW; - /* Interpretation of offset for color fields: All offsets are from the right, - * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you - * can use the offset as right argument to <<). A pixel afterwards is a bit - * stream and is written to video memory as that unmodified. This implies - * big-endian byte order if bits_per_pixel is greater than 8. + /* Interpretation of offset for color fields: All offsets are from the + * right, inside a "pixel" value, which is exactly 'bits_per_pixel' wide + * (means: you can use the offset as right argument to <<). A pixel + * afterwards is a bit stream and is written to video memory as that + * unmodified. This implies big-endian byte order if bits_per_pixel is + * greater than 8. */ if(info.bits_per_pixel == 32) { @@ -600,10 +211,11 @@ int mapFrameBufferLocked(struct private_module_t* module) info.transp.offset = 0; info.transp.length = 8; - /* Note: the GL driver does not have a r=8 g=8 b=8 a=0 config, so if we do - * not use the MDP for composition (i.e. hw composition == 0), ask for - * RGBA instead of RGBX. */ - if (property_get("debug.sf.hw", property, NULL) > 0 && atoi(property) == 0) + /* Note: the GL driver does not have a r=8 g=8 b=8 a=0 config, so if we + * do not use the MDP for composition (i.e. hw composition == 0), ask + * for RGBA instead of RGBX. */ + if (property_get("debug.sf.hw", property, NULL) > 0 && + atoi(property) == 0) module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888; else if(property_get("debug.composition.type", property, NULL) > 0 && (strncmp(property, "mdp", 3) == 0)) @@ -627,7 +239,8 @@ int mapFrameBufferLocked(struct private_module_t* module) } //adreno needs 4k aligned offsets. Max hole size is 4096-1 - int size = roundUpToPageSize(info.yres * info.xres * (info.bits_per_pixel/8)); + int size = roundUpToPageSize(info.yres * info.xres * + (info.bits_per_pixel/8)); /* * Request NUM_BUFFERS screens (at least 2 for page flipping) @@ -738,9 +351,9 @@ int mapFrameBufferLocked(struct private_module_t* module) size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres)* module->numBuffers; module->framebuffer = new private_handle_t(fd, fbSize, - private_handle_t::PRIV_FLAGS_USES_PMEM, - BUFFER_TYPE_UI, - module->fbFormat, info.xres, info.yres); + private_handle_t::PRIV_FLAGS_USES_PMEM, + BUFFER_TYPE_UI, + module->fbFormat, info.xres, info.yres); void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (vaddr == MAP_FAILED) { ALOGE("Error mapping the framebuffer (%s)", strerror(errno)); @@ -748,20 +361,10 @@ int mapFrameBufferLocked(struct private_module_t* module) } module->framebuffer->base = intptr_t(vaddr); memset(vaddr, 0, fbSize); - -#if defined(HDMI_DUAL_DISPLAY) - /* Overlay for HDMI*/ - pthread_mutex_init(&(module->overlayLock), NULL); - pthread_cond_init(&(module->overlayPost), NULL); module->currentOffset = 0; - module->exitHDMIUILoop = false; - module->hdmiStateChanged = false; - pthread_t hdmiUIThread; - pthread_create(&hdmiUIThread, NULL, &hdmi_ui_loop, (void *) module); - module->hdmiMirroringState = HDMI_NO_MIRRORING; - module->trueMirrorSupport = false; -#endif - + module->fbPostDone = false; + pthread_mutex_init(&(module->fbPostLock), NULL); + pthread_cond_init(&(module->fbPostCond), NULL); return 0; } @@ -778,14 +381,6 @@ static int mapFrameBuffer(struct private_module_t* module) static int fb_close(struct hw_device_t *dev) { fb_context_t* ctx = (fb_context_t*)dev; -#if defined(HDMI_DUAL_DISPLAY) - private_module_t* m = reinterpret_cast( - ctx->device.common.module); - pthread_mutex_lock(&m->overlayLock); - m->exitHDMIUILoop = true; - pthread_cond_signal(&(m->overlayPost)); - pthread_mutex_unlock(&m->overlayLock); -#endif if (ctx) { free(ctx); } @@ -828,8 +423,10 @@ int fb_device_open(hw_module_t const* module, const char* name, const_cast(dev->device.xdpi) = m->xdpi; const_cast(dev->device.ydpi) = m->ydpi; const_cast(dev->device.fps) = m->fps; - const_cast(dev->device.minSwapInterval) = PRIV_MIN_SWAP_INTERVAL; - const_cast(dev->device.maxSwapInterval) = PRIV_MAX_SWAP_INTERVAL; + const_cast(dev->device.minSwapInterval) = + PRIV_MIN_SWAP_INTERVAL; + const_cast(dev->device.maxSwapInterval) = + PRIV_MAX_SWAP_INTERVAL; const_cast(dev->device.numFramebuffers) = m->numBuffers; if (m->finfo.reserved[0] == 0x5444 && m->finfo.reserved[1] == 0x5055) { diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk index c83c99e..8e04606 100644 --- a/libhwcomposer/Android.mk +++ b/libhwcomposer/Android.mk @@ -6,9 +6,9 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw LOCAL_MODULE_TAGS := optional LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes) LOCAL_SHARED_LIBRARIES := $(common_libs) libEGL liboverlay libgenlock \ - libqdutils + libqdutils libhardware_legacy LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"hwcomposer\" LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) -LOCAL_SRC_FILES := hwc.cpp hwc_video.cpp hwc_utils.cpp - +LOCAL_SRC_FILES := hwc.cpp hwc_video.cpp hwc_utils.cpp \ + hwc_uimirror.cpp hwc_ext_observer.cpp include $(BUILD_SHARED_LIBRARY) diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp index 699e2ac..8aa6e83 100644 --- a/libhwcomposer/hwc.cpp +++ b/libhwcomposer/hwc.cpp @@ -24,6 +24,7 @@ #include "hwc_utils.h" #include "hwc_video.h" +#include "hwc_uimirror.h" using namespace qhwc; @@ -76,11 +77,14 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) if(VideoOverlay::prepare(ctx, list)) { ctx->overlayInUse = true; //Nothing here + } else if(UIMirrorOverlay::prepare(ctx, list)) { + ctx->overlayInUse = true; } else if (0) { //Other features ctx->overlayInUse = true; } } + return 0; } @@ -94,6 +98,7 @@ static int hwc_set(hwc_composer_device_t *dev, if (LIKELY(list)) { VideoOverlay::draw(ctx, list); EGLBoolean sucess = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur); + UIMirrorOverlay::draw(ctx); } else { ctx->mOverlay->setState(ovutils::OV_CLOSED); ctx->qbuf->unlockAllPrevious(); diff --git a/libhwcomposer/hwc_ext_observer.cpp b/libhwcomposer/hwc_ext_observer.cpp new file mode 100644 index 0000000..d79e2f3 --- /dev/null +++ b/libhwcomposer/hwc_ext_observer.cpp @@ -0,0 +1,446 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012, Code Aurora Forum. 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include "hwc_utils.h" +#include "hwc_ext_observer.h" + +namespace qhwc { + +#define EXT_OBSERVER_DEBUG 1 + +#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" + + +android::sp ExtDisplayObserver:: + sExtDisplayObserverInstance(0); + +ExtDisplayObserver::ExtDisplayObserver() : Thread(false), + fd(-1), mCurrentID(-1), mHwcContext(NULL) +{ + //Enable HPD for HDMI + writeHPDOption(1); +} + +ExtDisplayObserver::~ExtDisplayObserver() { + if (fd > 0) + close(fd); +} + +ExtDisplayObserver *ExtDisplayObserver::getInstance() { + ALOGD_IF(EXT_OBSERVER_DEBUG, "%s ", __FUNCTION__); + if(sExtDisplayObserverInstance.get() == NULL) + sExtDisplayObserverInstance = new ExtDisplayObserver(); + return sExtDisplayObserverInstance.get(); +} + +void ExtDisplayObserver::setHwcContext(hwc_context_t* hwcCtx) { + ALOGD_IF(EXT_OBSERVER_DEBUG, "%s", __FUNCTION__); + if(hwcCtx) { + mHwcContext = hwcCtx; + } + return; +} +void ExtDisplayObserver::onFirstRef() { + ALOGD_IF(EXT_OBSERVER_DEBUG, "%s", __FUNCTION__); + run("ExtDisplayObserver", ANDROID_PRIORITY_DISPLAY); +} + +int ExtDisplayObserver::readyToRun() { + //Initialize the uevent + uevent_init(); + ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: success", __FUNCTION__); + return android::NO_ERROR; +} + +void ExtDisplayObserver::handleUEvent(char* str){ + int connected = 0; + // TODO: check for fb2(WFD) driver also + if(!strcasestr(str, DEVICE_NODE)) + { + ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: Not Ext Disp Event ", __FUNCTION__); + return; + } + // Event will be of the form: + // change@/devices/virtual/graphics/fb1 ACTION=change + // DEVPATH=/devices/virtual/graphics/fb1 + // SUBSYSTEM=graphics HDCP_STATE=FAIL MAJOR=29 + // for now just parse the online or offline are important for us. + if(!(strncmp(str,"online@",strlen("online@")))) { + ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: external disp online", __FUNCTION__); + connected = 1; + readResolution(); + //Get the best mode and set + // TODO: DO NOT call this for WFD + setResolution(getBestMode()); + } else if(!(strncmp(str,"offline@",strlen("offline@")))) { + ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: external disp online", __FUNCTION__); + connected = 0; + close(fd); + } + setExternalDisplayStatus(connected); +} + +bool ExtDisplayObserver::threadLoop() +{ + static char uEventString[1024]; + memset(uEventString, 0, sizeof(uEventString)); + int count = uevent_next_event(uEventString, sizeof(uEventString)); + if(count) { + ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: UeventString: %s len = %d", + __FUNCTION__, uEventString, count); + handleUEvent(uEventString); + } + return true; +} + +struct disp_mode_timing_type { + int video_format; + + int active_h; + int active_v; + + int front_porch_h; + int pulse_width_h; + int back_porch_h; + + int front_porch_v; + int pulse_width_v; + int back_porch_v; + + int pixel_freq; + bool interlaced; + + void set_info(struct fb_var_screeninfo &info) const; +}; + +void disp_mode_timing_type::set_info(struct fb_var_screeninfo &info) const +{ + info.reserved[0] = 0; + info.reserved[1] = 0; + info.reserved[2] = 0; + info.reserved[3] = video_format; + + info.xoffset = 0; + info.yoffset = 0; + info.xres = active_h; + info.yres = active_v; + + info.pixclock = pixel_freq*1000; + info.vmode = interlaced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED; + + info.right_margin = front_porch_h; + info.hsync_len = pulse_width_h; + info.left_margin = back_porch_h; + info.lower_margin = front_porch_v; + info.vsync_len = pulse_width_v; + info.upper_margin = back_porch_v; +} + +/* Video formates supported by the HDMI Standard */ +/* Indicates the resolution, pix clock and the aspect ratio */ +#define m640x480p60_4_3 1 +#define m720x480p60_4_3 2 +#define m720x480p60_16_9 3 +#define m1280x720p60_16_9 4 +#define m1920x1080i60_16_9 5 +#define m1440x480i60_4_3 6 +#define m1440x480i60_16_9 7 +#define m1920x1080p60_16_9 16 +#define m720x576p50_4_3 17 +#define m720x576p50_16_9 18 +#define m1280x720p50_16_9 19 +#define m1440x576i50_4_3 21 +#define m1440x576i50_16_9 22 +#define m1920x1080p50_16_9 31 +#define m1920x1080p24_16_9 32 +#define m1920x1080p25_16_9 33 +#define m1920x1080p30_16_9 34 + +static struct disp_mode_timing_type supported_video_mode_lut[] = { + {m640x480p60_4_3, 640, 480, 16, 96, 48, 10, 2, 33, 25200, false}, + {m720x480p60_4_3, 720, 480, 16, 62, 60, 9, 6, 30, 27030, false}, + {m720x480p60_16_9, 720, 480, 16, 62, 60, 9, 6, 30, 27030, false}, + {m1280x720p60_16_9, 1280, 720, 110, 40, 220, 5, 5, 20, 74250, false}, + {m1920x1080i60_16_9, 1920, 540, 88, 44, 148, 2, 5, 5, 74250, false}, + {m1440x480i60_4_3, 1440, 240, 38, 124, 114, 4, 3, 15, 27000, true}, + {m1440x480i60_16_9, 1440, 240, 38, 124, 114, 4, 3, 15, 27000, true}, + {m1920x1080p60_16_9, 1920, 1080, 88, 44, 148, 4, 5, 36, 148500, false}, + {m720x576p50_4_3, 720, 576, 12, 64, 68, 5, 5, 39, 27000, false}, + {m720x576p50_16_9, 720, 576, 12, 64, 68, 5, 5, 39, 27000, false}, + {m1280x720p50_16_9, 1280, 720, 440, 40, 220, 5, 5, 20, 74250, false}, + {m1440x576i50_4_3, 1440, 288, 24, 126, 138, 2, 3, 19, 27000, true}, + {m1440x576i50_16_9, 1440, 288, 24, 126, 138, 2, 3, 19, 27000, true}, + {m1920x1080p50_16_9, 1920, 1080, 528, 44, 148, 4, 5, 36, 148500, false}, + {m1920x1080p24_16_9, 1920, 1080, 638, 44, 148, 4, 5, 36, 74250, false}, + {m1920x1080p25_16_9, 1920, 1080, 528, 44, 148, 4, 5, 36, 74250, false}, + {m1920x1080p30_16_9, 1920, 1080, 88, 44, 148, 4, 5, 36, 74250, false}, +}; +int ExtDisplayObserver::parseResolution(char* edidStr, int* edidModes, int len) +{ + 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; + for(int i=0; i 1 && isspace(mEDIDs[len-1])) + --len; + mEDIDs[len] = 0; + } + } + close(hdmiEDIDFile); + if(len > 0) { + // GEt EDID modes from the EDID strings + mModeCount = parseResolution(mEDIDs, mEDIDModes, len); + ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: mModeCount = %d", __FUNCTION__, + mModeCount); + } + + return (strlen(mEDIDs) > 0); +} + +bool ExtDisplayObserver::openFramebuffer() +{ + if (fd == -1) { + fd = open("/dev/graphics/fb1", O_RDWR); + if (fd < 0) + ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: /dev/graphics/fb1 not available" + "\n", __FUNCTION__); + } + return (fd > 0); +} + + +int ExtDisplayObserver::getModeOrder(int mode) +{ + switch (mode) { + default: + case m1440x480i60_4_3: + return 1; // 480i 4:3 + case m1440x480i60_16_9: + return 2; // 480i 16:9 + case m1440x576i50_4_3: + return 3; // i576i 4:3 + case m1440x576i50_16_9: + return 4; // 576i 16:9 + case m640x480p60_4_3: + return 5; // 640x480 4:3 + case m720x480p60_4_3: + return 6; // 480p 4:3 + case m720x480p60_16_9: + return 7; // 480p 16:9 + case m720x576p50_4_3: + return 8; // 576p 4:3 + case m720x576p50_16_9: + return 9; // 576p 16:9 + case m1920x1080i60_16_9: + return 10; // 1080i 16:9 + case m1280x720p50_16_9: + return 11; // 720p@50Hz + case m1280x720p60_16_9: + return 12; // 720p@60Hz + case m1920x1080p24_16_9: + return 13; //1080p@24Hz + case m1920x1080p25_16_9: + return 14; //108-p@25Hz + case m1920x1080p30_16_9: + return 15; //1080p@30Hz + case m1920x1080p50_16_9: + return 16; //1080p@50Hz + case m1920x1080p60_16_9: + return 17; //1080p@60Hz + } +} + +// Get the best mode for the current HD TV +int ExtDisplayObserver::getBestMode() { + int bestOrder = 0; + int bestMode = m640x480p60_4_3; + + // for all the edid read, get the best mode + for(int i = 0; i < mModeCount; i++) { + int mode = mEDIDModes[i]; + int order = getModeOrder(mode); + if (order > bestOrder) { + bestOrder = order; + bestMode = mode; + } + } + return bestMode; + } + +inline bool ExtDisplayObserver::isValidMode(int ID) +{ + return ((ID >= m640x480p60_4_3) && (ID <= m1920x1080p30_16_9)); +} + +void ExtDisplayObserver::setResolution(int ID) +{ + struct fb_var_screeninfo info; + if (!openFramebuffer()) + return; + //If its a valid mode and its a new ID - update var_screeninfo + if ((isValidMode(ID)) && mCurrentID != ID) { + const struct disp_mode_timing_type *mode = + &supported_video_mode_lut[0]; + unsigned count = sizeof(supported_video_mode_lut)/sizeof + (*supported_video_mode_lut); + for (unsigned int i = 0; i < count; ++i) { + const struct disp_mode_timing_type *cur = + &supported_video_mode_lut[i]; + if (cur->video_format == ID) + mode = cur; + } + ioctl(fd, FBIOGET_VSCREENINFO, &info); + ALOGD_IF(EXT_OBSERVER_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(EXT_OBSERVER_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; + } + //Powerup + ioctl(fd, FBIOBLANK, FB_BLANK_UNBLANK); + ioctl(fd, FBIOGET_VSCREENINFO, &info); + //Pan_Display + ioctl(fd, FBIOPAN_DISPLAY, &info); + property_set("hw.hdmiON", "1"); +} + + +int ExtDisplayObserver::getExternalDisplay() const +{ + return mExternalDisplay; +} + +void ExtDisplayObserver::setExternalDisplayStatus(int connected) +{ + + hwc_context_t* ctx = mHwcContext; + if(ctx) { + ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: status = %d", __FUNCTION__, + connected); + // Store the external display + mExternalDisplay = connected;//(external_display_type)value; + //Invalidate + hwc_procs* proc = (hwc_procs*)ctx->device.reserved_proc[0]; + if(!proc) { + ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: HWC proc not registered", + __FUNCTION__); + } else { + /* Trigger redraw */ + ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: Invalidate !!", __FUNCTION__); + proc->invalidate(proc); + } + } + return; +} + +bool ExtDisplayObserver::writeHPDOption(int userOption) const +{ + bool ret = true; + int hdmiHPDFile = open(SYSFS_HPD,O_RDWR, 0); + if (hdmiHPDFile < 0) { + ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: state file '%s' not found : ret%d" + "err str: %s", __FUNCTION__, SYSFS_HPD, hdmiHPDFile, strerror(errno)); + ret = false; + } else { + int err = -1; + ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: option = %d", __FUNCTION__, + userOption); + if(userOption) + err = write(hdmiHPDFile, "1", 2); + else + err = write(hdmiHPDFile, "0" , 2); + if (err <= 0) { + ALOGD_IF(EXT_OBSERVER_DEBUG, "%s: file write failed '%s'", + __FUNCTION__, SYSFS_HPD); + ret = false; + } + close(hdmiHPDFile); + } + return ret; +} +}; + diff --git a/libhwcomposer/hwc_ext_observer.h b/libhwcomposer/hwc_ext_observer.h new file mode 100644 index 0000000..e7cb890 --- /dev/null +++ b/libhwcomposer/hwc_ext_observer.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012, Code Aurora Forum. 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_EXT_OBSERVER_H +#define HWC_EXT_OBSERVER_H + +#include + +struct hwc_context_t; + +namespace qhwc { + +class ExtDisplayObserver : public android::Thread +{ + //Type of external display - OFF, HDMI, WFD + enum external_display_type { + EXT_TYPE_NONE, + EXT_TYPE_HDMI, + EXT_TYPE_WIFI + }; + + // Mirroring state + enum external_mirroring_state { + EXT_MIRRORING_OFF, + EXT_MIRRORING_ON, + }; + public: + /*Overrides*/ + virtual bool threadLoop(); + virtual int readyToRun(); + virtual void onFirstRef(); + + virtual ~ExtDisplayObserver(); + static ExtDisplayObserver *getInstance(); + int getExternalDisplay() const; + void setHwcContext(hwc_context_t* hwcCtx); + + private: + ExtDisplayObserver(); + void setExternalDisplayStatus(int connected); + bool readResolution(); + int parseResolution(char* edidStr, int* edidModes, int len); + void setResolution(int ID); + bool openFramebuffer(); + bool writeHPDOption(int userOption) const; + bool isValidMode(int ID); + void handleUEvent(char* str); + int getModeOrder(int mode); + int getBestMode(); + + int fd; + int mExternalDisplay; + int mCurrentID; + char mEDIDs[128]; + int mEDIDModes[64]; + int mModeCount; + hwc_context_t *mHwcContext; + static android::sp sExtDisplayObserverInstance; +}; + +}; //qhwc +// --------------------------------------------------------------------------- +#endif //HWC_EXT_OBSERVER_H diff --git a/libhwcomposer/hwc_uimirror.cpp b/libhwcomposer/hwc_uimirror.cpp new file mode 100644 index 0000000..f5cf3e6 --- /dev/null +++ b/libhwcomposer/hwc_uimirror.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012, Code Aurora Forum. 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 "hwc_uimirror.h" +#include "hwc_ext_observer.h" + +namespace qhwc { + +#define HWC_UI_MIRROR 0 + +// Function to get the primary device orientation +// Loops thru the hardware layers and returns the orientation of the max. +// number of layers +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__); + return -1; + } + for(size_t i=0; i <= list->numHwLayers;i++ ) + { + for(size_t j=i+1; j <= list->numHwLayers; j++) + { + // Should we not check for the video layer orientation as it might + // source orientation(?) + if(list->hwLayers[i].transform == list->hwLayers[j].transform) + { + orientation = list->hwLayers[i].transform; + } + } + } + return orientation; +} + +//Static Members +ovutils::eOverlayState UIMirrorOverlay::sState = ovutils::OV_CLOSED; +bool UIMirrorOverlay::sIsUiMirroringOn = false; + + +//Prepare the overlay for the UI mirroring +bool UIMirrorOverlay::prepare(hwc_context_t *ctx, hwc_layer_list_t *list) { + sState = ovutils::OV_CLOSED; + sIsUiMirroringOn = false; + // If external display is connected + if(ctx->mExtDisplayObserver->getExternalDisplay()) { + sState = ovutils::OV_UI_MIRROR; + configure(ctx, list); + } + return sIsUiMirroringOn; +} + +// Configure +bool UIMirrorOverlay::configure(hwc_context_t *ctx, hwc_layer_list_t *list) +{ + if (LIKELY(ctx->mOverlay)) { + overlay::Overlay& ov = *(ctx->mOverlay); + // Set overlay state + ov.setState(sState); + framebuffer_device_t *fbDev = ctx->fbDev; + if(fbDev) { + private_module_t* m = reinterpret_cast( + fbDev->common.module); + int alignedW = ALIGN(m->info.xres, 32); + + private_handle_t const* hnd = + reinterpret_cast(m->framebuffer); + unsigned int size = hnd->size/m->numBuffers; + ovutils::Whf info(alignedW, hnd->height, hnd->format, size); + // Determine the RGB pipe for UI depending on the state + ovutils::eDest dest = ovutils::OV_PIPE_ALL; + if (sState == ovutils::OV_2D_TRUE_UI_MIRROR) { + // True UI mirroring state: external RGB pipe is OV_PIPE2 + dest = ovutils::OV_PIPE2; + } else if (sState == ovutils::OV_UI_MIRROR) { + // UI-only mirroring state: external RGB pipe is OV_PIPE0 + dest = ovutils::OV_PIPE0; + } + + ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_MEMORY_ID_TYPE_FB; + /* - TODO: Secure content + if (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) { + ovutils::setMdpFlags(mdpFlags, + ovutils::OV_MDP_SECURE_OVERLAY_SESSION); + } + */ + + ovutils::PipeArgs parg(mdpFlags, + info, + ovutils::ZORDER_0, + ovutils::IS_FG_OFF, + ovutils::ROT_FLAG_ENABLED); + ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg }; + ov.setSource(pargs, dest); + + // x,y,w,h + ovutils::Dim dcrop(0, 0, m->info.xres, m->info.yres); + ov.setCrop(dcrop, dest); + //Get the current orientation on primary panel + int transform = getDeviceOrientation(ctx, list); + ovutils::eTransform orient = + static_cast(transform); + ov.setTransform(orient, dest); + + ovutils::Dim dim; + dim.x = 0; + dim.y = 0; + dim.w = m->info.xres; + dim.h = m->info.yres; + ov.setPosition(dim, dest); + if (!ov.commit(dest)) { + ALOGE("%s: commit fails", __FUNCTION__); + return false; + } + sIsUiMirroringOn = true; + } + } + return sIsUiMirroringOn; +} + +bool UIMirrorOverlay::draw(hwc_context_t *ctx) +{ + if(!sIsUiMirroringOn) { + return true; + } + bool ret = true; + overlay::Overlay& ov = *(ctx->mOverlay); + ovutils::eOverlayState state = ov.getState(); + ovutils::eDest dest = ovutils::OV_PIPE_ALL; + framebuffer_device_t *fbDev = ctx->fbDev; + if(fbDev) { + private_module_t* m = reinterpret_cast( + fbDev->common.module); + //wait for the fb_post to be called + pthread_mutex_lock(&m->fbPostLock); + while(m->fbPostDone == false) { + pthread_cond_wait(&(m->fbPostCond), &(m->fbPostLock)); + } + pthread_mutex_unlock(&m->fbPostLock); + switch (state) { + case ovutils::OV_UI_MIRROR: + if (!ov.queueBuffer(m->framebuffer->fd, m->currentOffset, + ovutils::OV_PIPE0)) { + ALOGE("%s: queueBuffer failed for external", __FUNCTION__); + } + 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__); + } + break; + + default: + break; + } + // TODO: + // Call PANDISPLAY ioctl here to kickoff + } + return ret; +} + +//--------------------------------------------------------------------- +}; //namespace qhwc diff --git a/libhwcomposer/hwc_uimirror.h b/libhwcomposer/hwc_uimirror.h new file mode 100644 index 0000000..af43848 --- /dev/null +++ b/libhwcomposer/hwc_uimirror.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2012, Code Aurora Forum. 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_UIMIRROR_H +#define HWC_UIMIRROR_H +#include "hwc_utils.h" + +#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) +#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) + +namespace qhwc { +//Feature for Mirroring UI on the External display +class UIMirrorOverlay { + public: + // Sets up members and prepares overlay if conditions are met + static bool prepare(hwc_context_t *ctx, hwc_layer_list_t *list); + // Draws layer if this feature is on + static bool draw(hwc_context_t *ctx); + private: + //Configures overlay + static bool configure(hwc_context_t *ctx, hwc_layer_list_t *list); + //The chosen overlay state. + static ovutils::eOverlayState sState; + //Flags if this feature is on. + static bool sIsUiMirroringOn; +}; + +}; //namespace qhwc + +#endif //HWC_UIMIRROR_H diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp index 90c32fe..ea2fe66 100644 --- a/libhwcomposer/hwc_utils.cpp +++ b/libhwcomposer/hwc_utils.cpp @@ -18,7 +18,7 @@ #include "hwc_utils.h" #include "mdp_version.h" #include "hwc_video.h" - +#include "hwc_ext_observer.h" namespace qhwc { void initContext(hwc_context_t *ctx) { @@ -30,6 +30,8 @@ void initContext(hwc_context_t *ctx) ctx->hasOverlay = qdutils::MDPVersion::getInstance().hasOverlay(); ALOGI("MDP version: %d",ctx->mdpVersion); + ctx->mExtDisplayObserver = ExtDisplayObserver::getInstance(); + ctx->mExtDisplayObserver->setHwcContext(ctx); } void closeContext(hwc_context_t *ctx) diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h index b664260..2ee7188 100644 --- a/libhwcomposer/hwc_utils.h +++ b/libhwcomposer/hwc_utils.h @@ -36,13 +36,7 @@ struct hwc_context_t; namespace qhwc { -enum external_display_type { - EXT_TYPE_NONE, - EXT_TYPE_HDMI, - EXT_TYPE_WIFI -}; - - +class ExtDisplayObserver; // ----------------------------------------------------------------------------- // Utility functions - implemented in hwc_utils.cpp void dumpLayer(hwc_layer_t const* l); @@ -77,7 +71,6 @@ static inline bool isBufferLocked(const private_handle_t* hnd) { // This structure contains overall state struct hwc_context_t { hwc_composer_device_t device; - int hdmiEnabled; int numHwLayers; int mdpVersion; bool hasOverlay; @@ -91,6 +84,9 @@ struct hwc_context_t { //QueuedBufferStore to hold buffers for overlay qhwc::QueuedBufferStore *qbuf; + + // External display related information + qhwc::ExtDisplayObserver*mExtDisplayObserver; }; #endif //HWC_UTILS_H diff --git a/libhwcomposer/hwc_video.cpp b/libhwcomposer/hwc_video.cpp index bae35c8..525d662 100644 --- a/libhwcomposer/hwc_video.cpp +++ b/libhwcomposer/hwc_video.cpp @@ -16,6 +16,7 @@ */ #include "hwc_video.h" +#include "hwc_ext_observer.h" namespace qhwc { @@ -56,12 +57,14 @@ void VideoOverlay::chooseState(hwc_context_t *ctx) { //Support 1 video layer if(sYuvCount == 1) { - if(sIsLayerSkip && ctx->hdmiEnabled) { //Skip on primary, display on ext. + //Skip on primary, display on ext. + if(sIsLayerSkip && ctx->mExtDisplayObserver->getExternalDisplay()) { //TODO //VIDEO_ON_TV_ONLY } else if(sIsLayerSkip) { //skip on primary, no ext newState = ovutils::OV_CLOSED; - } else if(ctx->hdmiEnabled) { //display on both + } else if(ctx->mExtDisplayObserver->getExternalDisplay()) { + //display on both newState = ovutils::OV_2D_VIDEO_ON_PANEL_TV; } else { //display on primary only newState = ovutils::OV_2D_VIDEO_ON_PANEL; diff --git a/liboverlay/overlayUtils.cpp b/liboverlay/overlayUtils.cpp index 8c9ca99..ce18174 100644 --- a/liboverlay/overlayUtils.cpp +++ b/liboverlay/overlayUtils.cpp @@ -142,7 +142,10 @@ int FrameBufferInfo::getHeight() const { } bool FrameBufferInfo::supportTrueMirroring() const { - return mBorderFillSupported; + char value[PROPERTY_VALUE_MAX] = {0}; + property_get("hw.trueMirrorSupported", value, "0"); + int trueMirroringSupported = atoi(value); + return (trueMirroringSupported && mBorderFillSupported); } //--------------------------------------------------------