hwc_utils.cpp revision c1de3bb0682a9d3b6ae96943e444e3536bb4c811
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 * Copyright (C) 2012-2013, The Linux Foundation All rights reserved.
4 *
5 * Not a Contribution, Apache license notifications and license are retained
6 * for attribution purposes only.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20#define HWC_UTILS_DEBUG 0
21#include <sys/ioctl.h>
22#include <binder/IServiceManager.h>
23#include <EGL/egl.h>
24#include <cutils/properties.h>
25#include <gralloc_priv.h>
26#include <fb_priv.h>
27#include <overlay.h>
28#include "hwc_utils.h"
29#include "hwc_mdpcomp.h"
30#include "hwc_fbupdate.h"
31#include "mdp_version.h"
32#include "hwc_copybit.h"
33#include "external.h"
34#include "hwc_qclient.h"
35#include "QService.h"
36#include "comptype.h"
37
38using namespace qClient;
39using namespace qService;
40using namespace android;
41
42namespace qhwc {
43
44// Opens Framebuffer device
45static void openFramebufferDevice(hwc_context_t *ctx)
46{
47    hw_module_t const *module;
48    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
49        framebuffer_open(module, &(ctx->mFbDev));
50        private_module_t* m = reinterpret_cast<private_module_t*>(
51                ctx->mFbDev->common.module);
52        //xres, yres may not be 32 aligned
53        ctx->dpyAttr[HWC_DISPLAY_PRIMARY].stride = m->finfo.line_length /
54                                                (m->info.xres/8);
55        ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres = m->info.xres;
56        ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres = m->info.yres;
57        ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xdpi = ctx->mFbDev->xdpi;
58        ctx->dpyAttr[HWC_DISPLAY_PRIMARY].ydpi = ctx->mFbDev->ydpi;
59        ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period =
60                1000000000l / ctx->mFbDev->fps;
61        ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd = openFb(HWC_DISPLAY_PRIMARY);
62    }
63}
64
65void initContext(hwc_context_t *ctx)
66{
67    openFramebufferDevice(ctx);
68    overlay::Overlay::initOverlay();
69    ctx->mOverlay = overlay::Overlay::getInstance();
70    ctx->mMDP.version = qdutils::MDPVersion::getInstance().getMDPVersion();
71    ctx->mMDP.hasOverlay = qdutils::MDPVersion::getInstance().hasOverlay();
72    ctx->mMDP.panel = qdutils::MDPVersion::getInstance().getPanelType();
73    //Is created and destroyed only once for primary
74    //For external it could get created and destroyed multiple times depending
75    //on what external we connect to.
76    ctx->mFBUpdate[HWC_DISPLAY_PRIMARY] =
77        IFBUpdate::getObject(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres,
78        HWC_DISPLAY_PRIMARY);
79
80    char value[PROPERTY_VALUE_MAX];
81    // Check if the target supports copybit compostion (dyn/mdp/c2d) to
82    // decide if we need to open the copybit module.
83    int compositionType =
84        qdutils::QCCompositionType::getInstance().getCompositionType();
85
86    if (compositionType & (qdutils::COMPOSITION_TYPE_DYN |
87                           qdutils::COMPOSITION_TYPE_MDP |
88                           qdutils::COMPOSITION_TYPE_C2D)) {
89            ctx->mCopyBit[HWC_DISPLAY_PRIMARY] = new CopyBit();
90    }
91
92    ctx->mExtDisplay = new ExternalDisplay(ctx);
93    for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++)
94        ctx->mLayerCache[i] = new LayerCache();
95    ctx->mMDPComp = MDPComp::getObject(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres);
96    MDPComp::init(ctx);
97
98    pthread_mutex_init(&(ctx->vstate.lock), NULL);
99    pthread_cond_init(&(ctx->vstate.cond), NULL);
100    ctx->vstate.enable = false;
101    ctx->mExtDispConfiguring = false;
102
103    //Right now hwc starts the service but anybody could do it, or it could be
104    //independent process as well.
105    QService::init();
106    sp<IQClient> client = new QClient(ctx);
107    interface_cast<IQService>(
108            defaultServiceManager()->getService(
109            String16("display.qservice")))->connect(client);
110
111    ALOGI("Initializing Qualcomm Hardware Composer");
112    ALOGI("MDP version: %d", ctx->mMDP.version);
113}
114
115void closeContext(hwc_context_t *ctx)
116{
117    if(ctx->mOverlay) {
118        delete ctx->mOverlay;
119        ctx->mOverlay = NULL;
120    }
121
122    for(int i = 0; i< HWC_NUM_DISPLAY_TYPES; i++) {
123        if(ctx->mCopyBit[i]) {
124            delete ctx->mCopyBit[i];
125            ctx->mCopyBit[i] = NULL;
126        }
127    }
128
129    if(ctx->mFbDev) {
130        framebuffer_close(ctx->mFbDev);
131        ctx->mFbDev = NULL;
132        close(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd);
133        ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd = -1;
134    }
135
136    if(ctx->mExtDisplay) {
137        delete ctx->mExtDisplay;
138        ctx->mExtDisplay = NULL;
139    }
140
141    for(int i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
142        if(ctx->mFBUpdate[i]) {
143            delete ctx->mFBUpdate[i];
144            ctx->mFBUpdate[i] = NULL;
145        }
146    }
147
148    if(ctx->mMDPComp) {
149        delete ctx->mMDPComp;
150        ctx->mMDPComp = NULL;
151    }
152
153    pthread_mutex_destroy(&(ctx->vstate.lock));
154    pthread_cond_destroy(&(ctx->vstate.cond));
155}
156
157
158void dumpsys_log(android::String8& buf, const char* fmt, ...)
159{
160    va_list varargs;
161    va_start(varargs, fmt);
162    buf.appendFormatV(fmt, varargs);
163    va_end(varargs);
164}
165
166/* Calculates the destination position based on the action safe rectangle */
167void getActionSafePosition(hwc_context_t *ctx, int dpy, uint32_t& x,
168                           uint32_t& y, uint32_t& w, uint32_t& h) {
169
170    // if external supports underscan, do nothing
171    // it will be taken care in the driver
172    if(ctx->mExtDisplay->isCEUnderscanSupported())
173        return;
174
175    float wRatio = 1.0;
176    float hRatio = 1.0;
177    float xRatio = 1.0;
178    float yRatio = 1.0;
179
180    float fbWidth = ctx->dpyAttr[dpy].xres;
181    float fbHeight = ctx->dpyAttr[dpy].yres;
182
183    float asX = 0;
184    float asY = 0;
185    float asW = fbWidth;
186    float asH= fbHeight;
187    char value[PROPERTY_VALUE_MAX];
188
189    // Apply action safe parameters
190    property_get("hw.actionsafe.width", value, "0");
191    int asWidthRatio = atoi(value);
192    property_get("hw.actionsafe.height", value, "0");
193    int asHeightRatio = atoi(value);
194    // based on the action safe ratio, get the Action safe rectangle
195    asW = fbWidth * (1.0f -  asWidthRatio / 100.0f);
196    asH = fbHeight * (1.0f -  asHeightRatio / 100.0f);
197    asX = (fbWidth - asW) / 2;
198    asY = (fbHeight - asH) / 2;
199
200    // calculate the position ratio
201    xRatio = (float)x/fbWidth;
202    yRatio = (float)y/fbHeight;
203    wRatio = (float)w/fbWidth;
204    hRatio = (float)h/fbHeight;
205
206    //Calculate the position...
207    x = (xRatio * asW) + asX;
208    y = (yRatio * asH) + asY;
209    w = (wRatio * asW);
210    h = (hRatio * asH);
211
212    return;
213}
214
215static inline bool isAlphaScaled(hwc_layer_1_t const* layer) {
216    int dst_w, dst_h, src_w, src_h;
217
218    hwc_rect_t displayFrame  = layer->displayFrame;
219    hwc_rect_t sourceCrop = layer->sourceCrop;
220
221    dst_w = displayFrame.right - displayFrame.left;
222    dst_h = displayFrame.bottom - displayFrame.top;
223
224    src_w = sourceCrop.right - sourceCrop.left;
225    src_h = sourceCrop.bottom - sourceCrop.top;
226
227    if(((src_w != dst_w) || (src_h != dst_h))) {
228        if(layer->blending != HWC_BLENDING_NONE)
229            return true;
230    }
231    return false;
232}
233
234void setListStats(hwc_context_t *ctx,
235        const hwc_display_contents_1_t *list, int dpy) {
236
237    ctx->listStats[dpy].numAppLayers = list->numHwLayers - 1;
238    ctx->listStats[dpy].fbLayerIndex = list->numHwLayers - 1;
239    ctx->listStats[dpy].skipCount = 0;
240    ctx->listStats[dpy].needsAlphaScale = false;
241    ctx->listStats[dpy].yuvCount = 0;
242
243    for (size_t i = 0; i < list->numHwLayers; i++) {
244        hwc_layer_1_t const* layer = &list->hwLayers[i];
245        private_handle_t *hnd = (private_handle_t *)layer->handle;
246
247        //reset stored yuv index
248        ctx->listStats[dpy].yuvIndices[i] = -1;
249
250        if(list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) {
251            continue;
252        //We disregard FB being skip for now! so the else if
253        } else if (isSkipLayer(&list->hwLayers[i])) {
254            ctx->listStats[dpy].skipCount++;
255        } else if (UNLIKELY(isYuvBuffer(hnd))) {
256            int& yuvCount = ctx->listStats[dpy].yuvCount;
257            ctx->listStats[dpy].yuvIndices[yuvCount] = i;
258            yuvCount++;
259        }
260
261        if(!ctx->listStats[dpy].needsAlphaScale)
262            ctx->listStats[dpy].needsAlphaScale = isAlphaScaled(layer);
263    }
264}
265
266
267static inline void calc_cut(float& leftCutRatio, float& topCutRatio,
268        float& rightCutRatio, float& bottomCutRatio, int orient) {
269    if(orient & HAL_TRANSFORM_FLIP_H) {
270        swap(leftCutRatio, rightCutRatio);
271    }
272    if(orient & HAL_TRANSFORM_FLIP_V) {
273        swap(topCutRatio, bottomCutRatio);
274    }
275    if(orient & HAL_TRANSFORM_ROT_90) {
276        //Anti clock swapping
277        float tmpCutRatio = leftCutRatio;
278        leftCutRatio = topCutRatio;
279        topCutRatio = rightCutRatio;
280        rightCutRatio = bottomCutRatio;
281        bottomCutRatio = tmpCutRatio;
282    }
283}
284
285bool isSecuring(hwc_context_t* ctx) {
286    if((ctx->mMDP.version < qdutils::MDSS_V5) &&
287       (ctx->mMDP.version > qdutils::MDP_V3_0) &&
288        ctx->mSecuring) {
289        return true;
290    }
291    return false;
292}
293
294bool isSecureModePolicy(int mdpVersion) {
295    if (mdpVersion < qdutils::MDSS_V5)
296        return true;
297    else
298        return false;
299}
300
301//Crops source buffer against destination and FB boundaries
302void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst,
303        const int fbWidth, const int fbHeight, int orient) {
304    int& crop_l = crop.left;
305    int& crop_t = crop.top;
306    int& crop_r = crop.right;
307    int& crop_b = crop.bottom;
308    int crop_w = crop.right - crop.left;
309    int crop_h = crop.bottom - crop.top;
310
311    int& dst_l = dst.left;
312    int& dst_t = dst.top;
313    int& dst_r = dst.right;
314    int& dst_b = dst.bottom;
315    int dst_w = abs(dst.right - dst.left);
316    int dst_h = abs(dst.bottom - dst.top);
317
318    float leftCutRatio = 0.0f, rightCutRatio = 0.0f, topCutRatio = 0.0f,
319            bottomCutRatio = 0.0f;
320
321    if(dst_l < 0) {
322        leftCutRatio = (float)(0.0f - dst_l) / (float)dst_w;
323        dst_l = 0;
324    }
325    if(dst_r > fbWidth) {
326        rightCutRatio = (float)(dst_r - fbWidth) / (float)dst_w;
327        dst_r = fbWidth;
328    }
329    if(dst_t < 0) {
330        topCutRatio = (float)(0 - dst_t) / (float)dst_h;
331        dst_t = 0;
332    }
333    if(dst_b > fbHeight) {
334        bottomCutRatio = (float)(dst_b - fbHeight) / (float)dst_h;
335        dst_b = fbHeight;
336    }
337
338    calc_cut(leftCutRatio, topCutRatio, rightCutRatio, bottomCutRatio, orient);
339    crop_l += crop_w * leftCutRatio;
340    crop_t += crop_h * topCutRatio;
341    crop_r -= crop_w * rightCutRatio;
342    crop_b -= crop_h * bottomCutRatio;
343}
344
345bool isExternalActive(hwc_context_t* ctx) {
346    return ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive;
347}
348
349int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy,
350                                                        int fd) {
351    int ret = 0;
352    struct mdp_buf_sync data;
353    int acquireFd[MAX_NUM_LAYERS];
354    int count = 0;
355    int releaseFd = -1;
356    int fbFd = -1;
357    memset(&data, 0, sizeof(data));
358    bool swapzero = false;
359    data.flags = MDP_BUF_SYNC_FLAG_WAIT;
360    data.acq_fen_fd = acquireFd;
361    data.rel_fen_fd = &releaseFd;
362    char property[PROPERTY_VALUE_MAX];
363    if(property_get("debug.egl.swapinterval", property, "1") > 0) {
364        if(atoi(property) == 0)
365            swapzero = true;
366    }
367
368    //Accumulate acquireFenceFds
369    for(uint32_t i = 0; i < list->numHwLayers; i++) {
370        if(list->hwLayers[i].compositionType == HWC_OVERLAY &&
371                        list->hwLayers[i].acquireFenceFd != -1) {
372            if(UNLIKELY(swapzero))
373                acquireFd[count++] = -1;
374            else
375                acquireFd[count++] = list->hwLayers[i].acquireFenceFd;
376        }
377        if(list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) {
378            if(UNLIKELY(swapzero))
379                acquireFd[count++] = -1;
380            else if(fd != -1) {
381                //set the acquireFD from fd - which is coming from c2d
382                acquireFd[count++] = fd;
383                // Buffer sync IOCTL should be async when using c2d fence is
384                // used
385                data.flags &= ~MDP_BUF_SYNC_FLAG_WAIT;
386            } else if(list->hwLayers[i].acquireFenceFd != -1)
387                acquireFd[count++] = list->hwLayers[i].acquireFenceFd;
388        }
389    }
390
391    data.acq_fen_fd_cnt = count;
392    fbFd = ctx->dpyAttr[dpy].fd;
393    //Waits for acquire fences, returns a release fence
394    if(LIKELY(!swapzero)) {
395        uint64_t start = systemTime();
396        ret = ioctl(fbFd, MSMFB_BUFFER_SYNC, &data);
397        ALOGD_IF(HWC_UTILS_DEBUG, "%s: time taken for MSMFB_BUFFER_SYNC IOCTL = %d",
398                            __FUNCTION__, (size_t) ns2ms(systemTime() - start));
399    }
400    if(ret < 0) {
401        ALOGE("ioctl MSMFB_BUFFER_SYNC failed, err=%s",
402                strerror(errno));
403    }
404    for(uint32_t i = 0; i < list->numHwLayers; i++) {
405        if(list->hwLayers[i].compositionType == HWC_OVERLAY ||
406           list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) {
407            //Close the acquireFenceFds
408            if(list->hwLayers[i].acquireFenceFd >= 0) {
409                close(list->hwLayers[i].acquireFenceFd);
410                list->hwLayers[i].acquireFenceFd = -1;
411            }
412            if(fd >= 0) {
413                close(fd);
414                fd = -1;
415            }
416            //Populate releaseFenceFds.
417            if(UNLIKELY(swapzero))
418                list->hwLayers[i].releaseFenceFd = -1;
419            else
420                list->hwLayers[i].releaseFenceFd = dup(releaseFd);
421        }
422    }
423    if(UNLIKELY(swapzero)){
424        list->retireFenceFd = -1;
425        close(releaseFd);
426    } else {
427        list->retireFenceFd = releaseFd;
428    }
429    return ret;
430}
431
432void LayerCache::resetLayerCache(int num) {
433    for(uint32_t i = 0; i < MAX_NUM_LAYERS; i++) {
434        hnd[i] = NULL;
435    }
436    numHwLayers = num;
437}
438
439void LayerCache::updateLayerCache(hwc_display_contents_1_t* list) {
440
441    int numFbLayers = 0;
442    int numCacheableLayers = 0;
443
444    canUseLayerCache = false;
445    //Bail if geometry changed or num of layers changed
446    if(list->flags & HWC_GEOMETRY_CHANGED ||
447       list->numHwLayers != numHwLayers ) {
448        resetLayerCache(list->numHwLayers);
449        return;
450    }
451
452    for(uint32_t i = 0; i < list->numHwLayers; i++) {
453        //Bail on skip layers
454        if(list->hwLayers[i].flags & HWC_SKIP_LAYER) {
455            resetLayerCache(list->numHwLayers);
456            return;
457        }
458
459        if(list->hwLayers[i].compositionType == HWC_FRAMEBUFFER) {
460            numFbLayers++;
461            if(hnd[i] == NULL) {
462                hnd[i] = list->hwLayers[i].handle;
463            } else if (hnd[i] ==
464                       list->hwLayers[i].handle) {
465                numCacheableLayers++;
466            } else {
467                hnd[i] = NULL;
468                return;
469            }
470        } else {
471            hnd[i] = NULL;
472        }
473    }
474    if(numFbLayers == numCacheableLayers)
475        canUseLayerCache = true;
476
477    //XXX: The marking part is separate, if MDP comp wants
478    // to use it in the future. Right now getting MDP comp
479    // to use this is more trouble than it is worth.
480    markCachedLayersAsOverlay(list);
481}
482
483void LayerCache::markCachedLayersAsOverlay(hwc_display_contents_1_t* list) {
484    //This optimization only works if ALL the layer handles
485    //that were on the framebuffer didn't change.
486    if(canUseLayerCache){
487        for(uint32_t i = 0; i < list->numHwLayers; i++) {
488            if (list->hwLayers[i].handle &&
489                list->hwLayers[i].handle == hnd[i] &&
490                list->hwLayers[i].compositionType != HWC_FRAMEBUFFER_TARGET)
491            {
492                list->hwLayers[i].compositionType = HWC_OVERLAY;
493            }
494        }
495    }
496
497}
498
499};//namespace
500