1/*
2 *  Copyright (c) 2013-15, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *     * Redistributions of source code must retain the above copyright
8 *       notice, this list of conditions and the following disclaimer.
9 *     * Redistributions in binary form must reproduce the above
10 *       copyright notice, this list of conditions and the following
11 *       disclaimer in the documentation and/or other materials provided
12 *       with the distribution.
13 *     * Neither the name of The Linux Foundation nor the names of its
14 *       contributors may be used to endorse or promote products derived
15 *       from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR CLIENTS; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <hwc_qclient.h>
31#include <IQService.h>
32#include <hwc_utils.h>
33#include <mdp_version.h>
34#include <hwc_mdpcomp.h>
35#include <hwc_virtual.h>
36#include <overlay.h>
37#include <display_config.h>
38#include <hwc_qdcm.h>
39
40#define QCLIENT_DEBUG 0
41
42using namespace android;
43using namespace qService;
44using namespace qhwc;
45using namespace overlay;
46using namespace qdutils;
47using namespace qQdcm;
48
49namespace qClient {
50
51// ----------------------------------------------------------------------------
52QClient::QClient(hwc_context_t *ctx) : mHwcContext(ctx),
53        mMPDeathNotifier(new MPDeathNotifier(ctx))
54{
55    ALOGD_IF(QCLIENT_DEBUG, "QClient Constructor invoked");
56}
57
58QClient::~QClient()
59{
60    ALOGD_IF(QCLIENT_DEBUG,"QClient Destructor invoked");
61}
62
63static void securing(hwc_context_t *ctx, uint32_t startEnd) {
64    //The only way to make this class in this process subscribe to media
65    //player's death.
66    IMediaDeathNotifier::getMediaPlayerService();
67
68    ctx->mDrawLock.lock();
69    ctx->mSecuring = startEnd;
70    //We're done securing
71    if(startEnd == IQService::END)
72        ctx->mSecureMode = true;
73    ctx->mDrawLock.unlock();
74
75    if(ctx->proc)
76        ctx->proc->invalidate(ctx->proc);
77}
78
79static void unsecuring(hwc_context_t *ctx, uint32_t startEnd) {
80    ctx->mDrawLock.lock();
81    ctx->mSecuring = startEnd;
82    //We're done unsecuring
83    if(startEnd == IQService::END)
84        ctx->mSecureMode = false;
85    ctx->mDrawLock.unlock();
86
87    if(ctx->proc)
88        ctx->proc->invalidate(ctx->proc);
89}
90
91void QClient::MPDeathNotifier::died() {
92    mHwcContext->mDrawLock.lock();
93    ALOGD_IF(QCLIENT_DEBUG, "Media Player died");
94    mHwcContext->mSecuring = false;
95    mHwcContext->mSecureMode = false;
96    mHwcContext->mDrawLock.unlock();
97    if(mHwcContext->proc)
98        mHwcContext->proc->invalidate(mHwcContext->proc);
99}
100
101static android::status_t screenRefresh(hwc_context_t *ctx) {
102    status_t result = NO_INIT;
103    if(ctx->proc) {
104        ctx->proc->invalidate(ctx->proc);
105        result = NO_ERROR;
106    }
107    return result;
108}
109
110static void setExtOrientation(hwc_context_t *ctx, uint32_t orientation) {
111    ctx->mExtOrientation = orientation;
112}
113
114static void isExternalConnected(hwc_context_t* ctx, Parcel* outParcel) {
115    int connected;
116    connected = ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected ? 1 : 0;
117    outParcel->writeInt32(connected);
118}
119
120static void getDisplayAttributes(hwc_context_t* ctx, const Parcel* inParcel,
121        Parcel* outParcel) {
122    int dpy = inParcel->readInt32();
123    outParcel->writeInt32(ctx->dpyAttr[dpy].vsync_period);
124    if (ctx->dpyAttr[dpy].customFBSize) {
125        outParcel->writeInt32(ctx->dpyAttr[dpy].xres_new);
126        outParcel->writeInt32(ctx->dpyAttr[dpy].yres_new);
127    } else {
128        outParcel->writeInt32(ctx->dpyAttr[dpy].xres);
129        outParcel->writeInt32(ctx->dpyAttr[dpy].yres);
130    }
131    outParcel->writeFloat(ctx->dpyAttr[dpy].xdpi);
132    outParcel->writeFloat(ctx->dpyAttr[dpy].ydpi);
133    //XXX: Need to check what to return for HDMI
134    outParcel->writeInt32(ctx->mMDP.panel);
135}
136static void setHSIC(const Parcel* inParcel) {
137    int dpy = inParcel->readInt32();
138    ALOGD_IF(0, "In %s: dpy = %d", __FUNCTION__, dpy);
139    HSICData_t hsic_data;
140    hsic_data.hue = inParcel->readInt32();
141    hsic_data.saturation = inParcel->readFloat();
142    hsic_data.intensity = inParcel->readInt32();
143    hsic_data.contrast = inParcel->readFloat();
144    //XXX: Actually set the HSIC data through ABL lib
145}
146
147
148static void setBufferMirrorMode(hwc_context_t *ctx, uint32_t enable) {
149    ctx->mBufferMirrorMode = enable;
150}
151
152static status_t getDisplayVisibleRegion(hwc_context_t* ctx, int dpy,
153                                Parcel* outParcel) {
154    // Get the info only if the dpy is valid
155    if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) {
156        Locker::Autolock _sl(ctx->mDrawLock);
157        if(dpy && (ctx->mExtOrientation || ctx->mBufferMirrorMode)) {
158            // Return the destRect on external, if external orienation
159            // is enabled
160            outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.left);
161            outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.top);
162            outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.right);
163            outParcel->writeInt32(ctx->dpyAttr[dpy].mDstRect.bottom);
164        } else {
165            outParcel->writeInt32(ctx->mViewFrame[dpy].left);
166            outParcel->writeInt32(ctx->mViewFrame[dpy].top);
167            outParcel->writeInt32(ctx->mViewFrame[dpy].right);
168            outParcel->writeInt32(ctx->mViewFrame[dpy].bottom);
169        }
170        return NO_ERROR;
171    } else {
172        ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy);
173        return BAD_VALUE;
174    }
175}
176
177// USed for setting the secondary(hdmi/wfd) status
178static void setSecondaryDisplayStatus(hwc_context_t *ctx,
179                                      const Parcel* inParcel) {
180    uint32_t dpy = inParcel->readInt32();
181    uint32_t status = inParcel->readInt32();
182    ALOGD_IF(QCLIENT_DEBUG, "%s: dpy = %d status = %s", __FUNCTION__,
183                                        dpy, getExternalDisplayState(status));
184
185    if(dpy > HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) {
186        if(dpy == HWC_DISPLAY_VIRTUAL && status == qdutils::EXTERNAL_OFFLINE) {
187            ctx->mWfdSyncLock.lock();
188            ctx->mWfdSyncLock.signal();
189            ctx->mWfdSyncLock.unlock();
190        } else if(status == qdutils::EXTERNAL_PAUSE) {
191            handle_pause(ctx, dpy);
192        } else if(status == qdutils::EXTERNAL_RESUME) {
193            handle_resume(ctx, dpy);
194        }
195    } else {
196        ALOGE("%s: Invalid dpy %d", __FUNCTION__, dpy);
197        return;
198    }
199}
200
201
202static status_t setViewFrame(hwc_context_t* ctx, const Parcel* inParcel) {
203    int dpy = inParcel->readInt32();
204    if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) {
205        Locker::Autolock _sl(ctx->mDrawLock);
206        ctx->mViewFrame[dpy].left   = inParcel->readInt32();
207        ctx->mViewFrame[dpy].top    = inParcel->readInt32();
208        ctx->mViewFrame[dpy].right  = inParcel->readInt32();
209        ctx->mViewFrame[dpy].bottom = inParcel->readInt32();
210        ALOGD_IF(QCLIENT_DEBUG, "%s: mViewFrame[%d] = [%d %d %d %d]",
211            __FUNCTION__, dpy,
212            ctx->mViewFrame[dpy].left, ctx->mViewFrame[dpy].top,
213            ctx->mViewFrame[dpy].right, ctx->mViewFrame[dpy].bottom);
214        return NO_ERROR;
215    } else {
216        ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy);
217        return BAD_VALUE;
218    }
219}
220
221static void toggleDynamicDebug(hwc_context_t* ctx, const Parcel* inParcel) {
222    int debug_type = inParcel->readInt32();
223    bool enable = !!inParcel->readInt32();
224    ALOGD("%s: debug_type: %d enable:%d",
225            __FUNCTION__, debug_type, enable);
226    Locker::Autolock _sl(ctx->mDrawLock);
227    switch (debug_type) {
228        //break is ignored for DEBUG_ALL to toggle all of them at once
229        case IQService::DEBUG_ALL:
230        case IQService::DEBUG_MDPCOMP:
231            qhwc::MDPComp::dynamicDebug(enable);
232            if (debug_type != IQService::DEBUG_ALL)
233                break;
234        case IQService::DEBUG_VSYNC:
235            ctx->vstate.debug = enable;
236            if (debug_type != IQService::DEBUG_ALL)
237                break;
238        case IQService::DEBUG_VD:
239            HWCVirtualVDS::dynamicDebug(enable);
240            if (debug_type != IQService::DEBUG_ALL)
241                break;
242        case IQService::DEBUG_PIPE_LIFECYCLE:
243            Overlay::debugPipeLifecycle(enable);
244            if (debug_type != IQService::DEBUG_ALL)
245                break;
246    }
247}
248
249static void setIdleTimeout(hwc_context_t* ctx, const Parcel* inParcel) {
250    uint32_t timeout = (uint32_t)inParcel->readInt32();
251    ALOGD("%s :%u ms", __FUNCTION__, timeout);
252    Locker::Autolock _sl(ctx->mDrawLock);
253    MDPComp::setIdleTimeout(timeout);
254}
255
256static void configureDynRefreshRate(hwc_context_t* ctx,
257                                    const Parcel* inParcel) {
258    uint32_t op = (uint32_t)inParcel->readInt32();
259    uint32_t refresh_rate = (uint32_t)inParcel->readInt32();
260    MDPVersion& mdpHw = MDPVersion::getInstance();
261    uint32_t dpy = HWC_DISPLAY_PRIMARY;
262
263    if(mdpHw.isDynFpsSupported()) {
264        Locker::Autolock _sl(ctx->mDrawLock);
265
266        switch (op) {
267        case DISABLE_METADATA_DYN_REFRESH_RATE:
268            ctx->mUseMetaDataRefreshRate = false;
269            setRefreshRate(ctx, dpy, ctx->dpyAttr[dpy].refreshRate);
270            break;
271        case ENABLE_METADATA_DYN_REFRESH_RATE:
272            ctx->mUseMetaDataRefreshRate = true;
273            setRefreshRate(ctx, dpy, ctx->dpyAttr[dpy].refreshRate);
274            break;
275        case SET_BINDER_DYN_REFRESH_RATE:
276            if(ctx->mUseMetaDataRefreshRate)
277                ALOGW("%s: Ignoring binder request to change refresh-rate",
278                      __FUNCTION__);
279            else {
280                uint32_t rate = roundOff(refresh_rate);
281                if((rate >= mdpHw.getMinFpsSupported() &&
282                    rate <= mdpHw.getMaxFpsSupported())) {
283                    setRefreshRate(ctx, dpy, rate);
284                } else {
285                    ALOGE("%s: Requested refresh-rate should be between \
286                          (%d) and (%d). Given (%d)", __FUNCTION__,
287                          mdpHw.getMinFpsSupported(),
288                          mdpHw.getMaxFpsSupported(), rate);
289                }
290            }
291            break;
292        default:
293            ALOGE("%s: Invalid op %d",__FUNCTION__,op);
294        }
295    }
296}
297
298static status_t setPartialUpdateState(hwc_context_t *ctx, uint32_t state) {
299    ALOGD("%s: state: %d", __FUNCTION__, state);
300    switch(state) {
301        case IQService::PREF_PARTIAL_UPDATE:
302            if(qhwc::MDPComp::setPartialUpdatePref(ctx, true) < 0)
303                return NO_INIT;
304            return NO_ERROR;
305        case IQService::PREF_POST_PROCESSING:
306            if(qhwc::MDPComp::setPartialUpdatePref(ctx, false) < 0)
307                return NO_INIT;
308            qhwc::MDPComp::enablePartialUpdate(false);
309            return NO_ERROR;
310        case IQService::ENABLE_PARTIAL_UPDATE:
311            qhwc::MDPComp::enablePartialUpdate(true);
312            return NO_ERROR;
313        default:
314            ALOGE("%s: Invalid state", __FUNCTION__);
315            return NO_ERROR;
316    };
317}
318
319static void toggleScreenUpdate(hwc_context_t* ctx, uint32_t on) {
320    ALOGD("%s: toggle update: %d", __FUNCTION__, on);
321    if (on == 0) {
322        ctx->mDrawLock.lock();
323        ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isPause = true;
324        ctx->mOverlay->configBegin();
325        ctx->mOverlay->configDone();
326        ctx->mRotMgr->clear();
327        if(!Overlay::displayCommit(ctx->dpyAttr[0].fd)) {
328            ALOGE("%s: Display commit failed", __FUNCTION__);
329        }
330        ctx->mDrawLock.unlock();
331    } else {
332        ctx->mDrawLock.lock();
333        ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isPause = false;
334        ctx->mDrawLock.unlock();
335        ctx->proc->invalidate(ctx->proc);
336    }
337}
338
339status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
340        Parcel* outParcel) {
341    status_t ret = NO_ERROR;
342
343    switch(command) {
344        case IQService::SECURING:
345            securing(mHwcContext, inParcel->readInt32());
346            break;
347        case IQService::UNSECURING:
348            unsecuring(mHwcContext, inParcel->readInt32());
349            break;
350        case IQService::SCREEN_REFRESH:
351            return screenRefresh(mHwcContext);
352            break;
353        case IQService::EXTERNAL_ORIENTATION:
354            setExtOrientation(mHwcContext, inParcel->readInt32());
355            break;
356        case IQService::BUFFER_MIRRORMODE:
357            setBufferMirrorMode(mHwcContext, inParcel->readInt32());
358            break;
359        case IQService::GET_DISPLAY_VISIBLE_REGION:
360            ret = getDisplayVisibleRegion(mHwcContext, inParcel->readInt32(),
361                                    outParcel);
362            break;
363        case IQService::CHECK_EXTERNAL_STATUS:
364            isExternalConnected(mHwcContext, outParcel);
365            break;
366        case IQService::GET_DISPLAY_ATTRIBUTES:
367            getDisplayAttributes(mHwcContext, inParcel, outParcel);
368            break;
369        case IQService::SET_HSIC_DATA:
370            setHSIC(inParcel);
371            break;
372        case IQService::SET_SECONDARY_DISPLAY_STATUS:
373            setSecondaryDisplayStatus(mHwcContext, inParcel);
374            break;
375        case IQService::SET_VIEW_FRAME:
376            setViewFrame(mHwcContext, inParcel);
377            break;
378        case IQService::DYNAMIC_DEBUG:
379            toggleDynamicDebug(mHwcContext, inParcel);
380            break;
381        case IQService::SET_IDLE_TIMEOUT:
382            setIdleTimeout(mHwcContext, inParcel);
383            break;
384        case IQService::SET_PARTIAL_UPDATE:
385            ret = setPartialUpdateState(mHwcContext, inParcel->readInt32());
386            break;
387        case IQService::CONFIGURE_DYN_REFRESH_RATE:
388            configureDynRefreshRate(mHwcContext, inParcel);
389        case IQService::QDCM_SVC_CMDS:
390            qdcmCmdsHandler(mHwcContext, inParcel, outParcel);
391            break;
392        case IQService::TOGGLE_SCREEN_UPDATE:
393            toggleScreenUpdate(mHwcContext, inParcel->readInt32());
394            break;
395        default:
396            ret = NO_ERROR;
397    }
398    return ret;
399}
400
401}
402