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