diff --git a/libhwcomposer/hwcomposer.cpp b/libhwcomposer/hwcomposer.cpp index 9e7b99d..6f6b84c 100644 --- a/libhwcomposer/hwcomposer.cpp +++ b/libhwcomposer/hwcomposer.cpp @@ -41,6 +41,7 @@ #include #include #include +#include /*****************************************************************************/ #define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1)) @@ -51,6 +52,7 @@ #define MAX_BYPASS_LAYERS 3 #define BYPASS_DEBUG 0 #define BYPASS_INDEX_OFFSET 4 +#define DEFAULT_IDLE_TIME 2000 enum BypassState { BYPASS_ON, @@ -91,6 +93,8 @@ struct hwc_context_t { int layerindex[MAX_BYPASS_LAYERS]; int nPipesUsed; BypassState bypassState; + IdleTimer idleTimer; + bool idleTimeOut; #endif #if defined HDMI_DUAL_DISPLAY external_display_type mHDMIEnabled; // Type of external display @@ -162,6 +166,25 @@ static inline int max(const int& a, const int& b) { return (a > b) ? a : b; } #ifdef COMPOSITION_BYPASS +static void timeout_handler(void *udata) { + struct hwc_context_t* ctx = (struct hwc_context_t*)(udata); + + if(!ctx) { + LOGE("%s: received empty data in timer callback", __FUNCTION__); + return; + } + + hwc_procs* proc = (hwc_procs*)ctx->device.reserved_proc[0]; + + if(!proc) { + LOGE("%s: HWC proc not registered", __FUNCTION__); + return; + } + /* Trigger SF to redraw the current frame */ + proc->invalidate(proc); + ctx->idleTimeOut = true; +} + void setLayerbypassIndex(hwc_layer_t* layer, const int bypass_index) { layer->flags &= ~HWC_BYPASS_INDEX_MASK; @@ -394,6 +417,12 @@ inline static bool isBypassDoable(hwc_composer_device_t *dev, const int yuvCount hwc_context_t* ctx = (hwc_context_t*)(dev); private_hwc_module_t* hwcModule = reinterpret_cast( dev->common.module); + + if(!ctx) { + LOGE("%s: hwc context is NULL", __FUNCTION__); + return false; + } + //Check if enabled in build.prop if(hwcModule->isBypassEnabled == false) { return false; @@ -414,10 +443,11 @@ inline static bool isBypassDoable(hwc_composer_device_t *dev, const int yuvCount return false; } - char value[PROPERTY_VALUE_MAX]; - if (property_get("debug.egl.swapinterval", value, "1") > 0) { - ctx->swapInterval = atoi(value); + if(ctx->idleTimeOut) { + ctx->idleTimeOut = false; + return false; } + //Bypass is not efficient if rotation or asynchronous mode is needed. for(int i = 0; i < list->numHwLayers; ++i) { if(list->hwLayers[i].transform) { @@ -1153,7 +1183,7 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) { isBypassUsed = false; } } else { - LOGE_IF(BYPASS_DEBUG,"%s: Bypass not possible[%d,%d]",__FUNCTION__, + LOGE_IF( BYPASS_DEBUG,"%s: Bypass not possible[%d,%d]",__FUNCTION__, isDoable, !isSkipLayerPresent ); isBypassUsed = false; } @@ -1534,6 +1564,7 @@ static int hwc_set(hwc_composer_device_t *dev, continue; #ifdef COMPOSITION_BYPASS } else if (list->hwLayers[i].flags & HWC_COMP_BYPASS) { + ctx->idleTimer.reset(); drawLayerUsingBypass(ctx, &(list->hwLayers[i]), i); #endif } else if (list->hwLayers[i].compositionType == HWC_USE_OVERLAY) { @@ -1712,6 +1743,17 @@ static int hwc_device_open(const struct hw_module_t* module, const char* name, } unsetBypassBufferLockState(dev); dev->bypassState = BYPASS_OFF; + + char property[PROPERTY_VALUE_MAX]; + unsigned long idle_timeout = DEFAULT_IDLE_TIME; + if (property_get("debug.bypass.idletime", property, NULL) > 0) { + if(atoi(property) != 0) + idle_timeout = atoi(property); + } + + dev->idleTimer.create(timeout_handler, dev); + dev->idleTimer.setFreq(idle_timeout); + dev->idleTimeOut = false; #endif ExtDispOnly::init(); #if defined HDMI_DUAL_DISPLAY diff --git a/libqcomui/Android.mk b/libqcomui/Android.mk index 9734813..54d2712 100644 --- a/libqcomui/Android.mk +++ b/libqcomui/Android.mk @@ -3,7 +3,8 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ qcom_ui.cpp \ - utils/profiler.cpp + utils/profiler.cpp \ + utils/IdleTimer.cpp ifeq ($(TARGET_BOARD_PLATFORM),qsd8k) # these are originally for 7x27a LOCAL_CFLAGS += -DCHECK_FOR_EXTERNAL_FORMAT diff --git a/libqcomui/utils/IdleTimer.cpp b/libqcomui/utils/IdleTimer.cpp new file mode 100755 index 0000000..6e4631e --- /dev/null +++ b/libqcomui/utils/IdleTimer.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2012, Code Aurora Forum. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "IdleTimer.h" +TimerHandler IdleTimer::mHandler = NULL; + +int IdleTimer::create(TimerHandler reg_handler, void* user_data) { + + /* store registerd handler */ + mHandler = reg_handler; + + + mSAction.sa_flags = SA_SIGINFO; + mSAction.sa_sigaction = (TimerFP)(&IdleTimer::timer_cb); + sigemptyset(&mSAction.sa_mask); + if (sigaction(SIGRTMIN, &mSAction, NULL) == -1) { + LOGE("%s: IdleTimer::sigaction failed!!", __FUNCTION__); + return -1; + } + + /* start the timer */ + mSEvent.sigev_notify = SIGEV_SIGNAL; + mSEvent.sigev_signo = SIGRTMIN; + mSEvent.sigev_value.sival_ptr = user_data; + if (timer_create(CLOCK_REALTIME, &mSEvent, &mID) == -1) { + LOGE("%s: IdleTimer::timer_create failed!!", __FUNCTION__); + return -1; + } + + return 0; +} + +int IdleTimer::reset() { + + /* clear signal mask */ + sigemptyset(&mSAction.sa_mask); + if (sigaction(SIGRTMIN, &mSAction, NULL) == -1) { + LOGE("%s: IdleTimer::sigaction failed!!", __FUNCTION__); + return -1; + } + /* rearm timer */ + if (timer_settime(mID, 0, &mSpec, NULL) == -1) { + LOGE("%s: IdleTimer::timer_settime failed!!",__FUNCTION__); + return -1; + } + return 0; +} + +void IdleTimer::setFreq(unsigned long freq_msecs) { + mSpec.it_value.tv_sec = freq_msecs / 1000; + mSpec.it_value.tv_nsec = 0; + mSpec.it_interval.tv_sec = mSpec.it_value.tv_sec; + mSpec.it_interval.tv_nsec = mSpec.it_value.tv_nsec; +} + +void IdleTimer::timer_cb(int sig, siginfo_t* si, void* uc) { + mHandler((void*)si->si_value.sival_ptr); + signal(sig, SIG_IGN); +} diff --git a/libqcomui/utils/IdleTimer.h b/libqcomui/utils/IdleTimer.h new file mode 100755 index 0000000..5f2e84c --- /dev/null +++ b/libqcomui/utils/IdleTimer.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2012, Code Aurora Forum. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Code Aurora Forum, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef INCLUDE_IDLETIMER +#define INCLUDE_IDLETIMER + +#include +#include +#include + +typedef void (*TimerFP)(int, siginfo_t *, void*); +typedef void (*TimerHandler)(void*); + +class IdleTimer +{ + struct sigaction mSAction; + struct sigevent mSEvent; + struct itimerspec mSpec; + timer_t mID; + static TimerHandler mHandler; + +public: + IdleTimer():mID(-1){}; + /* create timer obj */ + int create(TimerHandler reg_handler, void* user_data); + /* arm timer with given value */ + int reset(); + /* set timeout period */ + void setFreq(unsigned long freq_msecs); + /* internal timeout callback function before + * invoking user registered handler */ + static void timer_cb(int sig, siginfo_t* si, void* uc); +}; + + +#endif // INCLUDE_IDLETIMER