hwc_mdpcomp.cpp revision 832fb268445bd30f2a44a7e34e6fcc2da31c6ffc
1/*
2 * Copyright (C) 2012-2013, The Linux Foundation. All rights reserved.
3 * Not a Contribution, Apache license notifications and license are retained
4 * for attribution purposes only.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *      http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19#include <math.h>
20#include "hwc_mdpcomp.h"
21#include <sys/ioctl.h>
22#include "external.h"
23#include "qdMetaData.h"
24#include "mdp_version.h"
25#include <overlayRotator.h>
26
27using namespace overlay;
28using namespace qdutils;
29using namespace overlay::utils;
30namespace ovutils = overlay::utils;
31
32namespace qhwc {
33
34//==============MDPComp========================================================
35
36IdleInvalidator *MDPComp::idleInvalidator = NULL;
37bool MDPComp::sIdleFallBack = false;
38bool MDPComp::sDebugLogs = false;
39bool MDPComp::sEnabled = false;
40bool MDPComp::sEnableMixedMode = true;
41int MDPComp::sMaxPipesPerMixer = MAX_PIPES_PER_MIXER;
42
43MDPComp* MDPComp::getObject(const int& width, const int& rightSplit,
44        const int& dpy) {
45    if(width > MAX_DISPLAY_DIM || rightSplit) {
46        return new MDPCompHighRes(dpy);
47    }
48    return new MDPCompLowRes(dpy);
49}
50
51MDPComp::MDPComp(int dpy):mDpy(dpy){};
52
53void MDPComp::dump(android::String8& buf)
54{
55    Locker::Autolock _l(mMdpCompLock);
56    dumpsys_log(buf,"HWC Map for Dpy: %s \n",
57                mDpy ? "\"EXTERNAL\"" : "\"PRIMARY\"");
58    dumpsys_log(buf,"PREV_FRAME: layerCount:%2d    mdpCount:%2d \
59                cacheCount:%2d \n", mCachedFrame.layerCount,
60                mCachedFrame.mdpCount, mCachedFrame.cacheCount);
61    dumpsys_log(buf,"CURR_FRAME: layerCount:%2d    mdpCount:%2d \
62                fbCount:%2d \n", mCurrentFrame.layerCount,
63                mCurrentFrame.mdpCount, mCurrentFrame.fbCount);
64    dumpsys_log(buf,"needsFBRedraw:%3s  pipesUsed:%2d  MaxPipesPerMixer: %d \n",
65                (mCurrentFrame.needsRedraw? "YES" : "NO"),
66                mCurrentFrame.mdpCount, sMaxPipesPerMixer);
67    dumpsys_log(buf," ---------------------------------------------  \n");
68    dumpsys_log(buf," listIdx | cached? | mdpIndex | comptype  |  Z  \n");
69    dumpsys_log(buf," ---------------------------------------------  \n");
70    for(int index = 0; index < mCurrentFrame.layerCount; index++ )
71        dumpsys_log(buf," %7d | %7s | %8d | %9s | %2d \n",
72                    index,
73                    (mCurrentFrame.isFBComposed[index] ? "YES" : "NO"),
74                    mCurrentFrame.layerToMDP[index],
75                    (mCurrentFrame.isFBComposed[index] ?
76                     (mCurrentFrame.needsRedraw ? "GLES" : "CACHE") : "MDP"),
77                    (mCurrentFrame.isFBComposed[index] ? mCurrentFrame.fbZ :
78    mCurrentFrame.mdpToLayer[mCurrentFrame.layerToMDP[index]].pipeInfo->zOrder));
79    dumpsys_log(buf,"\n");
80}
81
82bool MDPComp::init(hwc_context_t *ctx) {
83
84    if(!ctx) {
85        ALOGE("%s: Invalid hwc context!!",__FUNCTION__);
86        return false;
87    }
88
89    char property[PROPERTY_VALUE_MAX];
90
91    sEnabled = false;
92    if((property_get("persist.hwc.mdpcomp.enable", property, NULL) > 0) &&
93       (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
94        (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
95        sEnabled = true;
96        if(!setupBasePipe(ctx)) {
97            ALOGE("%s: Failed to setup primary base pipe", __FUNCTION__);
98            return false;
99        }
100    }
101
102    sEnableMixedMode = true;
103    if((property_get("debug.mdpcomp.mixedmode.disable", property, NULL) > 0) &&
104       (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
105        (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
106        sEnableMixedMode = false;
107    }
108
109    sDebugLogs = false;
110    if(property_get("debug.mdpcomp.logs", property, NULL) > 0) {
111        if(atoi(property) != 0)
112            sDebugLogs = true;
113    }
114
115    sMaxPipesPerMixer = MAX_PIPES_PER_MIXER;
116    if(property_get("debug.mdpcomp.maxpermixer", property, "-1") > 0) {
117        int val = atoi(property);
118        if(val >= 0)
119            sMaxPipesPerMixer = min(val, MAX_PIPES_PER_MIXER);
120    }
121
122    long idle_timeout = DEFAULT_IDLE_TIME;
123    if(property_get("debug.mdpcomp.idletime", property, NULL) > 0) {
124        if(atoi(property) != 0)
125            idle_timeout = atoi(property);
126    }
127
128    //create Idle Invalidator only when not disabled through property
129    if(idle_timeout != -1)
130        idleInvalidator = IdleInvalidator::getInstance();
131
132    if(idleInvalidator == NULL) {
133        ALOGE("%s: failed to instantiate idleInvalidator object", __FUNCTION__);
134    } else {
135        idleInvalidator->init(timeout_handler, ctx, idle_timeout);
136    }
137    return true;
138}
139
140void MDPComp::timeout_handler(void *udata) {
141    struct hwc_context_t* ctx = (struct hwc_context_t*)(udata);
142
143    if(!ctx) {
144        ALOGE("%s: received empty data in timer callback", __FUNCTION__);
145        return;
146    }
147
148    if(!ctx->proc) {
149        ALOGE("%s: HWC proc not registered", __FUNCTION__);
150        return;
151    }
152    sIdleFallBack = true;
153    /* Trigger SF to redraw the current frame */
154    ctx->proc->invalidate(ctx->proc);
155}
156
157void MDPComp::setMDPCompLayerFlags(hwc_context_t *ctx,
158                                   hwc_display_contents_1_t* list) {
159    LayerProp *layerProp = ctx->layerProp[mDpy];
160
161    for(int index = 0; index < ctx->listStats[mDpy].numAppLayers; index++) {
162        hwc_layer_1_t* layer = &(list->hwLayers[index]);
163        if(!mCurrentFrame.isFBComposed[index]) {
164            layerProp[index].mFlags |= HWC_MDPCOMP;
165            layer->compositionType = HWC_OVERLAY;
166            layer->hints |= HWC_HINT_CLEAR_FB;
167            mCachedFrame.hnd[index] = NULL;
168        } else {
169            if(!mCurrentFrame.needsRedraw)
170                layer->compositionType = HWC_OVERLAY;
171        }
172    }
173}
174
175/*
176 * Sets up BORDERFILL as default base pipe and detaches RGB0.
177 * Framebuffer is always updated using PLAY ioctl.
178 */
179bool MDPComp::setupBasePipe(hwc_context_t *ctx) {
180    const int dpy = HWC_DISPLAY_PRIMARY;
181    int fb_stride = ctx->dpyAttr[dpy].stride;
182    int fb_width = ctx->dpyAttr[dpy].xres;
183    int fb_height = ctx->dpyAttr[dpy].yres;
184    int fb_fd = ctx->dpyAttr[dpy].fd;
185
186    mdp_overlay ovInfo;
187    msmfb_overlay_data ovData;
188    memset(&ovInfo, 0, sizeof(mdp_overlay));
189    memset(&ovData, 0, sizeof(msmfb_overlay_data));
190
191    ovInfo.src.format = MDP_RGB_BORDERFILL;
192    ovInfo.src.width  = fb_width;
193    ovInfo.src.height = fb_height;
194    ovInfo.src_rect.w = fb_width;
195    ovInfo.src_rect.h = fb_height;
196    ovInfo.dst_rect.w = fb_width;
197    ovInfo.dst_rect.h = fb_height;
198    ovInfo.id = MSMFB_NEW_REQUEST;
199
200    if (ioctl(fb_fd, MSMFB_OVERLAY_SET, &ovInfo) < 0) {
201        ALOGE("Failed to call ioctl MSMFB_OVERLAY_SET err=%s",
202              strerror(errno));
203        return false;
204    }
205
206    ovData.id = ovInfo.id;
207    if (ioctl(fb_fd, MSMFB_OVERLAY_PLAY, &ovData) < 0) {
208        ALOGE("Failed to call ioctl MSMFB_OVERLAY_PLAY err=%s",
209              strerror(errno));
210        return false;
211    }
212    return true;
213}
214
215MDPComp::FrameInfo::FrameInfo() {
216    reset(0);
217}
218
219void MDPComp::FrameInfo::reset(const int& numLayers) {
220    for(int i = 0 ; i < MAX_PIPES_PER_MIXER && numLayers; i++ ) {
221        if(mdpToLayer[i].pipeInfo) {
222            delete mdpToLayer[i].pipeInfo;
223            mdpToLayer[i].pipeInfo = NULL;
224            //We dont own the rotator
225            mdpToLayer[i].rot = NULL;
226        }
227    }
228
229    memset(&mdpToLayer, 0, sizeof(mdpToLayer));
230    memset(&layerToMDP, -1, sizeof(layerToMDP));
231    memset(&isFBComposed, 1, sizeof(isFBComposed));
232
233    layerCount = numLayers;
234    fbCount = numLayers;
235    mdpCount = 0;
236    needsRedraw = true;
237    fbZ = 0;
238}
239
240void MDPComp::FrameInfo::map() {
241    // populate layer and MDP maps
242    int mdpIdx = 0;
243    for(int idx = 0; idx < layerCount; idx++) {
244        if(!isFBComposed[idx]) {
245            mdpToLayer[mdpIdx].listIndex = idx;
246            layerToMDP[idx] = mdpIdx++;
247        }
248    }
249}
250
251MDPComp::LayerCache::LayerCache() {
252    reset();
253}
254
255void MDPComp::LayerCache::reset() {
256    memset(&hnd, 0, sizeof(hnd));
257    mdpCount = 0;
258    cacheCount = 0;
259    layerCount = 0;
260    fbZ = -1;
261}
262
263void MDPComp::LayerCache::cacheAll(hwc_display_contents_1_t* list) {
264    const int numAppLayers = list->numHwLayers - 1;
265    for(int i = 0; i < numAppLayers; i++) {
266        hnd[i] = list->hwLayers[i].handle;
267    }
268}
269
270void MDPComp::LayerCache::updateCounts(const FrameInfo& curFrame) {
271    mdpCount = curFrame.mdpCount;
272    cacheCount = curFrame.fbCount;
273    layerCount = curFrame.layerCount;
274    fbZ = curFrame.fbZ;
275}
276
277bool MDPComp::isValidDimension(hwc_context_t *ctx, hwc_layer_1_t *layer) {
278    const int dpy = HWC_DISPLAY_PRIMARY;
279    private_handle_t *hnd = (private_handle_t *)layer->handle;
280
281    if(!hnd) {
282        ALOGE("%s: layer handle is NULL", __FUNCTION__);
283        return false;
284    }
285
286    int hw_w = ctx->dpyAttr[mDpy].xres;
287    int hw_h = ctx->dpyAttr[mDpy].yres;
288
289    hwc_rect_t crop = layer->sourceCrop;
290    hwc_rect_t dst = layer->displayFrame;
291
292    if(dst.left < 0 || dst.top < 0 || dst.right > hw_w || dst.bottom > hw_h) {
293       hwc_rect_t scissor = {0, 0, hw_w, hw_h };
294       qhwc::calculate_crop_rects(crop, dst, scissor, layer->transform);
295    }
296
297    int crop_w = crop.right - crop.left;
298    int crop_h = crop.bottom - crop.top;
299    int dst_w = dst.right - dst.left;
300    int dst_h = dst.bottom - dst.top;
301    float w_dscale = ceilf((float)crop_w / (float)dst_w);
302    float h_dscale = ceilf((float)crop_h / (float)dst_h);
303
304    //Workaround for MDP HW limitation in DSI command mode panels where
305    //FPS will not go beyond 30 if buffers on RGB pipes are of width < 5
306
307    if((crop_w < 5)||(crop_h < 5))
308        return false;
309
310    const uint32_t downscale =
311            qdutils::MDPVersion::getInstance().getMaxMDPDownscale();
312    if(ctx->mMDP.version >= qdutils::MDSS_V5) {
313        if(!qdutils::MDPVersion::getInstance().supportsDecimation()) {
314            if(crop_w > MAX_DISPLAY_DIM || w_dscale > downscale ||
315                    h_dscale > downscale)
316                return false;
317        } else if(w_dscale > 64 || h_dscale > 64) {
318            return false;
319        }
320    } else { //A-family
321        if(w_dscale > downscale || h_dscale > downscale)
322            return false;
323    }
324
325    return true;
326}
327
328ovutils::eDest MDPComp::getMdpPipe(hwc_context_t *ctx, ePipeType type) {
329    overlay::Overlay& ov = *ctx->mOverlay;
330    ovutils::eDest mdp_pipe = ovutils::OV_INVALID;
331
332    switch(type) {
333    case MDPCOMP_OV_DMA:
334        mdp_pipe = ov.nextPipe(ovutils::OV_MDP_PIPE_DMA, mDpy);
335        if(mdp_pipe != ovutils::OV_INVALID) {
336            return mdp_pipe;
337        }
338    case MDPCOMP_OV_ANY:
339    case MDPCOMP_OV_RGB:
340        mdp_pipe = ov.nextPipe(ovutils::OV_MDP_PIPE_RGB, mDpy);
341        if(mdp_pipe != ovutils::OV_INVALID) {
342            return mdp_pipe;
343        }
344
345        if(type == MDPCOMP_OV_RGB) {
346            //Requested only for RGB pipe
347            break;
348        }
349    case  MDPCOMP_OV_VG:
350        return ov.nextPipe(ovutils::OV_MDP_PIPE_VG, mDpy);
351    default:
352        ALOGE("%s: Invalid pipe type",__FUNCTION__);
353        return ovutils::OV_INVALID;
354    };
355    return ovutils::OV_INVALID;
356}
357
358bool MDPComp::isFrameDoable(hwc_context_t *ctx) {
359    bool ret = true;
360    const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
361
362    if(!isEnabled()) {
363        ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled.", __FUNCTION__);
364        ret = false;
365    } else if(qdutils::MDPVersion::getInstance().is8x26() &&
366            ctx->mVideoTransFlag &&
367            ctx->mExtDisplay->isExternalConnected()) {
368        //1 Padding round to shift pipes across mixers
369        ALOGD_IF(isDebug(),"%s: MDP Comp. video transition padding round",
370                __FUNCTION__);
371        ret = false;
372    } else if(ctx->mExtDispConfiguring) {
373        ALOGD_IF( isDebug(),"%s: External Display connection is pending",
374                  __FUNCTION__);
375        ret = false;
376    } else if(ctx->isPaddingRound) {
377        ctx->isPaddingRound = false;
378        ALOGD_IF(isDebug(), "%s: padding round",__FUNCTION__);
379        ret = false;
380    }
381    return ret;
382}
383
384/* Checks for conditions where all the layers marked for MDP comp cannot be
385 * bypassed. On such conditions we try to bypass atleast YUV layers */
386bool MDPComp::isFullFrameDoable(hwc_context_t *ctx,
387                                hwc_display_contents_1_t* list){
388
389    const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
390
391    if(sIdleFallBack) {
392        ALOGD_IF(isDebug(), "%s: Idle fallback dpy %d",__FUNCTION__, mDpy);
393        return false;
394    }
395
396    if(mDpy > HWC_DISPLAY_PRIMARY){
397        ALOGD_IF(isDebug(), "%s: Cannot support External display(s)",
398                 __FUNCTION__);
399        return false;
400    }
401
402    if(isSkipPresent(ctx, mDpy)) {
403        ALOGD_IF(isDebug(),"%s: SKIP present: %d",
404                __FUNCTION__,
405                isSkipPresent(ctx, mDpy));
406        return false;
407    }
408
409    if(ctx->listStats[mDpy].planeAlpha
410                     && ctx->mMDP.version >= qdutils::MDSS_V5) {
411        ALOGD_IF(isDebug(), "%s: plane alpha not implemented on MDSS",
412                 __FUNCTION__);
413        return false;
414    }
415
416    if(ctx->listStats[mDpy].needsAlphaScale
417       && ctx->mMDP.version < qdutils::MDSS_V5) {
418        ALOGD_IF(isDebug(), "%s: frame needs alpha downscaling",__FUNCTION__);
419        return false;
420    }
421
422    //MDP composition is not efficient if layer needs rotator.
423    for(int i = 0; i < numAppLayers; ++i) {
424        // As MDP h/w supports flip operation, use MDP comp only for
425        // 180 transforms. Fail for any transform involving 90 (90, 270).
426        hwc_layer_1_t* layer = &list->hwLayers[i];
427        private_handle_t *hnd = (private_handle_t *)layer->handle;
428        if(isYuvBuffer(hnd) ) {
429            if(isSecuring(ctx, layer)) {
430                ALOGD_IF(isDebug(), "%s: MDP securing is active", __FUNCTION__);
431                return false;
432            }
433        } else if(layer->transform & HWC_TRANSFORM_ROT_90) {
434            ALOGD_IF(isDebug(), "%s: orientation involved",__FUNCTION__);
435            return false;
436        }
437
438        if(!isValidDimension(ctx,layer)) {
439            ALOGD_IF(isDebug(), "%s: Buffer is of invalid width",
440                __FUNCTION__);
441            return false;
442        }
443
444        //For 8x26 with panel width>1k, if RGB layer needs HFLIP fail mdp comp
445        // may not need it if Gfx pre-rotation can handle all flips & rotations
446        if(qdutils::MDPVersion::getInstance().is8x26() &&
447                                (ctx->dpyAttr[mDpy].xres > 1024) &&
448                                (layer->transform & HWC_TRANSFORM_FLIP_H) &&
449                                (!isYuvBuffer(hnd)))
450                   return false;
451    }
452
453    //If all above hard conditions are met we can do full or partial MDP comp.
454    bool ret = false;
455    if(fullMDPComp(ctx, list)) {
456        ret = true;
457    } else if(partialMDPComp(ctx, list)) {
458        ret = true;
459    }
460    return ret;
461}
462
463bool MDPComp::fullMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
464    //Setup mCurrentFrame
465    mCurrentFrame.mdpCount = mCurrentFrame.layerCount;
466    mCurrentFrame.fbCount = 0;
467    mCurrentFrame.fbZ = -1;
468    memset(&mCurrentFrame.isFBComposed, 0, sizeof(mCurrentFrame.isFBComposed));
469
470    int mdpCount = mCurrentFrame.mdpCount;
471    if(mdpCount > sMaxPipesPerMixer) {
472        ALOGD_IF(isDebug(), "%s: Exceeds MAX_PIPES_PER_MIXER",__FUNCTION__);
473        return false;
474    }
475
476    int numPipesNeeded = pipesNeeded(ctx, list);
477    int availPipes = getAvailablePipes(ctx);
478
479    if(numPipesNeeded > availPipes) {
480        ALOGD_IF(isDebug(), "%s: Insufficient MDP pipes, needed %d, avail %d",
481                __FUNCTION__, numPipesNeeded, availPipes);
482        return false;
483    }
484
485    return true;
486}
487
488bool MDPComp::partialMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list)
489{
490    int numAppLayers = ctx->listStats[mDpy].numAppLayers;
491
492    if(!sEnableMixedMode) {
493        //Mixed mode is disabled. No need to even try caching.
494        return false;
495    }
496
497    //Setup mCurrentFrame
498    mCurrentFrame.reset(numAppLayers);
499    updateLayerCache(ctx, list);
500    updateYUV(ctx, list);
501    batchLayers(); //sets up fbZ also
502
503    int mdpCount = mCurrentFrame.mdpCount;
504    if(mdpCount > (sMaxPipesPerMixer - 1)) { // -1 since FB is used
505        ALOGD_IF(isDebug(), "%s: Exceeds MAX_PIPES_PER_MIXER",__FUNCTION__);
506        return false;
507    }
508
509    int numPipesNeeded = pipesNeeded(ctx, list);
510    int availPipes = getAvailablePipes(ctx);
511
512    if(numPipesNeeded > availPipes) {
513        ALOGD_IF(isDebug(), "%s: Insufficient MDP pipes, needed %d, avail %d",
514                __FUNCTION__, numPipesNeeded, availPipes);
515        return false;
516    }
517
518    return true;
519}
520
521bool MDPComp::isOnlyVideoDoable(hwc_context_t *ctx,
522        hwc_display_contents_1_t* list){
523    int numAppLayers = ctx->listStats[mDpy].numAppLayers;
524    mCurrentFrame.reset(numAppLayers);
525    updateYUV(ctx, list);
526    int mdpCount = mCurrentFrame.mdpCount;
527    int fbNeeded = int(mCurrentFrame.fbCount != 0);
528
529    if(!isYuvPresent(ctx, mDpy)) {
530        return false;
531    }
532
533    if(!mdpCount)
534        return false;
535
536    if(mdpCount > (sMaxPipesPerMixer - fbNeeded)) {
537        ALOGD_IF(isDebug(), "%s: Exceeds MAX_PIPES_PER_MIXER",__FUNCTION__);
538        return false;
539    }
540
541    int numPipesNeeded = pipesNeeded(ctx, list);
542    int availPipes = getAvailablePipes(ctx);
543    if(numPipesNeeded > availPipes) {
544        ALOGD_IF(isDebug(), "%s: Insufficient MDP pipes, needed %d, avail %d",
545                __FUNCTION__, numPipesNeeded, availPipes);
546        return false;
547    }
548
549    int nYuvCount = ctx->listStats[mDpy].yuvCount;
550    for(int index = 0; index < nYuvCount ; index ++) {
551        int nYuvIndex = ctx->listStats[mDpy].yuvIndices[index];
552        hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex];
553        if(layer->planeAlpha < 0xFF) {
554            ALOGD_IF(isDebug(), "%s: Cannot handle YUV layer with plane alpha\
555                    in video only mode",
556                    __FUNCTION__);
557            return false;
558        }
559    }
560
561    return true;
562}
563
564/* Checks for conditions where YUV layers cannot be bypassed */
565bool MDPComp::isYUVDoable(hwc_context_t* ctx, hwc_layer_1_t* layer) {
566    if(isSkipLayer(layer)) {
567        ALOGE("%s: Unable to bypass skipped YUV", __FUNCTION__);
568        return false;
569    }
570
571    if(isSecuring(ctx, layer)) {
572        ALOGD_IF(isDebug(), "%s: MDP securing is active", __FUNCTION__);
573        return false;
574    }
575
576    if(!isValidDimension(ctx, layer)) {
577        ALOGD_IF(isDebug(), "%s: Buffer is of invalid width",
578            __FUNCTION__);
579        return false;
580    }
581
582    return true;
583}
584
585void  MDPComp::batchLayers() {
586    /* Idea is to keep as many contiguous non-updating(cached) layers in FB and
587     * send rest of them through MDP. NEVER mark an updating layer for caching.
588     * But cached ones can be marked for MDP*/
589
590    int maxBatchStart = -1;
591    int maxBatchCount = 0;
592
593    /* All or Nothing is cached. No batching needed */
594    if(!mCurrentFrame.fbCount) {
595        mCurrentFrame.fbZ = -1;
596        return;
597    }
598    if(!mCurrentFrame.mdpCount) {
599        mCurrentFrame.fbZ = 0;
600        return;
601    }
602
603    /* Search for max number of contiguous (cached) layers */
604    int i = 0;
605    while (i < mCurrentFrame.layerCount) {
606        int count = 0;
607        while(mCurrentFrame.isFBComposed[i] && i < mCurrentFrame.layerCount) {
608            count++; i++;
609        }
610        if(count > maxBatchCount) {
611            maxBatchCount = count;
612            maxBatchStart = i - count;
613            mCurrentFrame.fbZ = maxBatchStart;
614        }
615        if(i < mCurrentFrame.layerCount) i++;
616    }
617
618    /* reset rest of the layers for MDP comp */
619    for(int i = 0; i < mCurrentFrame.layerCount; i++) {
620        if(i != maxBatchStart){
621            mCurrentFrame.isFBComposed[i] = false;
622        } else {
623            i += maxBatchCount;
624        }
625    }
626
627    mCurrentFrame.fbCount = maxBatchCount;
628    mCurrentFrame.mdpCount = mCurrentFrame.layerCount -
629            mCurrentFrame.fbCount;
630
631    ALOGD_IF(isDebug(),"%s: cached count: %d",__FUNCTION__,
632             mCurrentFrame.fbCount);
633}
634
635void MDPComp::updateLayerCache(hwc_context_t* ctx,
636                               hwc_display_contents_1_t* list) {
637
638    int numAppLayers = ctx->listStats[mDpy].numAppLayers;
639    int numCacheableLayers = 0;
640
641    for(int i = 0; i < numAppLayers; i++) {
642        if (mCachedFrame.hnd[i] == list->hwLayers[i].handle) {
643            numCacheableLayers++;
644            mCurrentFrame.isFBComposed[i] = true;
645        } else {
646            mCurrentFrame.isFBComposed[i] = false;
647            mCachedFrame.hnd[i] = list->hwLayers[i].handle;
648        }
649    }
650
651    mCurrentFrame.fbCount = numCacheableLayers;
652    mCurrentFrame.mdpCount = mCurrentFrame.layerCount -
653            mCurrentFrame.fbCount;
654    ALOGD_IF(isDebug(),"%s: cached count: %d",__FUNCTION__, numCacheableLayers);
655}
656
657int MDPComp::getAvailablePipes(hwc_context_t* ctx) {
658    int numDMAPipes = qdutils::MDPVersion::getInstance().getDMAPipes();
659    overlay::Overlay& ov = *ctx->mOverlay;
660
661    int numAvailable = ov.availablePipes(mDpy);
662
663    //Reserve DMA for rotator
664    if(Overlay::getDMAMode() == Overlay::DMA_BLOCK_MODE)
665        numAvailable -= numDMAPipes;
666
667    //Reserve pipe(s)for FB
668    if(mCurrentFrame.fbCount)
669        numAvailable -= pipesForFB();
670
671    return numAvailable;
672}
673
674void MDPComp::updateYUV(hwc_context_t* ctx, hwc_display_contents_1_t* list) {
675
676    int nYuvCount = ctx->listStats[mDpy].yuvCount;
677    for(int index = 0;index < nYuvCount; index++){
678        int nYuvIndex = ctx->listStats[mDpy].yuvIndices[index];
679        hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex];
680
681        if(!isYUVDoable(ctx, layer)) {
682            if(!mCurrentFrame.isFBComposed[nYuvIndex]) {
683                mCurrentFrame.isFBComposed[nYuvIndex] = true;
684                mCurrentFrame.fbCount++;
685            }
686        } else {
687            if(mCurrentFrame.isFBComposed[nYuvIndex]) {
688                mCurrentFrame.isFBComposed[nYuvIndex] = false;
689                mCurrentFrame.fbCount--;
690            }
691        }
692    }
693
694    mCurrentFrame.mdpCount = mCurrentFrame.layerCount -
695            mCurrentFrame.fbCount;
696    ALOGD_IF(isDebug(),"%s: cached count: %d",__FUNCTION__,
697             mCurrentFrame.fbCount);
698}
699
700bool MDPComp::programMDP(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
701    if(!allocLayerPipes(ctx, list)) {
702        ALOGD_IF(isDebug(), "%s: Unable to allocate MDP pipes", __FUNCTION__);
703        return false;
704    }
705
706    bool fbBatch = false;
707    for (int index = 0, mdpNextZOrder = 0; index < mCurrentFrame.layerCount;
708            index++) {
709        if(!mCurrentFrame.isFBComposed[index]) {
710            int mdpIndex = mCurrentFrame.layerToMDP[index];
711            hwc_layer_1_t* layer = &list->hwLayers[index];
712
713            MdpPipeInfo* cur_pipe = mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
714            cur_pipe->zOrder = mdpNextZOrder++;
715
716            if(configure(ctx, layer, mCurrentFrame.mdpToLayer[mdpIndex]) != 0 ){
717                ALOGD_IF(isDebug(), "%s: Failed to configure overlay for \
718                         layer %d",__FUNCTION__, index);
719                return false;
720            }
721        } else if(fbBatch == false) {
722                mdpNextZOrder++;
723                fbBatch = true;
724        }
725    }
726
727    return true;
728}
729
730bool MDPComp::programYUV(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
731    if(!allocLayerPipes(ctx, list)) {
732        ALOGD_IF(isDebug(), "%s: Unable to allocate MDP pipes", __FUNCTION__);
733        return false;
734    }
735    //If we are in this block, it means we have yuv + rgb layers both
736    int mdpIdx = 0;
737    for (int index = 0; index < mCurrentFrame.layerCount; index++) {
738        if(!mCurrentFrame.isFBComposed[index]) {
739            hwc_layer_1_t* layer = &list->hwLayers[index];
740            int mdpIndex = mCurrentFrame.layerToMDP[index];
741            MdpPipeInfo* cur_pipe =
742                    mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
743            cur_pipe->zOrder = mdpIdx++;
744
745            if(configure(ctx, layer,
746                        mCurrentFrame.mdpToLayer[mdpIndex]) != 0 ){
747                ALOGD_IF(isDebug(), "%s: Failed to configure overlay for \
748                        layer %d",__FUNCTION__, index);
749                return false;
750            }
751        }
752    }
753    return true;
754}
755
756int MDPComp::prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
757
758    const int numLayers = ctx->listStats[mDpy].numAppLayers;
759
760    { //LOCK SCOPE BEGIN
761        Locker::Autolock _l(mMdpCompLock);
762
763        //reset old data
764        mCurrentFrame.reset(numLayers);
765
766        //number of app layers exceeds MAX_NUM_APP_LAYERS fall back to GPU
767        //do not cache the information for next draw cycle.
768        if(numLayers > MAX_NUM_APP_LAYERS) {
769            mCachedFrame.updateCounts(mCurrentFrame);
770            ALOGD_IF(isDebug(), "%s: Number of App layers exceeded the limit ",
771                                    __FUNCTION__);
772            return 0;
773        }
774
775        //Hard conditions, if not met, cannot do MDP comp
776        if(!isFrameDoable(ctx)) {
777            ALOGD_IF( isDebug(),"%s: MDP Comp not possible for this frame",
778                                    __FUNCTION__);
779            mCurrentFrame.reset(numLayers);
780            mCachedFrame.cacheAll(list);
781            mCachedFrame.updateCounts(mCurrentFrame);
782            return 0;
783        }
784
785        //Check whether layers marked for MDP Composition is actually doable.
786        if(isFullFrameDoable(ctx, list)){
787            mCurrentFrame.map();
788            //Acquire and Program MDP pipes
789            if(!programMDP(ctx, list)) {
790                mCurrentFrame.reset(numLayers);
791                mCachedFrame.cacheAll(list);
792            } else { //Success
793                //Any change in composition types needs an FB refresh
794                mCurrentFrame.needsRedraw = false;
795                if(mCurrentFrame.fbCount &&
796                        ((mCurrentFrame.mdpCount != mCachedFrame.mdpCount) ||
797                        (mCurrentFrame.fbCount != mCachedFrame.cacheCount) ||
798                        (mCurrentFrame.fbZ != mCachedFrame.fbZ) ||
799                        (!mCurrentFrame.mdpCount) ||
800                        (list->flags & HWC_GEOMETRY_CHANGED) ||
801                        isSkipPresent(ctx, mDpy) ||
802                        (mDpy > HWC_DISPLAY_PRIMARY))) {
803                    mCurrentFrame.needsRedraw = true;
804                }
805            }
806        } else if(isOnlyVideoDoable(ctx, list)) {
807            //All layers marked for MDP comp cannot be bypassed.
808            //Try to compose atleast YUV layers through MDP comp and let
809            //all the RGB layers compose in FB
810            //Destination over
811            mCurrentFrame.fbZ = -1;
812            if(mCurrentFrame.fbCount)
813                mCurrentFrame.fbZ = mCurrentFrame.mdpCount;
814
815            mCurrentFrame.map();
816            if(!programYUV(ctx, list)) {
817                mCurrentFrame.reset(numLayers);
818                mCachedFrame.cacheAll(list);
819            }
820        } else {
821            mCurrentFrame.reset(numLayers);
822            mCachedFrame.cacheAll(list);
823        }
824
825        //UpdateLayerFlags
826        setMDPCompLayerFlags(ctx, list);
827        mCachedFrame.updateCounts(mCurrentFrame);
828
829    } //LOCK SCOPE END. dump also need this lock.
830    // unlock it before calling dump function to avoid deadlock
831    if(isDebug()) {
832        ALOGD("GEOMETRY change: %d", (list->flags & HWC_GEOMETRY_CHANGED));
833        android::String8 sDump("");
834        dump(sDump);
835        ALOGE("%s",sDump.string());
836    }
837
838    return mCurrentFrame.fbZ;
839}
840
841//=============MDPCompLowRes===================================================
842
843/*
844 * Configures pipe(s) for MDP composition
845 */
846int MDPCompLowRes::configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
847                             PipeLayerPair& PipeLayerPair) {
848    MdpPipeInfoLowRes& mdp_info =
849        *(static_cast<MdpPipeInfoLowRes*>(PipeLayerPair.pipeInfo));
850    eMdpFlags mdpFlags = OV_MDP_BACKEND_COMPOSITION;
851    eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder);
852    eIsFg isFg = IS_FG_OFF;
853    eDest dest = mdp_info.index;
854
855    ALOGD_IF(isDebug(),"%s: configuring: layer: %p z_order: %d dest_pipe: %d",
856             __FUNCTION__, layer, zOrder, dest);
857
858    return configureLowRes(ctx, layer, mDpy, mdpFlags, zOrder, isFg, dest,
859                           &PipeLayerPair.rot);
860}
861
862int MDPCompLowRes::pipesNeeded(hwc_context_t *ctx,
863                               hwc_display_contents_1_t* list) {
864    return mCurrentFrame.mdpCount;
865}
866
867bool MDPCompLowRes::allocLayerPipes(hwc_context_t *ctx,
868        hwc_display_contents_1_t* list) {
869    for(int index = 0; index < mCurrentFrame.layerCount; index++) {
870
871        if(mCurrentFrame.isFBComposed[index]) continue;
872
873        hwc_layer_1_t* layer = &list->hwLayers[index];
874        private_handle_t *hnd = (private_handle_t *)layer->handle;
875        int mdpIndex = mCurrentFrame.layerToMDP[index];
876        PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
877        info.pipeInfo = new MdpPipeInfoLowRes;
878        info.rot = NULL;
879        MdpPipeInfoLowRes& pipe_info = *(MdpPipeInfoLowRes*)info.pipeInfo;
880        ePipeType type = MDPCOMP_OV_ANY;
881
882        if(isYuvBuffer(hnd)) {
883            type = MDPCOMP_OV_VG;
884        } else if(!qhwc::needsScaling(ctx, layer, mDpy)
885            && Overlay::getDMAMode() != Overlay::DMA_BLOCK_MODE
886            && ctx->mMDP.version >= qdutils::MDSS_V5) {
887            type = MDPCOMP_OV_DMA;
888        }
889
890        pipe_info.index = getMdpPipe(ctx, type);
891        if(pipe_info.index == ovutils::OV_INVALID) {
892            ALOGD_IF(isDebug(), "%s: Unable to get pipe type = %d",
893                __FUNCTION__, (int) type);
894            return false;
895        }
896    }
897    return true;
898}
899
900bool MDPCompLowRes::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
901
902    if(!isEnabled()) {
903        ALOGD_IF(isDebug(),"%s: MDP Comp not configured", __FUNCTION__);
904        return true;
905    }
906
907    if(!ctx || !list) {
908        ALOGE("%s: invalid contxt or list",__FUNCTION__);
909        return false;
910    }
911
912    if(ctx->listStats[mDpy].numAppLayers > MAX_NUM_APP_LAYERS) {
913        ALOGD_IF(isDebug(),"%s: Exceeding max layer count", __FUNCTION__);
914        return true;
915    }
916
917    Locker::Autolock _l(mMdpCompLock);
918
919    /* reset Invalidator */
920    if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount)
921        idleInvalidator->markForSleep();
922
923    overlay::Overlay& ov = *ctx->mOverlay;
924    LayerProp *layerProp = ctx->layerProp[mDpy];
925
926    int numHwLayers = ctx->listStats[mDpy].numAppLayers;
927    for(int i = 0; i < numHwLayers && mCurrentFrame.mdpCount; i++ )
928    {
929        if(mCurrentFrame.isFBComposed[i]) continue;
930
931        hwc_layer_1_t *layer = &list->hwLayers[i];
932        private_handle_t *hnd = (private_handle_t *)layer->handle;
933        if(!hnd) {
934            ALOGE("%s handle null", __FUNCTION__);
935            return false;
936        }
937
938        int mdpIndex = mCurrentFrame.layerToMDP[i];
939
940        MdpPipeInfoLowRes& pipe_info =
941            *(MdpPipeInfoLowRes*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
942        ovutils::eDest dest = pipe_info.index;
943        if(dest == ovutils::OV_INVALID) {
944            ALOGE("%s: Invalid pipe index (%d)", __FUNCTION__, dest);
945            return false;
946        }
947
948        if(!(layerProp[i].mFlags & HWC_MDPCOMP)) {
949            continue;
950        }
951
952        ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
953                 using  pipe: %d", __FUNCTION__, layer,
954                 hnd, dest );
955
956        int fd = hnd->fd;
957        uint32_t offset = hnd->offset;
958        Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
959        if(rot) {
960            if(!rot->queueBuffer(fd, offset))
961                return false;
962            fd = rot->getDstMemId();
963            offset = rot->getDstOffset();
964        }
965
966        if (!ov.queueBuffer(fd, offset, dest)) {
967            ALOGE("%s: queueBuffer failed for display:%d ", __FUNCTION__, mDpy);
968            return false;
969        }
970
971        layerProp[i].mFlags &= ~HWC_MDPCOMP;
972    }
973    return true;
974}
975
976//=============MDPCompHighRes===================================================
977
978int MDPCompHighRes::pipesNeeded(hwc_context_t *ctx,
979        hwc_display_contents_1_t* list) {
980    int pipesNeeded = 0;
981    const int xres = ctx->dpyAttr[mDpy].xres;
982    //Default even split for all displays with high res
983    int lSplit = xres / 2;
984    if(mDpy == HWC_DISPLAY_PRIMARY &&
985            qdutils::MDPVersion::getInstance().getLeftSplit()) {
986        //Override if split published by driver for primary
987        lSplit = qdutils::MDPVersion::getInstance().getLeftSplit();
988    }
989
990    for(int i = 0; i < mCurrentFrame.layerCount; ++i) {
991        if(!mCurrentFrame.isFBComposed[i]) {
992            hwc_layer_1_t* layer = &list->hwLayers[i];
993            hwc_rect_t dst = layer->displayFrame;
994            if(dst.left > lSplit) {
995                pipesNeeded++;
996            } else if(dst.right <= lSplit) {
997                pipesNeeded++;
998            } else {
999                pipesNeeded += 2;
1000            }
1001        }
1002    }
1003    return pipesNeeded;
1004}
1005
1006bool MDPCompHighRes::acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer,
1007        MdpPipeInfoHighRes& pipe_info,
1008        ePipeType type) {
1009    const int xres = ctx->dpyAttr[mDpy].xres;
1010    //Default even split for all displays with high res
1011    int lSplit = xres / 2;
1012    if(mDpy == HWC_DISPLAY_PRIMARY &&
1013            qdutils::MDPVersion::getInstance().getLeftSplit()) {
1014        //Override if split published by driver for primary
1015        lSplit = qdutils::MDPVersion::getInstance().getLeftSplit();
1016    }
1017
1018    hwc_rect_t dst = layer->displayFrame;
1019    if(dst.left > lSplit) {
1020        pipe_info.lIndex = ovutils::OV_INVALID;
1021        pipe_info.rIndex = getMdpPipe(ctx, type);
1022        if(pipe_info.rIndex == ovutils::OV_INVALID)
1023            return false;
1024    } else if (dst.right <= lSplit) {
1025        pipe_info.rIndex = ovutils::OV_INVALID;
1026        pipe_info.lIndex = getMdpPipe(ctx, type);
1027        if(pipe_info.lIndex == ovutils::OV_INVALID)
1028            return false;
1029    } else {
1030        pipe_info.rIndex = getMdpPipe(ctx, type);
1031        pipe_info.lIndex = getMdpPipe(ctx, type);
1032        if(pipe_info.rIndex == ovutils::OV_INVALID ||
1033           pipe_info.lIndex == ovutils::OV_INVALID)
1034            return false;
1035    }
1036    return true;
1037}
1038
1039bool MDPCompHighRes::allocLayerPipes(hwc_context_t *ctx,
1040        hwc_display_contents_1_t* list) {
1041    for(int index = 0 ; index < mCurrentFrame.layerCount; index++) {
1042
1043        if(mCurrentFrame.isFBComposed[index]) continue;
1044
1045        hwc_layer_1_t* layer = &list->hwLayers[index];
1046        private_handle_t *hnd = (private_handle_t *)layer->handle;
1047        int mdpIndex = mCurrentFrame.layerToMDP[index];
1048        PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
1049        info.pipeInfo = new MdpPipeInfoHighRes;
1050        info.rot = NULL;
1051        MdpPipeInfoHighRes& pipe_info = *(MdpPipeInfoHighRes*)info.pipeInfo;
1052        ePipeType type = MDPCOMP_OV_ANY;
1053
1054        if(isYuvBuffer(hnd)) {
1055            type = MDPCOMP_OV_VG;
1056        } else if(!qhwc::needsScaling(ctx, layer, mDpy)
1057            && Overlay::getDMAMode() != Overlay::DMA_BLOCK_MODE
1058            && ctx->mMDP.version >= qdutils::MDSS_V5) {
1059            type = MDPCOMP_OV_DMA;
1060        }
1061
1062        if(!acquireMDPPipes(ctx, layer, pipe_info, type)) {
1063            ALOGD_IF(isDebug(), "%s: Unable to get pipe for type = %d",
1064                    __FUNCTION__, (int) type);
1065            return false;
1066        }
1067    }
1068    return true;
1069}
1070/*
1071 * Configures pipe(s) for MDP composition
1072 */
1073int MDPCompHighRes::configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
1074        PipeLayerPair& PipeLayerPair) {
1075    MdpPipeInfoHighRes& mdp_info =
1076        *(static_cast<MdpPipeInfoHighRes*>(PipeLayerPair.pipeInfo));
1077    eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder);
1078    eIsFg isFg = IS_FG_OFF;
1079    eMdpFlags mdpFlagsL = OV_MDP_BACKEND_COMPOSITION;
1080    eDest lDest = mdp_info.lIndex;
1081    eDest rDest = mdp_info.rIndex;
1082
1083    ALOGD_IF(isDebug(),"%s: configuring: layer: %p z_order: %d dest_pipeL: %d"
1084             "dest_pipeR: %d",__FUNCTION__, layer, zOrder, lDest, rDest);
1085
1086    return configureHighRes(ctx, layer, mDpy, mdpFlagsL, zOrder, isFg, lDest,
1087                            rDest, &PipeLayerPair.rot);
1088}
1089
1090bool MDPCompHighRes::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
1091
1092    if(!isEnabled()) {
1093        ALOGD_IF(isDebug(),"%s: MDP Comp not configured", __FUNCTION__);
1094        return true;
1095    }
1096
1097    if(!ctx || !list) {
1098        ALOGE("%s: invalid contxt or list",__FUNCTION__);
1099        return false;
1100    }
1101
1102    if(ctx->listStats[mDpy].numAppLayers > MAX_NUM_APP_LAYERS) {
1103        ALOGD_IF(isDebug(),"%s: Exceeding max layer count", __FUNCTION__);
1104        return true;
1105    }
1106
1107    Locker::Autolock _l(mMdpCompLock);
1108
1109    /* reset Invalidator */
1110    if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount)
1111        idleInvalidator->markForSleep();
1112
1113    overlay::Overlay& ov = *ctx->mOverlay;
1114    LayerProp *layerProp = ctx->layerProp[mDpy];
1115
1116    int numHwLayers = ctx->listStats[mDpy].numAppLayers;
1117    for(int i = 0; i < numHwLayers && mCurrentFrame.mdpCount; i++ )
1118    {
1119        if(mCurrentFrame.isFBComposed[i]) continue;
1120
1121        hwc_layer_1_t *layer = &list->hwLayers[i];
1122        private_handle_t *hnd = (private_handle_t *)layer->handle;
1123        if(!hnd) {
1124            ALOGE("%s handle null", __FUNCTION__);
1125            return false;
1126        }
1127
1128        if(!(layerProp[i].mFlags & HWC_MDPCOMP)) {
1129            continue;
1130        }
1131
1132        int mdpIndex = mCurrentFrame.layerToMDP[i];
1133
1134        MdpPipeInfoHighRes& pipe_info =
1135            *(MdpPipeInfoHighRes*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
1136        Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
1137
1138        ovutils::eDest indexL = pipe_info.lIndex;
1139        ovutils::eDest indexR = pipe_info.rIndex;
1140
1141        int fd = hnd->fd;
1142        int offset = hnd->offset;
1143
1144        if(rot) {
1145            rot->queueBuffer(fd, offset);
1146            fd = rot->getDstMemId();
1147            offset = rot->getDstOffset();
1148        }
1149
1150        //************* play left mixer **********
1151        if(indexL != ovutils::OV_INVALID) {
1152            ovutils::eDest destL = (ovutils::eDest)indexL;
1153            ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
1154                     using  pipe: %d", __FUNCTION__, layer, hnd, indexL );
1155            if (!ov.queueBuffer(fd, offset, destL)) {
1156                ALOGE("%s: queueBuffer failed for left mixer", __FUNCTION__);
1157                return false;
1158            }
1159        }
1160
1161        //************* play right mixer **********
1162        if(indexR != ovutils::OV_INVALID) {
1163            ovutils::eDest destR = (ovutils::eDest)indexR;
1164            ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
1165                     using  pipe: %d", __FUNCTION__, layer, hnd, indexR );
1166            if (!ov.queueBuffer(fd, offset, destR)) {
1167                ALOGE("%s: queueBuffer failed for right mixer", __FUNCTION__);
1168                return false;
1169            }
1170        }
1171
1172        layerProp[i].mFlags &= ~HWC_MDPCOMP;
1173    }
1174
1175    return true;
1176}
1177}; //namespace
1178
1179