From bd86fcfff6a3b958c65506b57537cc4a1027f544 Mon Sep 17 00:00:00 2001 From: Jeykumar Sankaran Date: Mon, 23 Jul 2012 12:22:21 -0700 Subject: [PATCH] display: Add support for MDP Composition This change 1) implements MDP Composition upto 3 layers 2) adds invalidator support to fall back to FB composition during idle screen condition. Change-Id: I8d724f905c943f986b68596e2548a7f5a8ce6588 --- libhwcomposer/Android.mk | 3 +- libhwcomposer/hwc.cpp | 4 + libhwcomposer/hwc_mdpcomp.cpp | 829 ++++++++++++++++++++++++++++++++ libhwcomposer/hwc_mdpcomp.h | 220 +++++++++ libhwcomposer/hwc_utils.cpp | 5 + libhwcomposer/hwc_utils.h | 13 + libqdutils/Android.mk | 3 +- libqdutils/idle_invalidator.cpp | 18 +- 8 files changed, 1084 insertions(+), 11 deletions(-) create mode 100755 libhwcomposer/hwc_mdpcomp.cpp create mode 100755 libhwcomposer/hwc_mdpcomp.h mode change 100644 => 100755 libqdutils/idle_invalidator.cpp diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk index 9808aa5..05d033e 100644 --- a/libhwcomposer/Android.mk +++ b/libhwcomposer/Android.mk @@ -11,5 +11,6 @@ LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"hwcomposer\" LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) LOCAL_SRC_FILES := hwc.cpp hwc_video.cpp hwc_utils.cpp \ hwc_uimirror.cpp hwc_external.cpp \ - hwc_uevents.cpp hwc_copybit.cpp + hwc_uevents.cpp hwc_copybit.cpp \ + hwc_mdpcomp.cpp include $(BUILD_SHARED_LIBRARY) diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp index 81ccad2..10c2948 100644 --- a/libhwcomposer/hwc.cpp +++ b/libhwcomposer/hwc.cpp @@ -30,6 +30,7 @@ #include "hwc_uimirror.h" #include "hwc_copybit.h" #include "hwc_external.h" +#include "hwc_mdpcomp.h" using namespace qhwc; @@ -84,6 +85,8 @@ static int hwc_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list) //Nothing here } else if(UIMirrorOverlay::prepare(ctx, list)) { ctx->overlayInUse = true; + } else if(MDPComp::configure(dev, list)) { + ctx->overlayInUse = true; } else if (0) { //Other features ctx->overlayInUse = true; @@ -152,6 +155,7 @@ static int hwc_set(hwc_composer_device_t *dev, if (LIKELY(list)) { VideoOverlay::draw(ctx, list); CopyBit::draw(ctx, list, (EGLDisplay)dpy, (EGLSurface)sur); + MDPComp::draw(ctx, list); EGLBoolean sucess = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur); UIMirrorOverlay::draw(ctx); if(ctx->mExtDisplay->getExternalDisplay()) diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp new file mode 100755 index 0000000..8107400 --- /dev/null +++ b/libhwcomposer/hwc_mdpcomp.cpp @@ -0,0 +1,829 @@ +/* + * 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_mdpcomp.h" +#include "hwc_qbuf.h" +#include "hwc_external.h" + +#define SUPPORT_4LAYER 0 + +namespace qhwc { + +/****** Class PipeMgr ***********/ + +void inline PipeMgr::reset() { + mVGPipes = MAX_VG; + mVGUsed = 0; + mVGIndex = 0; + mRGBPipes = MAX_RGB; + mRGBUsed = 0; + mRGBIndex = MAX_VG; + mTotalAvail = mVGPipes + mRGBPipes; + memset(&mStatus, 0x0 , sizeof(int)*mTotalAvail); +} + +int PipeMgr::req_for_pipe(int pipe_req) { + + switch(pipe_req) { + case PIPE_REQ_VG: //VG + if(mVGPipes){ + mVGPipes--; + mVGUsed++; + mTotalAvail--; + return PIPE_REQ_VG; + } + case PIPE_REQ_RGB: // RGB + if(mRGBPipes) { + mRGBPipes--; + mRGBUsed++; + mTotalAvail--; + return PIPE_REQ_RGB; + } + return PIPE_NONE; + case PIPE_REQ_FB: //FB + if(mRGBPipes) { + mRGBPipes--; + mRGBUsed++; + mTotalAvail--; + mStatus[VAR_INDEX] = PIPE_IN_FB_MODE; + return PIPE_REQ_FB; + } + default: + break; + }; + return PIPE_NONE; +} + +int PipeMgr::assign_pipe(int pipe_pref) { + switch(pipe_pref) { + case PIPE_REQ_VG: //VG + if(mVGUsed) { + mVGUsed--; + mStatus[mVGIndex] = PIPE_IN_COMP_MODE; + return mVGIndex++; + } + case PIPE_REQ_RGB: //RGB + if(mRGBUsed) { + mRGBUsed--; + mStatus[mRGBIndex] = PIPE_IN_COMP_MODE; + return mRGBIndex++; + } + default: + ALOGE("%s: PipeMgr:invalid case in pipe_mgr_assign", + __FUNCTION__); + return -1; + }; +} + +/****** Class MDPComp ***********/ + +MDPComp::State MDPComp::sMDPCompState = MDPCOMP_OFF; +struct MDPComp::frame_info MDPComp::sCurrentFrame; +PipeMgr MDPComp::sPipeMgr; +IdleInvalidator *MDPComp::idleInvalidator = NULL; +bool MDPComp::sIdleFallBack = false; +bool MDPComp::sDebugLogs = false; +int MDPComp::sSkipCount = 0; +int MDPComp::sMaxLayers = 0; + +bool MDPComp::deinit() { + //XXX: Tear down MDP comp state + return true; +} + +void MDPComp::timeout_handler(void *udata) { + struct hwc_context_t* ctx = (struct hwc_context_t*)(udata); + + if(!ctx) { + ALOGE("%s: received empty data in timer callback", __FUNCTION__); + return; + } + + hwc_procs* proc = (hwc_procs*)ctx->device.reserved_proc[0]; + + if(!proc) { + ALOGE("%s: HWC proc not registered", __FUNCTION__); + return; + } + sIdleFallBack = true; + /* Trigger SF to redraw the current frame */ + proc->invalidate(proc); +} + +void MDPComp::reset( hwc_context_t *ctx, hwc_layer_list_t* list ) { + sCurrentFrame.count = 0; + free(sCurrentFrame.pipe_layer); + sCurrentFrame.pipe_layer = NULL; + + //Reset MDP pipes + sPipeMgr.reset(); + sPipeMgr.setStatus(VAR_INDEX, PIPE_IN_FB_MODE); + +#if SUPPORT_4LAYER + configure_var_pipe(ctx); +#endif + + //Reset flags and states + unsetMDPCompLayerFlags(ctx, list); + if(sMDPCompState == MDPCOMP_ON) { + sMDPCompState = MDPCOMP_OFF_PENDING; + } +} + +void MDPComp::setLayerIndex(hwc_layer_t* layer, const int pipe_index) +{ + layer->flags &= ~HWC_MDPCOMP_INDEX_MASK; + layer->flags |= pipe_index << MDPCOMP_INDEX_OFFSET; +} + +int MDPComp::getLayerIndex(hwc_layer_t* layer) +{ + int byp_index = -1; + + if(layer->flags & HWC_MDPCOMP) { + byp_index = ((layer->flags & HWC_MDPCOMP_INDEX_MASK) >> + MDPCOMP_INDEX_OFFSET); + byp_index = (byp_index < sMaxLayers ? byp_index : -1 ); + } + return byp_index; +} +void MDPComp::print_info(hwc_layer_t* layer) +{ + hwc_rect_t sourceCrop = layer->sourceCrop; + hwc_rect_t displayFrame = layer->displayFrame; + + int s_l = sourceCrop.left; + int s_t = sourceCrop.top; + int s_r = sourceCrop.right; + int s_b = sourceCrop.bottom; + + int d_l = displayFrame.left; + int d_t = displayFrame.top; + int d_r = displayFrame.right; + int d_b = displayFrame.bottom; + + ALOGD_IF(isDebug(), "src:[%d,%d,%d,%d] (%d x %d) \ + dst:[%d,%d,%d,%d] (%d x %d)", + s_l, s_t, s_r, s_b, (s_r - s_l), (s_b - s_t), + d_l, d_t, d_r, d_b, (d_r - d_l), (d_b - d_t)); +} +/* + * Configures pipe(s) for MDP composition + */ +int MDPComp::prepare(hwc_context_t *ctx, hwc_layer_t *layer, + mdp_pipe_info& mdp_info) { + + int nPipeIndex = mdp_info.index; + + if (ctx) { + + private_handle_t *hnd = (private_handle_t *)layer->handle; + + overlay::Overlay& ov = *(ctx->mOverlay); + + if(!hnd) { + ALOGE("%s: layer handle is NULL", __FUNCTION__); + return -1; + } + + + int hw_w = ctx->mFbDev->width; + int hw_h = ctx->mFbDev->height; + + + hwc_rect_t sourceCrop = layer->sourceCrop; + hwc_rect_t displayFrame = layer->displayFrame; + + const int src_w = sourceCrop.right - sourceCrop.left; + const int src_h = sourceCrop.bottom - sourceCrop.top; + + hwc_rect_t crop = sourceCrop; + int crop_w = crop.right - crop.left; + int crop_h = crop.bottom - crop.top; + + hwc_rect_t dst = displayFrame; + int dst_w = dst.right - dst.left; + int dst_h = dst.bottom - dst.top; + + //REDUNDANT ?? + if(hnd != NULL && + (hnd->flags & private_handle_t::PRIV_FLAGS_NONCONTIGUOUS_MEM )) { + ALOGE("%s: failed due to non-pmem memory",__FUNCTION__); + return -1; + } + + if(dst.left < 0 || dst.top < 0 || + dst.right > hw_w || dst.bottom > hw_h) { + ALOGD_IF(isDebug(),"%s: Destination has negative coordinates", + __FUNCTION__); + + qhwc::calculate_crop_rects(crop, dst, hw_w, hw_h); + + //Update calulated width and height + crop_w = crop.right - crop.left; + crop_h = crop.bottom - crop.top; + + dst_w = dst.right - dst.left; + dst_h = dst.bottom - dst.top; + } + + if( (dst_w > hw_w)|| (dst_h > hw_h)) { + ALOGD_IF(isDebug(),"%s: Dest rect exceeds FB", __FUNCTION__); + print_info(layer); + dst_w = hw_w; + dst_h = hw_h; + } + + // Determine pipe to set based on pipe index + ovutils::eDest dest = ovutils::OV_PIPE_ALL; + if (nPipeIndex == 0) { + dest = ovutils::OV_PIPE0; + } else if (nPipeIndex == 1) { + dest = ovutils::OV_PIPE1; + } else if (nPipeIndex == 2) { + dest = ovutils::OV_PIPE2; + } + + ovutils::eZorder zOrder = ovutils::ZORDER_0; + + if(mdp_info.z_order == 0 ) { + zOrder = ovutils::ZORDER_0; + } else if(mdp_info.z_order == 1 ) { + zOrder = ovutils::ZORDER_1; + } else if(mdp_info.z_order == 2 ) { + zOrder = ovutils::ZORDER_2; + } + + // Order order order + // setSource - just setting source + // setParameter - changes src w/h/f accordingly + // setCrop - ROI - src_rect + // setPosition - dst_rect + // commit - commit changes to mdp driver + // queueBuffer - not here, happens when draw is called + + ovutils::eTransform orient = + static_cast(layer->transform); + + ov.setTransform(orient, dest); + ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size); + ovutils::eMdpFlags mdpFlags = mdp_info.isVG ? ovutils::OV_MDP_PIPE_SHARE + : ovutils::OV_MDP_FLAGS_NONE; + ovutils::eIsFg isFG = mdp_info.isFG ? ovutils::IS_FG_SET + : ovutils::IS_FG_OFF; + ovutils::PipeArgs parg(mdpFlags, + info, + zOrder, + isFG, + ovutils::ROT_FLAG_DISABLED); + + ovutils::PipeArgs pargs[MAX_PIPES] = { parg, parg, parg }; + if (!ov.setSource(pargs, dest)) { + ALOGE("%s: setSource failed", __FUNCTION__); + return -1; + } + + ovutils::Dim dcrop(crop.left, crop.top, crop_w, crop_h); + if (!ov.setCrop(dcrop, dest)) { + ALOGE("%s: setCrop failed", __FUNCTION__); + return -1; + } + + ovutils::Dim dim(dst.left, dst.top, dst_w, dst_h); + if (!ov.setPosition(dim, dest)) { + ALOGE("%s: setPosition failed", __FUNCTION__); + return -1; + } + + ALOGD_IF(isDebug(),"%s: MDP set: crop[%d,%d,%d,%d] dst[%d,%d,%d,%d] \ + nPipe: %d isFG: %d zorder: %d",__FUNCTION__, dcrop.x, + dcrop.y,dcrop.w, dcrop.h, dim.x, dim.y, dim.w, dim.h, + nPipeIndex,mdp_info.isFG, mdp_info.z_order); + + if (!ov.commit(dest)) { + ALOGE("%s: commit failed", __FUNCTION__); + return -1; + } + } + return 0; +} + +/* + * MDPComp not possible when + * 1. We have more than sMaxLayers + * 2. External display connected + * 3. Composition is triggered by + * Idle timer expiry + * 4. Rotation is needed + * 5. Overlay in use + */ + +bool MDPComp::is_doable(hwc_composer_device_t *dev, + const hwc_layer_list_t* list) { + hwc_context_t* ctx = (hwc_context_t*)(dev); + + if(!ctx) { + ALOGE("%s: hwc context is NULL", __FUNCTION__); + return false; + } + + //Number of layers + if(list->numHwLayers < 1 || list->numHwLayers > sMaxLayers) { + ALOGD_IF(isDebug(), "%s: Unsupported number of layers",__FUNCTION__); + return false; + } + + //Disable MDPComp when ext display connected + if(ctx->mExtDisplay->getExternalDisplay()) { + ALOGD_IF(isDebug(), "%s: External display connected.", __FUNCTION__); + } + + //FB composition on idle timeout + if(sIdleFallBack) { + ALOGD_IF(isDebug(), "%s: idle fallback",__FUNCTION__); + return false; + } + + //MDP composition is not efficient if rotation is needed. + for(unsigned int i = 0; i < list->numHwLayers; ++i) { + if(list->hwLayers[i].transform) { + ALOGD_IF(isDebug(), "%s: orientation involved",__FUNCTION__); + return false; + } + } + + return true; +} + +void MDPComp::setMDPCompLayerFlags(hwc_layer_list_t* list) { + + for(int index = 0 ; index < sCurrentFrame.count; index++ ) + { + int layer_index = sCurrentFrame.pipe_layer[index].layer_index; + if(layer_index >= 0) { + hwc_layer_t* layer = &(list->hwLayers[layer_index]); + + layer->flags |= HWC_MDPCOMP; + layer->compositionType = HWC_OVERLAY; + layer->hints |= HWC_HINT_CLEAR_FB; + } + } +} + +void MDPComp::get_layer_info(hwc_layer_t* layer, int& flags) { + + private_handle_t* hnd = (private_handle_t*)layer->handle; + + if(layer->flags & HWC_SKIP_LAYER) { + flags |= MDPCOMP_LAYER_SKIP; + } else if(hnd != NULL && + (hnd->flags & private_handle_t::PRIV_FLAGS_NONCONTIGUOUS_MEM )) { + flags |= MDPCOMP_LAYER_UNSUPPORTED_MEM; + } + + if(layer->blending != HWC_BLENDING_NONE) + flags |= MDPCOMP_LAYER_BLEND; + + int dst_w, dst_h; + getLayerResolution(layer, dst_w, dst_h); + + hwc_rect_t sourceCrop = layer->sourceCrop; + const int src_w = sourceCrop.right - sourceCrop.left; + const int src_h = sourceCrop.bottom - sourceCrop.top; + if(((src_w > dst_w) || (src_h > dst_h))) { + flags |= MDPCOMP_LAYER_DOWNSCALE; + } +} + +int MDPComp::mark_layers(hwc_layer_list_t* list, layer_mdp_info* layer_info, + frame_info& current_frame) { + + int layer_count = list->numHwLayers; + + if(layer_count > sMaxLayers) { + if(!sPipeMgr.req_for_pipe(PIPE_REQ_FB)) { + ALOGE("%s: binding var pipe to FB failed!!", __FUNCTION__); + return 0; + } + } + + //Parse layers from higher z-order + for(int index = layer_count - 1 ; index >= 0; index-- ) { + hwc_layer_t* layer = &list->hwLayers[index]; + + int layer_prop = 0; + get_layer_info(layer, layer_prop); + + ALOGD_IF(isDebug(),"%s: prop for layer [%d]: %x", __FUNCTION__, + index, layer_prop); + + //Both in cases of NON-CONTIGUOUS memory or SKIP layer, + //current version of mdp composition falls back completely to FB + //composition. + //TO DO: Support dual mode composition + + if(layer_prop & MDPCOMP_LAYER_UNSUPPORTED_MEM) { + ALOGD_IF(isDebug(), "%s: Non contigous memory",__FUNCTION__); + return MDPCOMP_ABORT; + } + + if(layer_prop & MDPCOMP_LAYER_SKIP) { + ALOGD_IF(isDebug(), "%s:skip layer",__FUNCTION__); + return MDPCOMP_ABORT; + } + + //Request for MDP pipes + int pipe_pref = PIPE_REQ_VG; + + if((layer_prop & MDPCOMP_LAYER_DOWNSCALE) && + (layer_prop & MDPCOMP_LAYER_BLEND)) { + pipe_pref = PIPE_REQ_RGB; + } + + int allocated_pipe = sPipeMgr.req_for_pipe( pipe_pref); + if(allocated_pipe) { + layer_info[index].can_use_mdp = true; + layer_info[index].pipe_pref = allocated_pipe; + current_frame.count++; + }else { + ALOGE("%s: pipe marking in mark layer fails for : %d", + __FUNCTION__, allocated_pipe); + return MDPCOMP_FAILURE; + } + } + return MDPCOMP_SUCCESS; +} + +void MDPComp::reset_layer_mdp_info(layer_mdp_info* layer_info, int count) { + for(int i = 0 ; i < count; i++ ) { + layer_info[i].can_use_mdp = false; + layer_info[i].pipe_pref = PIPE_NONE; + } +} + +bool MDPComp::alloc_layer_pipes(hwc_layer_list_t* list, + layer_mdp_info* layer_info, frame_info& current_frame) { + + int layer_count = list->numHwLayers; + int mdp_count = current_frame.count; + int fallback_count = layer_count - mdp_count; + int frame_pipe_count = 0; + + ALOGD_IF(isDebug(), "%s: dual mode: %d total count: %d \ + mdp count: %d fallback count: %d", + __FUNCTION__, (layer_count != mdp_count), + layer_count, mdp_count, fallback_count); + + for(int index = 0 ; index < layer_count ; index++ ) { + hwc_layer_t* layer = &list->hwLayers[index]; + + if(layer_info[index].can_use_mdp) { + pipe_layer_pair& info = current_frame.pipe_layer[frame_pipe_count]; + mdp_pipe_info& pipe_info = info.pipe_index; + + pipe_info.index = sPipeMgr.assign_pipe(layer_info[index].pipe_pref); + pipe_info.isVG = (layer_info[index].pipe_pref == PIPE_REQ_VG); + pipe_info.isFG = (frame_pipe_count == 0); + /* if VAR pipe is attached to FB, FB will be updated with + VSYNC WAIT flag, so no need to set VSYNC WAIT for any + bypass pipes. if not, set VSYNC WAIT to the last updating pipe*/ + pipe_info.vsync_wait = + (sPipeMgr.getStatus(VAR_INDEX) == PIPE_IN_FB_MODE) ? false: + (frame_pipe_count == (mdp_count - 1)); + /* All the layers composed on FB will have MDP zorder 0, so start + assigning from 1*/ + pipe_info.z_order = index - + (fallback_count ? fallback_count - 1 : fallback_count); + + info.layer_index = index; + frame_pipe_count++; + } + } + return 1; +} + +//returns array of layers and their allocated pipes +bool MDPComp::parse_and_allocate(hwc_context_t* ctx, hwc_layer_list_t* list, + frame_info& current_frame ) { + + int layer_count = list->numHwLayers; + + /* clear pipe status */ + sPipeMgr.reset(); + + layer_mdp_info* bp_layer_info = (layer_mdp_info*) + malloc(sizeof(layer_mdp_info)* layer_count); + + reset_layer_mdp_info(bp_layer_info, layer_count); + + /* iterate through layer list to mark candidate */ + if(mark_layers(list, bp_layer_info, current_frame) == MDPCOMP_ABORT) { + free(bp_layer_info); + current_frame.count = 0; + ALOGE_IF(isDebug(), "%s:mark_layers failed!!", __FUNCTION__); + return false; + } + current_frame.pipe_layer = (pipe_layer_pair*) + malloc(sizeof(pipe_layer_pair) * current_frame.count); + + /* allocate MDP pipes for marked layers */ + alloc_layer_pipes( list, bp_layer_info, current_frame); + + free(bp_layer_info); + return true; +} +#if SUPPORT_4LAYER +int MDPComp::configure_var_pipe(hwc_context_t* ctx) { + + if(!ctx) { + ALOGE("%s: invalid context", __FUNCTION__); + return -1; + } + + framebuffer_device_t *fbDev = ctx->fbDev; + if (!fbDev) { + ALOGE("%s: fbDev is NULL", __FUNCTION__); + return -1; + } + + int new_mode = -1, cur_mode; + fbDev->perform(fbDev,EVENT_GET_VAR_PIPE_MODE, (void*)&cur_mode); + + if(sPipeMgr.getStatus(VAR_INDEX) == PIPE_IN_FB_MODE) { + new_mode = VAR_PIPE_FB_ATTACH; + } else if(sPipeMgr.getStatus(VAR_INDEX) == PIPE_IN_BYP_MODE) { + new_mode = VAR_PIPE_FB_DETACH; + fbDev->perform(fbDev,EVENT_WAIT_POSTBUFFER,NULL); + } + + ALOGD_IF(isDebug(),"%s: old_mode: %d new_mode: %d", __FUNCTION__, + cur_mode, new_mode); + + if((new_mode != cur_mode) && (new_mode >= 0)) { + if(fbDev->perform(fbDev,EVENT_SET_VAR_PIPE_MODE,(void*)&new_mode) < 0) { + ALOGE("%s: Setting var pipe mode failed", __FUNCTION__); + } + } + + return 0; +} +#endif + +bool MDPComp::setup(hwc_context_t* ctx, hwc_layer_list_t* list) { + int nPipeIndex, vsync_wait, isFG; + int numHwLayers = list->numHwLayers; + + frame_info ¤t_frame = sCurrentFrame; + current_frame.count = 0; + + if(!ctx) { + ALOGE("%s: invalid context", __FUNCTION__); + return -1; + } + + framebuffer_device_t *fbDev = ctx->mFbDev; + if (!fbDev) { + ALOGE("%s: fbDev is NULL", __FUNCTION__); + return -1; + } + + if(!parse_and_allocate(ctx, list, current_frame)) { +#if SUPPORT_4LAYER + int mode = VAR_PIPE_FB_ATTACH; + if(fbDev->perform(fbDev,EVENT_SET_VAR_PIPE_MODE,(void*)&mode) < 0 ) { + ALOGE("%s: setting var pipe mode failed", __FUNCTION__); + } +#endif + ALOGD_IF(isDebug(), "%s: Falling back to FB", __FUNCTION__); + return false; + } +#if SUPPORT_4LAYER + configure_var_pipe(ctx); +#endif + + overlay::Overlay& ov = *(ctx->mOverlay); + ovutils::eOverlayState state = ov.getState(); + + if (current_frame.count == 1) { + state = ovutils::OV_BYPASS_1_LAYER; + } else if (current_frame.count == 2) { + state = ovutils::OV_BYPASS_2_LAYER; + } else if (current_frame.count == 3) { + state = ovutils::OV_BYPASS_3_LAYER; + } + + ov.setState(state); + + + for (int index = 0 ; index < current_frame.count; index++) { + int layer_index = current_frame.pipe_layer[index].layer_index; + hwc_layer_t* layer = &list->hwLayers[layer_index]; + mdp_pipe_info& cur_pipe = current_frame.pipe_layer[index].pipe_index; + + if( prepare(ctx, layer, cur_pipe) != 0 ) { + ALOGD_IF(isDebug(), "%s: MDPComp failed to configure overlay for \ + layer %d with pipe index:%d",__FUNCTION__, + index, cur_pipe.index); + return false; + } else { + setLayerIndex(layer, index); + } + } + return true; +} + +void MDPComp::unsetMDPCompLayerFlags(hwc_context_t* ctx, hwc_layer_list_t* list) +{ + if (!list) + return; + + for (int index = 0 ; index < sCurrentFrame.count; index++) { + int l_index = sCurrentFrame.pipe_layer[index].layer_index; + if(list->hwLayers[l_index].flags & HWC_MDPCOMP) { + list->hwLayers[l_index].flags &= ~HWC_MDPCOMP; + } + } +} + +int MDPComp::draw(hwc_context_t *ctx, hwc_layer_list_t* list) { + + if(!isEnabled()) { + ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled",__FUNCTION__); + return 0; + } + + if(!ctx || !list) { + ALOGE("%s: invalid contxt or list",__FUNCTION__); + return -1; + } + + overlay::Overlay& ov = *(ctx->mOverlay); + + for(unsigned int i = 0; i < list->numHwLayers; i++ ) + { + hwc_layer_t *layer = &list->hwLayers[i]; + + if(!(layer->flags & HWC_MDPCOMP)) { + ALOGD_IF(isDebug(), "%s: Layer Not flagged for MDP comp", + __FUNCTION__); + continue; + } + + int data_index = getLayerIndex(layer); + mdp_pipe_info& pipe_info = + sCurrentFrame.pipe_layer[data_index].pipe_index; + int index = pipe_info.index; + + if(index < 0) { + ALOGE("%s: Invalid pipe index (%d)", __FUNCTION__, index); + return -1; + } + + /* reset Invalidator */ + if(idleInvalidator) + idleInvalidator->markForSleep(); + + ovutils::eDest dest; + + if (index == 0) { + dest = ovutils::OV_PIPE0; + } else if (index == 1) { + dest = ovutils::OV_PIPE1; + } else if (index == 2) { + dest = ovutils::OV_PIPE2; + } + + if (ctx ) { + private_handle_t *hnd = (private_handle_t *)layer->handle; + if(!hnd) { + ALOGE("%s handle null", __FUNCTION__); + return -1; + } + + //lock buffer before queue + //XXX: Handle lock failure + ctx->qbuf->lockAndAdd(hnd); + + ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \ + using pipe: %d", __FUNCTION__, layer, + hnd, index ); + + if (!ov.queueBuffer(hnd->fd, hnd->offset, dest)) { + ALOGE("%s: queueBuffer failed for external", __FUNCTION__); + return -1; + } + } + layer->flags &= ~HWC_MDPCOMP; + layer->flags |= HWC_MDPCOMP_INDEX_MASK; + } + return 0; +} + +bool MDPComp::init(hwc_context_t *dev) { + + if(!dev) { + ALOGE("%s: Invalid hwc context!!",__FUNCTION__); + return false; + } + +#if SUPPORT_4LAYER + if(MAX_MDPCOMP_LAYERS > MAX_STATIC_PIPES) { + framebuffer_device_t *fbDev = dev->fbDevice; + if(fbDev == NULL) { + ALOGE("%s: FATAL: framebuffer device is NULL", __FUNCTION__); + return false; + } + + //Receive VAR pipe object from framebuffer + if(fbDev->perform(fbDev,EVENT_GET_VAR_PIPE,(void*)&ov) < 0) { + ALOGE("%s: FATAL: getVariablePipe failed!!", __FUNCTION__); + return false; + } + + sPipeMgr.setStatus(VAR_INDEX, PIPE_IN_FB_MODE); + } +#endif + char property[PROPERTY_VALUE_MAX]; + + sMaxLayers = 0; + if(property_get("debug.mdpcomp.maxlayer", property, NULL) > 0) { + if(atoi(property) != 0) + sMaxLayers = atoi(property); + } + + sDebugLogs = false; + if(property_get("debug.mdpcomp.logs", property, NULL) > 0) { + if(atoi(property) != 0) + sDebugLogs = true; + } + + unsigned long idle_timeout = DEFAULT_IDLE_TIME; + if(property_get("debug.mdpcomp.idletime", property, NULL) > 0) { + if(atoi(property) != 0) + idle_timeout = atoi(property); + } + + //create Idle Invalidator + idleInvalidator = IdleInvalidator::getInstance(); + + if(idleInvalidator == NULL) { + ALOGE("%s: failed to instantiate idleInvalidator object", __FUNCTION__); + } else { + idleInvalidator->init(timeout_handler, dev, idle_timeout); + } + return true; +} + +bool MDPComp::configure(hwc_composer_device_t *dev, hwc_layer_list_t* list) { + + if(!isEnabled()) { + ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled.", __FUNCTION__); + return false; + } + + hwc_context_t* ctx = (hwc_context_t*)(dev); + + bool isMDPCompUsed = true; + bool doable = is_doable(dev, list); + + if(doable) { + if(setup(ctx, list)) { + setMDPCompLayerFlags(list); + sMDPCompState = MDPCOMP_ON; + } else { + ALOGD_IF(isDebug(),"%s: MDP Comp Failed",__FUNCTION__); + isMDPCompUsed = false; + } + } else { + ALOGD_IF( isDebug(),"%s: MDP Comp not possible[%d]",__FUNCTION__, + doable); + isMDPCompUsed = false; + } + + //Reset states + if(!isMDPCompUsed) { + //Reset current frame + reset(ctx, list); + } + + sIdleFallBack = false; + + return isMDPCompUsed; +} +}; //namespace + diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h new file mode 100755 index 0000000..199204c --- /dev/null +++ b/libhwcomposer/hwc_mdpcomp.h @@ -0,0 +1,220 @@ +/* + * 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_MDP_COMP +#define HWC_MDP_COMP + +#include +#include +#include +#include + +#define MAX_STATIC_PIPES 3 +#define MDPCOMP_INDEX_OFFSET 4 +#define DEFAULT_IDLE_TIME 2000 + +#define MAX_VG 2 +#define MAX_RGB 2 +#define VAR_INDEX 3 +#define MAX_PIPES (MAX_VG + MAX_RGB) +#define HWC_MDPCOMP_INDEX_MASK 0x00000030 + + +//struct hwc_context_t; + +namespace qhwc { + +// pipe status +enum { + PIPE_UNASSIGNED = 0, + PIPE_IN_FB_MODE, + PIPE_IN_COMP_MODE, +}; + +// pipe request +enum { + PIPE_NONE = 0, + PIPE_REQ_VG, + PIPE_REQ_RGB, + PIPE_REQ_FB, +}; + +// MDP Comp Status +enum { + MDPCOMP_SUCCESS = 0, + MDPCOMP_FAILURE, + MDPCOMP_ABORT, +}; + +//This class manages the status of 4 MDP pipes and keeps +//track of Variable pipe mode. +class PipeMgr { + +public: + PipeMgr() { reset();} + //reset pipemgr params + void reset(); + + //Based on the preference received, pipe mgr + //allocates the best available pipe to handle + //the case + int req_for_pipe(int pipe_req); + + //Allocate requested pipe and update availablity + int assign_pipe(int pipe_pref); + + // Get/Set pipe status + void setStatus(int pipe_index, int pipe_status) { + mStatus[pipe_index] = pipe_status; + } + int getStatus(int pipe_index) { + return mStatus[pipe_index]; + } +private: + int mVGPipes; + int mVGUsed; + int mVGIndex; + int mRGBPipes; + int mRGBUsed; + int mRGBIndex; + int mTotalAvail; + int mStatus[MAX_PIPES]; +}; + + +class MDPComp { + enum State { + MDPCOMP_ON = 0, + MDPCOMP_OFF, + MDPCOMP_OFF_PENDING, + }; + + enum { + MDPCOMP_LAYER_BLEND = 1, + MDPCOMP_LAYER_DOWNSCALE = 2, + MDPCOMP_LAYER_SKIP = 4, + MDPCOMP_LAYER_UNSUPPORTED_MEM = 8, + }; + + struct mdp_pipe_info { + int index; + int z_order; + bool isVG; + bool isFG; + bool vsync_wait; + }; + + struct pipe_layer_pair { + int layer_index; + mdp_pipe_info pipe_index; + native_handle_t* handle; + }; + + struct frame_info { + int count; + struct pipe_layer_pair* pipe_layer; + + }; + + struct layer_mdp_info { + bool can_use_mdp; + int pipe_pref; + }; + + static State sMDPCompState; + static IdleInvalidator *idleInvalidator; + static struct frame_info sCurrentFrame; + static PipeMgr sPipeMgr; + static int sSkipCount; + static int sMaxLayers; + static bool sDebugLogs; + static bool sIdleFallBack; + +public: + /* Handler to invoke frame redraw on Idle Timer expiry */ + static void timeout_handler(void *udata); + + /* configure/tear-down MDPComp params*/ + static bool init(hwc_context_t *ctx); + static bool deinit(); + + /*sets up mdp comp for the current frame */ + static bool configure(hwc_composer_device_t *ctx, hwc_layer_list_t* list); + + /* draw */ + static int draw(hwc_context_t *ctx, hwc_layer_list_t *list); + + /* store frame stats */ + static void setStats(int skipCt) { sSkipCount = skipCt;}; + +private: + + /* get/set pipe index associated with overlay layers */ + static void setLayerIndex(hwc_layer_t* layer, const int pipe_index); + static int getLayerIndex(hwc_layer_t* layer); + + /* set/reset flags for MDPComp */ + static void setMDPCompLayerFlags(hwc_layer_list_t* list); + static void unsetMDPCompLayerFlags(hwc_context_t* ctx, + hwc_layer_list_t* list); + + static void print_info(hwc_layer_t* layer); + + /* configure's overlay pipes for the frame */ + static int prepare(hwc_context_t *ctx, hwc_layer_t *layer, + mdp_pipe_info& mdp_info); + + /* checks for conditions where mdpcomp is not possible */ + static bool is_doable(hwc_composer_device_t *dev, + const hwc_layer_list_t* list); + + static bool setup(hwc_context_t* ctx, hwc_layer_list_t* list); + + /* parses layer for properties affecting mdp comp */ + static void get_layer_info(hwc_layer_t* layer, int& flags); + + /* iterates through layer list to choose candidate to use overlay */ + static int mark_layers(hwc_layer_list_t* list, layer_mdp_info* layer_info, + frame_info& current_frame); + static bool parse_and_allocate(hwc_context_t* ctx, hwc_layer_list_t* list, + frame_info& current_frame ); + + /* clears layer info struct */ + static void reset_layer_mdp_info(layer_mdp_info* layer_mdp_info,int count); + + /* allocates pipes to selected candidates */ + static bool alloc_layer_pipes(hwc_layer_list_t* list, + layer_mdp_info* layer_info, + frame_info& current_frame); + /* updates variable pipe mode for the current frame */ + static int configure_var_pipe(hwc_context_t* ctx); + + /* get/set states */ + static State get_state() { return sMDPCompState; }; + static void set_state(State state) { sMDPCompState = state; }; + + /* reset state */ + static void reset( hwc_context_t *ctx, hwc_layer_list_t* list ); + + /* Is feature enabled */ + static bool isEnabled() { return sMaxLayers ? true : false; }; + /* Is debug enabled */ + static bool isDebug() { return sDebugLogs ? true : false; }; +}; +}; //namespace +#endif diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp index 870a758..0b62a98 100644 --- a/libhwcomposer/hwc_utils.cpp +++ b/libhwcomposer/hwc_utils.cpp @@ -22,6 +22,7 @@ #include "hwc_qbuf.h" #include "hwc_copybit.h" #include "hwc_external.h" +#include "hwc_mdpcomp.h" namespace qhwc { @@ -43,6 +44,7 @@ void initContext(hwc_context_t *ctx) ctx->hasOverlay = qdutils::MDPVersion::getInstance().hasOverlay(); ctx->mCopybitEngine = CopybitEngine::getInstance(); ctx->mExtDisplay = new ExternalDisplay(ctx); + MDPComp::init(ctx); init_uevent_thread(ctx); @@ -103,6 +105,7 @@ void getLayerStats(hwc_context_t *ctx, const hwc_layer_list_t *list) int yuvCount = 0; int yuvLayerIndex = -1; bool isYuvLayerSkip = false; + int skipCount = 0; for (size_t i = 0; i < list->numHwLayers; i++) { private_handle_t *hnd = @@ -120,11 +123,13 @@ void getLayerStats(hwc_context_t *ctx, const hwc_layer_list_t *list) if(yuvLayerIndex != -1 && yuvLayerIndex < (ssize_t)i) { isYuvLayerSkip = true; } + skipCount++; } } VideoOverlay::setStats(yuvCount, yuvLayerIndex, isYuvLayerSkip); CopyBit::setStats(yuvCount, yuvLayerIndex, isYuvLayerSkip); + MDPComp::setStats(skipCount); ctx->numHwLayers = list->numHwLayers; return; diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h index 1e405f7..a6c1446 100644 --- a/libhwcomposer/hwc_utils.h +++ b/libhwcomposer/hwc_utils.h @@ -50,6 +50,12 @@ enum HWCCompositionType { HWC_USE_COPYBIT // This layer is to be handled by copybit }; +enum { + HWC_MDPCOMP = 0x00000002, + HWC_LAYER_RESERVED_0 = 0x00000004, + HWC_LAYER_RESERVED_1 = 0x00000008 +}; + class ExternalDisplay; class CopybitEngine; @@ -81,6 +87,13 @@ static inline bool isBufferLocked(const private_handle_t* hnd) { // Initialize uevent thread void init_uevent_thread(hwc_context_t* ctx); +inline void getLayerResolution(const hwc_layer_t* layer, + int& width, int& height) +{ + hwc_rect_t displayFrame = layer->displayFrame; + width = displayFrame.right - displayFrame.left; + height = displayFrame.bottom - displayFrame.top; +} }; //qhwc namespace // ----------------------------------------------------------------------------- diff --git a/libqdutils/Android.mk b/libqdutils/Android.mk index dfeae09..61daeac 100644 --- a/libqdutils/Android.mk +++ b/libqdutils/Android.mk @@ -8,5 +8,6 @@ LOCAL_SHARED_LIBRARIES := $(common_libs) LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes) LOCAL_CFLAGS := $(common_flags) LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) -LOCAL_SRC_FILES := profiler.cpp mdp_version.cpp +LOCAL_SRC_FILES := profiler.cpp mdp_version.cpp \ + idle_invalidator.cpp include $(BUILD_SHARED_LIBRARY) diff --git a/libqdutils/idle_invalidator.cpp b/libqdutils/idle_invalidator.cpp old mode 100644 new mode 100755 index 0b98e11..d0c0f73 --- a/libqdutils/idle_invalidator.cpp +++ b/libqdutils/idle_invalidator.cpp @@ -27,10 +27,10 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "IdleInvalidator.h" +#include "idle_invalidator.h" #include -#define II_DEBUG 1 +#define II_DEBUG 0 static const char *threadName = "Invalidator"; InvalidatorHandler IdleInvalidator::mHandler = NULL; @@ -38,12 +38,12 @@ android::sp IdleInvalidator::sInstance(0); IdleInvalidator::IdleInvalidator(): Thread(false), mHwcContext(0), mSleepAgain(false), mSleepTime(0) { - ALOGE_IF(II_DEBUG, "shs %s", __func__); + ALOGD_IF(II_DEBUG, "%s", __func__); } int IdleInvalidator::init(InvalidatorHandler reg_handler, void* user_data, unsigned int idleSleepTime) { - ALOGE_IF(II_DEBUG, "shs %s", __func__); + ALOGD_IF(II_DEBUG, "%s", __func__); /* store registered handler */ mHandler = reg_handler; @@ -53,8 +53,8 @@ int IdleInvalidator::init(InvalidatorHandler reg_handler, void* user_data, } bool IdleInvalidator::threadLoop() { - ALOGE_IF(II_DEBUG, "shs %s", __func__); - usleep(mSleepTime * 1000); + ALOGD_IF(II_DEBUG, "%s", __func__); + usleep(mSleepTime * 500); if(mSleepAgain) { //We need to sleep again! mSleepAgain = false; @@ -66,12 +66,12 @@ bool IdleInvalidator::threadLoop() { } int IdleInvalidator::readyToRun() { - ALOGE_IF(II_DEBUG, "shs %s", __func__); + ALOGD_IF(II_DEBUG, "%s", __func__); return 0; /*NO_ERROR*/ } void IdleInvalidator::onFirstRef() { - ALOGE_IF(II_DEBUG, "shs %s", __func__); + ALOGD_IF(II_DEBUG, "%s", __func__); } void IdleInvalidator::markForSleep() { @@ -81,7 +81,7 @@ void IdleInvalidator::markForSleep() { } IdleInvalidator *IdleInvalidator::getInstance() { - ALOGE_IF(II_DEBUG, "shs %s", __func__); + ALOGD_IF(II_DEBUG, "%s", __func__); if(sInstance.get() == NULL) sInstance = new IdleInvalidator(); return sInstance.get();