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