DisplayAnalyzer.cpp revision 177b44e0661a92d06f8f37c51e59af86423f7a95
1/*
2 * Copyright © 2012 Intel Corporation
3 * All rights reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Jackie Li <yaodong.li@intel.com>
26 *
27 */
28
29#include <HwcTrace.h>
30#include <IDisplayDevice.h>
31#include <DisplayQuery.h>
32#include <BufferManager.h>
33#include <DisplayPlaneManager.h>
34#include <Hwcomposer.h>
35#include <DisplayAnalyzer.h>
36#include <cutils/properties.h>
37#include <GraphicBuffer.h>
38#include <ExternalDevice.h>
39
40namespace android {
41namespace intel {
42
43DisplayAnalyzer::DisplayAnalyzer()
44    : mInitialized(false),
45      mVideoExtModeEnabled(true),
46      mVideoExtModeEligible(false),
47      mVideoExtModeActive(false),
48      mBlankDevice(false),
49      mOverlayAllowed(true),
50      mActiveInputState(true),
51      mCachedNumDisplays(0),
52      mCachedDisplays(0),
53      mPendingEvents(),
54      mEventMutex(),
55      mEventHandledCondition()
56{
57}
58
59DisplayAnalyzer::~DisplayAnalyzer()
60{
61}
62
63bool DisplayAnalyzer::initialize()
64{
65    // by default video extended mode is enabled
66    char prop[PROPERTY_VALUE_MAX];
67    if (property_get("hwc.video.extmode.enable", prop, "1") > 0) {
68        mVideoExtModeEnabled = atoi(prop) ? true : false;
69    }
70    mVideoExtModeEligible = false;
71    mVideoExtModeActive = false;
72    mBlankDevice = false;
73    mOverlayAllowed = true;
74    mActiveInputState = true;
75    mCachedNumDisplays = 0;
76    mCachedDisplays = 0;
77    mPendingEvents.clear();
78    mVideoStateMap.clear();
79    mInitialized = true;
80
81    return true;
82}
83
84void DisplayAnalyzer::deinitialize()
85{
86    mPendingEvents.clear();
87    mVideoStateMap.clear();
88    mInitialized = false;
89}
90
91void DisplayAnalyzer::analyzeContents(
92        size_t numDisplays, hwc_display_contents_1_t** displays)
93{
94    // cache and use them only in this context during analysis
95    mCachedNumDisplays = numDisplays;
96    mCachedDisplays = displays;
97
98    handlePendingEvents();
99
100    if (mVideoExtModeEnabled) {
101        handleVideoExtMode();
102    }
103
104    if (mBlankDevice) {
105        // this will make sure device is blanked after geometry changes.
106        // blank event is only processed once
107        blankSecondaryDevice();
108    }
109}
110
111void DisplayAnalyzer::handleVideoExtMode()
112{
113    bool eligible = mVideoExtModeEligible;
114    checkVideoExtMode();
115    if (eligible == mVideoExtModeEligible) {
116        if (mVideoExtModeActive) {
117            // need to mark all layers
118            setCompositionType(0, HWC_OVERLAY, false);
119        }
120        return;
121    }
122
123    if (mVideoExtModeEligible) {
124        if (mActiveInputState) {
125            VTRACE("input is active");
126        } else {
127            enterVideoExtMode();
128        }
129    } else {
130        exitVideoExtMode();
131    }
132}
133
134void DisplayAnalyzer::checkVideoExtMode()
135{
136    if (mVideoStateMap.size() != 1) {
137        mVideoExtModeEligible = false;
138        return;
139    }
140
141    bool geometryChanged = false;
142    int activeDisplays = 0;
143
144    hwc_display_contents_1_t *content = NULL;
145    for (int i = 0; i < (int)mCachedNumDisplays; i++) {
146        content = mCachedDisplays[i];
147        if (content == NULL) {
148            continue;
149        }
150        activeDisplays++;
151        if (content->flags & HWC_GEOMETRY_CHANGED) {
152            geometryChanged = true;
153        }
154    }
155
156    if (activeDisplays <= 1) {
157        mVideoExtModeEligible = false;
158        return;
159    }
160
161    // video state update event may come later than geometry change event.
162    // in that case, video extended mode is not detected properly.
163#if 0
164    if (geometryChanged == false) {
165        // use previous analysis result
166        return;
167    }
168#endif
169
170    // reset eligibility of video extended mode
171    mVideoExtModeEligible = false;
172
173    // check if there is video layer in the primary device
174    content = mCachedDisplays[0];
175    if (content == NULL) {
176        return;
177    }
178
179    uint32_t videoHandle = 0;
180    bool videoLayerExist = false;
181    // exclude the frame buffer target layer
182    for (int j = 0; j < (int)content->numHwLayers - 1; j++) {
183        videoLayerExist = isVideoLayer(content->hwLayers[j]);
184        if (videoLayerExist) {
185            videoHandle = (uint32_t)content->hwLayers[j].handle;
186            break;
187        }
188    }
189
190    if (videoLayerExist == false) {
191        // no video layer is found in the primary layer
192        return;
193    }
194
195    // check whether video layer exists in external device or virtual device
196    // TODO: video may exist in virtual device but no in external device or vice versa
197    // TODO: multiple video layers are not addressed here
198    for (int i = 1; i < (int)mCachedNumDisplays; i++) {
199        content = mCachedDisplays[i];
200        if (content == NULL) {
201            continue;
202        }
203
204        // exclude the frame buffer target layer
205        for (int j = 0; j < (int)content->numHwLayers - 1; j++) {
206            if ((uint32_t)content->hwLayers[j].handle == videoHandle) {
207                VTRACE("video layer exists in device %d", i);
208                mVideoExtModeEligible = isVideoFullScreen(i, content->hwLayers[j]);
209                return;
210            }
211        }
212    }
213}
214
215bool DisplayAnalyzer::isVideoExtModeActive()
216{
217    return mVideoExtModeActive;
218}
219
220bool DisplayAnalyzer::isVideoExtModeEnabled()
221{
222#if 1
223    // enable it for run-time debugging purpose.
224    char prop[PROPERTY_VALUE_MAX];
225    if (property_get("hwc.video.extmode.enable", prop, "1") > 0) {
226        mVideoExtModeEnabled = atoi(prop) ? true : false;
227    }
228    ITRACE("video extended mode enabled: %d", mVideoExtModeEnabled);
229#endif
230
231    return mVideoExtModeEnabled;
232}
233
234bool DisplayAnalyzer::isVideoLayer(hwc_layer_1_t &layer)
235{
236    bool ret = false;
237    BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
238    if (!layer.handle) {
239        return false;
240    }
241    DataBuffer *buffer = bm->lockDataBuffer((uint32_t)layer.handle);
242     if (!buffer) {
243         ETRACE("failed to get buffer");
244     } else {
245        ret = DisplayQuery::isVideoFormat(buffer->getFormat());
246        bm->unlockDataBuffer(buffer);
247    }
248    return ret;
249}
250
251bool DisplayAnalyzer::isVideoFullScreen(int device, hwc_layer_1_t &layer)
252{
253    IDisplayDevice *displayDevice = Hwcomposer::getInstance().getDisplayDevice(device);
254    if (!displayDevice) {
255        return false;
256    }
257    int width = 0, height = 0;
258    if (!displayDevice->getDisplaySize(&width, &height)) {
259        return false;
260    }
261
262    VTRACE("video left %d, right %d, top %d, bottom %d, device width %d, height %d",
263        layer.displayFrame.left, layer.displayFrame.right,
264        layer.displayFrame.top, layer.displayFrame.bottom,
265        width, height);
266
267    int dstW = layer.displayFrame.right - layer.displayFrame.left;
268    int dstH = layer.displayFrame.bottom - layer.displayFrame.top;
269    if (dstW < width - 1 &&
270        dstH < height - 1) {
271        VTRACE("video is not full-screen");
272        return false;
273    }
274    return true;
275}
276
277bool DisplayAnalyzer::isOverlayAllowed()
278{
279    return mOverlayAllowed;
280}
281
282int DisplayAnalyzer::getVideoInstances()
283{
284    return (int)mVideoStateMap.size();
285}
286
287void DisplayAnalyzer::postHotplugEvent(bool connected)
288{
289    if (!connected) {
290        // enable vsync on the primary device immediately
291        Hwcomposer::getInstance().getVsyncManager()->enableDynamicVsync(true);
292    }
293
294    // handle hotplug event (vsync switch) asynchronously
295    Event e;
296    e.type = HOTPLUG_EVENT;
297    e.bValue = connected;
298    postEvent(e);
299    Hwcomposer::getInstance().invalidate();
300}
301
302void DisplayAnalyzer::postVideoEvent(int instanceID, int state)
303{
304    Event e;
305    e.type = VIDEO_EVENT;
306    e.videoEvent.instanceID = instanceID;
307    e.videoEvent.state = state;
308    postEvent(e);
309
310    if ((state == VIDEO_PLAYBACK_STARTING) ||
311        (state == VIDEO_PLAYBACK_STOPPING && hasProtectedLayer())) {
312        Hwcomposer::getInstance().invalidate();
313        Mutex::Autolock lock(mEventMutex);
314        // ideally overlay should be disabled in the surface flinger thread, if it is not processed
315        // in close to one vsync cycle (50ms)  it will be safely disabled in this thread context
316        // there is no threading issue
317        status_t err = mEventHandledCondition.waitRelative(mEventMutex, milliseconds(50));
318        if (err == -ETIMEDOUT) {
319            WTRACE("timeout waiting for event handling");
320            Hwcomposer::getInstance().getPlaneManager()->disableOverlayPlanes();
321        }
322    }
323}
324
325void DisplayAnalyzer::postBlankEvent(bool blank)
326{
327    Event e;
328    e.type = BLANK_EVENT;
329    e.bValue = blank;
330    postEvent(e);
331    Hwcomposer::getInstance().invalidate();
332}
333
334void DisplayAnalyzer::postInputEvent(bool active)
335{
336    Event e;
337    e.type = INPUT_EVENT;
338    e.bValue = active;
339    postEvent(e);
340    Hwcomposer::getInstance().invalidate();
341}
342
343void DisplayAnalyzer::postEvent(Event& e)
344{
345    Mutex::Autolock lock(mEventMutex);
346    mPendingEvents.add(e);
347}
348
349bool DisplayAnalyzer::getEvent(Event& e)
350{
351    Mutex::Autolock lock(mEventMutex);
352    if (mPendingEvents.size() == 0) {
353        return false;
354    }
355    e = mPendingEvents[0];
356    mPendingEvents.removeAt(0);
357    return true;
358}
359
360void DisplayAnalyzer::handlePendingEvents()
361{
362    // handle one event per analysis to avoid blocking surface flinger
363    // some event may take lengthy time to process
364    Event e;
365    if (!getEvent(e)) {
366        return;
367    }
368
369    switch (e.type) {
370    case HOTPLUG_EVENT:
371        handleHotplugEvent(e.bValue);
372        break;
373    case BLANK_EVENT:
374        handleBlankEvent(e.bValue);
375        break;
376    case VIDEO_EVENT:
377        handleVideoEvent(e.videoEvent.instanceID, e.videoEvent.state);
378        break;
379    case TIMING_EVENT:
380        handleTimingEvent();
381        break;
382    case INPUT_EVENT:
383        handleInputEvent(e.bValue);
384        break;
385    case DPMS_EVENT:
386        handleDpmsEvent(e.nValue);
387        break;
388    }
389}
390
391void DisplayAnalyzer::handleHotplugEvent(bool connected)
392{
393}
394
395void DisplayAnalyzer::handleBlankEvent(bool blank)
396{
397    mBlankDevice = blank;
398    // force geometry changed in the secondary device to reset layer composition type
399    for (int i = 0; i < (int)mCachedNumDisplays; i++) {
400        if (i == IDisplayDevice::DEVICE_PRIMARY) {
401            continue;
402        }
403        if (mCachedDisplays[i]) {
404            mCachedDisplays[i]->flags |= HWC_GEOMETRY_CHANGED;
405        }
406    }
407    blankSecondaryDevice();
408}
409
410void DisplayAnalyzer::handleTimingEvent()
411{
412    // check whether external device is connected, reset refresh rate to match video frame rate
413    // if video is in playing state or reset refresh rate to default preferred one if video is not
414    // at playing state
415    Hwcomposer *hwc = &Hwcomposer::getInstance();
416    ExternalDevice *dev = NULL;
417    dev = (ExternalDevice *)hwc->getDisplayDevice(IDisplayDevice::DEVICE_EXTERNAL);
418    if (!dev) {
419        return;
420    }
421
422    if (!dev->isConnected()) {
423        return;
424    }
425
426    if (hwc->getMultiDisplayObserver()->isExternalDeviceTimingFixed()) {
427        VTRACE("Timing of external device is fixed.");
428        return;
429    }
430
431    int hz = 0;
432    if (mVideoStateMap.size() == 1) {
433        VideoSourceInfo info;
434        int instanceID = mVideoStateMap.keyAt(0);
435        status_t err = hwc->getMultiDisplayObserver()->getVideoSourceInfo(
436                instanceID, &info);
437        if (err == NO_ERROR) {
438            hz = info.frameRate;
439        }
440    }
441
442    dev->setRefreshRate(hz);
443}
444
445void DisplayAnalyzer::handleVideoEvent(int instanceID, int state)
446{
447    mVideoStateMap.removeItem(instanceID);
448    if (state != VIDEO_PLAYBACK_STOPPED) {
449        mVideoStateMap.add(instanceID, state);
450    }
451
452    Hwcomposer *hwc = &Hwcomposer::getInstance();
453
454    // sanity check
455    if (hwc->getMultiDisplayObserver()->getVideoSessionNumber() !=
456        (int)mVideoStateMap.size()) {
457        WTRACE("session number does not match!!");
458        mVideoStateMap.clear();
459        if (state != VIDEO_PLAYBACK_STOPPED) {
460            mVideoStateMap.add(instanceID, state);
461        }
462    }
463
464    // check if composition type needs to be reset
465    bool reset = false;
466    if ((state == VIDEO_PLAYBACK_STARTING) ||
467        (state == VIDEO_PLAYBACK_STOPPING && hasProtectedLayer())) {
468        // if video is in starting or stopping stage, overlay use is temporarily not allowed to
469        // avoid scrambed RGB overlay if video is protected.
470        mOverlayAllowed = false;
471        reset = true;
472
473        // disable overlay plane and acknolwdge the waiting thread
474        hwc->getPlaneManager()->disableOverlayPlanes();
475        mEventHandledCondition.signal();
476    } else {
477        reset = !mOverlayAllowed;
478        mOverlayAllowed = true;
479    }
480
481    if (reset) {
482        hwc_display_contents_1_t *content = NULL;
483        for (int i = 0; i < (int)mCachedNumDisplays; i++) {
484            setCompositionType(i, HWC_FRAMEBUFFER, true);
485        }
486    }
487
488    // delay changing timing as it is a lengthy operation
489    if (state == VIDEO_PLAYBACK_STARTED ||
490        state == VIDEO_PLAYBACK_STOPPED) {
491        Event e;
492        e.type = TIMING_EVENT;
493        postEvent(e);
494    }
495}
496
497void DisplayAnalyzer::blankSecondaryDevice()
498{
499    hwc_display_contents_1_t *content = NULL;
500    hwc_layer_1 *layer = NULL;
501    for (int i = 0; i < (int)mCachedNumDisplays; i++) {
502        if (i == IDisplayDevice::DEVICE_PRIMARY) {
503            continue;
504        }
505        content = mCachedDisplays[i];
506        if (content == NULL) {
507            continue;
508        }
509
510        for (int j = 0; j < (int)content->numHwLayers - 1; j++) {
511            layer = &content->hwLayers[j];
512            if (!layer) {
513                continue;
514            }
515            if (mBlankDevice) {
516                layer->hints |= HWC_HINT_CLEAR_FB;
517                layer->flags &= ~HWC_SKIP_LAYER;
518                layer->compositionType = HWC_OVERLAY;
519            } else {
520                layer->hints &= ~HWC_HINT_CLEAR_FB;
521                layer->compositionType = HWC_FRAMEBUFFER;
522            }
523        }
524    }
525}
526
527void DisplayAnalyzer::handleInputEvent(bool active)
528{
529    mActiveInputState = active;
530    if (!mVideoExtModeEligible) {
531        ITRACE("not eligible for video extended mode");
532        return;
533    }
534
535    if (active) {
536        exitVideoExtMode();
537    } else {
538        enterVideoExtMode();
539    }
540}
541
542void DisplayAnalyzer::handleDpmsEvent(int delayCount)
543{
544    if (mActiveInputState || !mVideoExtModeEligible) {
545        ITRACE("aborting display power off in video extended mode");
546        return;
547    }
548
549    if (delayCount < DELAY_BEFORE_DPMS_OFF) {
550        Event e;
551        e.type = DPMS_EVENT;
552        e.nValue = delayCount + 1;
553        postEvent(e);
554        return;
555    }
556
557    if (Hwcomposer::getInstance().getVsyncManager()->getVsyncSource() ==
558        IDisplayDevice::DEVICE_PRIMARY) {
559        ETRACE("primary display is source of vsync, it can't be powered off");
560        return;
561    }
562
563    ITRACE("powering off primary display...");
564    Hwcomposer::getInstance().getDrm()->setDpmsMode(
565        IDisplayDevice::DEVICE_PRIMARY,
566        IDisplayDevice::DEVICE_DISPLAY_OFF);
567}
568
569void DisplayAnalyzer::enterVideoExtMode()
570{
571    if (mVideoExtModeActive) {
572        WTRACE("already in video extended mode.");
573        return;
574    }
575
576    ITRACE("entering video extended mode...");
577    mVideoExtModeActive = true;
578    Hwcomposer::getInstance().getVsyncManager()->resetVsyncSource();
579
580    setCompositionType(0, HWC_OVERLAY, true);
581
582    // Do not power off primary display immediately as flip is asynchronous
583    Event e;
584    e.type = DPMS_EVENT;
585    e.nValue = 0;
586    postEvent(e);
587}
588
589void DisplayAnalyzer::exitVideoExtMode()
590{
591    if (!mVideoExtModeActive) {
592        WTRACE("Not in video extended mode");
593        return;
594    }
595
596    ITRACE("exitting video extended mode...");
597
598    mVideoExtModeActive = false;
599
600    Hwcomposer::getInstance().getDrm()->setDpmsMode(
601        IDisplayDevice::DEVICE_PRIMARY,
602        IDisplayDevice::DEVICE_DISPLAY_ON);
603
604    Hwcomposer::getInstance().getVsyncManager()->resetVsyncSource();
605
606    setCompositionType(0, HWC_FRAMEBUFFER, true);
607}
608
609bool DisplayAnalyzer::isPresentationLayer(hwc_layer_1_t &layer)
610{
611    if (layer.handle == NULL) {
612        return false;
613    }
614    if (mCachedDisplays == NULL) {
615        return false;
616    }
617    // check if the given layer exists in the primary device
618    hwc_display_contents_1_t *content = mCachedDisplays[0];
619    if (content == NULL) {
620        return false;
621    }
622    for (size_t i = 0; i < content->numHwLayers - 1; i++) {
623        if ((uint32_t)content->hwLayers[i].handle == (uint32_t)layer.handle) {
624            VTRACE("Layer exists for Primary device");
625            return false;
626        }
627    }
628    return true;
629}
630
631bool DisplayAnalyzer::hasProtectedLayer()
632{
633    DataBuffer * buffer = NULL;
634    hwc_display_contents_1_t *content = NULL;
635    BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
636
637    if (bm == NULL){
638        return false;
639    }
640
641    if (mCachedDisplays == NULL) {
642        return false;
643    }
644    // check if the given layer exists in the primary device
645    for (int index = 0; index < (int)mCachedNumDisplays; index++) {
646        content = mCachedDisplays[index];
647        if (content == NULL) {
648            continue;
649        }
650
651        for (size_t i = 0; i < content->numHwLayers - 1; i++) {
652            if (isProtectedLayer(content->hwLayers[i]))
653                return true;
654        }
655    }
656
657    return false;
658}
659
660bool DisplayAnalyzer::isProtectedLayer(hwc_layer_1_t &layer)
661{
662    if (!layer.handle) {
663        return false;
664    }
665    bool ret = false;
666    BufferManager *bm = Hwcomposer::getInstance().getBufferManager();
667    DataBuffer *buffer = bm->lockDataBuffer((uint32_t)layer.handle);
668    if (!buffer) {
669        ETRACE("failed to get buffer");
670    } else {
671        ret = GraphicBuffer::isProtectedBuffer((GraphicBuffer*)buffer);
672        bm->unlockDataBuffer(buffer);
673    }
674    return ret;
675}
676
677void DisplayAnalyzer::setCompositionType(hwc_display_contents_1_t *display, int type)
678{
679    for (size_t i = 0; i < display->numHwLayers - 1; i++) {
680        hwc_layer_1_t *layer = &display->hwLayers[i];
681        if (layer) layer->compositionType = type;
682    }
683}
684
685void DisplayAnalyzer::setCompositionType(int device, int type, bool reset)
686{
687    hwc_display_contents_1_t *content = mCachedDisplays[device];
688    if (content == NULL) {
689        ETRACE("Invalid device %d", device);
690        return;
691    }
692
693    // don't need to set geometry changed if layers are just needed to be marked
694    if (reset) {
695        content->flags |= HWC_GEOMETRY_CHANGED;
696    }
697
698    setCompositionType(content, type);
699}
700
701} // namespace intel
702} // namespace android
703
704