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
6 * retained 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
21#define DEBUG_FBUPDATE 0
22#include <gralloc_priv.h>
23#include "hwc_fbupdate.h"
24
25namespace qhwc {
26
27namespace ovutils = overlay::utils;
28
29IFBUpdate* IFBUpdate::getObject(const int& width, const int& dpy) {
30    if(width > MAX_DISPLAY_DIM) {
31        return new FBUpdateHighRes(dpy);
32    }
33    return new FBUpdateLowRes(dpy);
34}
35
36inline void IFBUpdate::reset() {
37    mModeOn = false;
38}
39
40//================= Low res====================================
41FBUpdateLowRes::FBUpdateLowRes(const int& dpy): IFBUpdate(dpy) {}
42
43inline void FBUpdateLowRes::reset() {
44    IFBUpdate::reset();
45    mDest = ovutils::OV_INVALID;
46}
47
48bool FBUpdateLowRes::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
49                             int fbZorder) {
50    if(!ctx->mMDP.hasOverlay) {
51        ALOGD_IF(DEBUG_FBUPDATE, "%s, this hw doesnt support overlays",
52                 __FUNCTION__);
53        return false;
54    }
55    mModeOn = configure(ctx, list, fbZorder);
56    return mModeOn;
57}
58
59// Configure
60bool FBUpdateLowRes::configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
61                               int fbZorder) {
62    bool ret = false;
63    hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
64    if (LIKELY(ctx->mOverlay)) {
65        overlay::Overlay& ov = *(ctx->mOverlay);
66        private_handle_t *hnd = (private_handle_t *)layer->handle;
67        ovutils::Whf info(getWidth(hnd), getHeight(hnd),
68                          ovutils::getMdpFormat(hnd->format), hnd->size);
69
70        //Request an RGB pipe
71        ovutils::eDest dest = ov.nextPipe(ovutils::OV_MDP_PIPE_ANY, mDpy);
72        if(dest == ovutils::OV_INVALID) { //None available
73            ALOGE("%s: No pipes available to configure framebuffer",
74                __FUNCTION__);
75            return false;
76        }
77
78        mDest = dest;
79
80        ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_BLEND_FG_PREMULT;
81
82        ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
83
84        //XXX: FB layer plane alpha is currently sent as zero from
85        //surfaceflinger
86        ovutils::PipeArgs parg(mdpFlags,
87                info,
88                zOrder,
89                ovutils::IS_FG_OFF,
90                ovutils::ROT_FLAGS_NONE,
91                ovutils::DEFAULT_PLANE_ALPHA,
92                (ovutils::eBlending) getBlending(layer->blending));
93        ov.setSource(parg, dest);
94
95        hwc_rect_t sourceCrop;
96        getNonWormholeRegion(list, sourceCrop);
97        // x,y,w,h
98        ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top,
99                           sourceCrop.right - sourceCrop.left,
100                           sourceCrop.bottom - sourceCrop.top);
101        ov.setCrop(dcrop, dest);
102
103        int transform = layer->transform;
104        ovutils::eTransform orient =
105            static_cast<ovutils::eTransform>(transform);
106        ov.setTransform(orient, dest);
107
108        hwc_rect_t displayFrame = sourceCrop;
109        ovutils::Dim dpos(displayFrame.left,
110                          displayFrame.top,
111                          displayFrame.right - displayFrame.left,
112                          displayFrame.bottom - displayFrame.top);
113        // Calculate the actionsafe dimensions for External(dpy = 1 or 2)
114        if(mDpy)
115            getActionSafePosition(ctx, mDpy, dpos.x, dpos.y, dpos.w, dpos.h);
116        ov.setPosition(dpos, dest);
117
118        ret = true;
119        if (!ov.commit(dest)) {
120            ALOGE("%s: commit fails", __FUNCTION__);
121            ret = false;
122        }
123    }
124    return ret;
125}
126
127bool FBUpdateLowRes::draw(hwc_context_t *ctx, private_handle_t *hnd)
128{
129    if(!mModeOn) {
130        return true;
131    }
132    bool ret = true;
133    overlay::Overlay& ov = *(ctx->mOverlay);
134    ovutils::eDest dest = mDest;
135    if (!ov.queueBuffer(hnd->fd, hnd->offset, dest)) {
136        ALOGE("%s: queueBuffer failed for FBUpdate", __FUNCTION__);
137        ret = false;
138    }
139    return ret;
140}
141
142//================= High res====================================
143FBUpdateHighRes::FBUpdateHighRes(const int& dpy): IFBUpdate(dpy) {}
144
145inline void FBUpdateHighRes::reset() {
146    IFBUpdate::reset();
147    mDestLeft = ovutils::OV_INVALID;
148    mDestRight = ovutils::OV_INVALID;
149}
150
151bool FBUpdateHighRes::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
152                              int fbZorder) {
153    if(!ctx->mMDP.hasOverlay) {
154        ALOGD_IF(DEBUG_FBUPDATE, "%s, this hw doesnt support overlays",
155                 __FUNCTION__);
156        return false;
157    }
158    ALOGD_IF(DEBUG_FBUPDATE, "%s, mModeOn = %d", __FUNCTION__, mModeOn);
159    mModeOn = configure(ctx, list, fbZorder);
160    return mModeOn;
161}
162
163// Configure
164bool FBUpdateHighRes::configure(hwc_context_t *ctx,
165                                hwc_display_contents_1 *list, int fbZorder) {
166    bool ret = false;
167    hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
168    if (LIKELY(ctx->mOverlay)) {
169        overlay::Overlay& ov = *(ctx->mOverlay);
170        private_handle_t *hnd = (private_handle_t *)layer->handle;
171        ovutils::Whf info(getWidth(hnd), getHeight(hnd),
172                          ovutils::getMdpFormat(hnd->format), hnd->size);
173
174        //Request left RGB pipe
175        ovutils::eDest destL = ov.nextPipe(ovutils::OV_MDP_PIPE_RGB, mDpy);
176        if(destL == ovutils::OV_INVALID) { //None available
177            ALOGE("%s: No pipes available to configure framebuffer",
178                __FUNCTION__);
179            return false;
180        }
181        //Request right RGB pipe
182        ovutils::eDest destR = ov.nextPipe(ovutils::OV_MDP_PIPE_RGB, mDpy);
183        if(destR == ovutils::OV_INVALID) { //None available
184            ALOGE("%s: No pipes available to configure framebuffer",
185                __FUNCTION__);
186            return false;
187        }
188
189        mDestLeft = destL;
190        mDestRight = destR;
191
192        ovutils::eMdpFlags mdpFlagsL = ovutils::OV_MDP_BLEND_FG_PREMULT;
193
194        ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
195
196        //XXX: FB layer plane alpha is currently sent as zero from
197        //surfaceflinger
198        ovutils::PipeArgs pargL(mdpFlagsL,
199                info,
200                zOrder,
201                ovutils::IS_FG_OFF,
202                ovutils::ROT_FLAGS_NONE,
203                ovutils::DEFAULT_PLANE_ALPHA,
204                (ovutils::eBlending) getBlending(layer->blending));
205        ov.setSource(pargL, destL);
206
207        ovutils::eMdpFlags mdpFlagsR = mdpFlagsL;
208        ovutils::setMdpFlags(mdpFlagsR, ovutils::OV_MDSS_MDP_RIGHT_MIXER);
209        ovutils::PipeArgs pargR(mdpFlagsR,
210                info,
211                zOrder,
212                ovutils::IS_FG_OFF,
213                ovutils::ROT_FLAGS_NONE,
214                ovutils::DEFAULT_PLANE_ALPHA,
215                (ovutils::eBlending) getBlending(layer->blending));
216        ov.setSource(pargR, destR);
217
218        hwc_rect_t sourceCrop;
219        getNonWormholeRegion(list, sourceCrop);
220        ovutils::Dim dcropL(sourceCrop.left, sourceCrop.top,
221                            (sourceCrop.right - sourceCrop.left) / 2,
222                            sourceCrop.bottom - sourceCrop.top);
223        ovutils::Dim dcropR(
224            sourceCrop.left + (sourceCrop.right - sourceCrop.left) / 2,
225            sourceCrop.top,
226            (sourceCrop.right - sourceCrop.left) / 2,
227            sourceCrop.bottom - sourceCrop.top);
228        ov.setCrop(dcropL, destL);
229        ov.setCrop(dcropR, destR);
230
231        int transform = layer->transform;
232        ovutils::eTransform orient =
233            static_cast<ovutils::eTransform>(transform);
234        ov.setTransform(orient, destL);
235        ov.setTransform(orient, destR);
236
237        hwc_rect_t displayFrame = sourceCrop;
238        //For FB left, top will always be 0
239        //That should also be the case if using 2 mixers for single display
240        ovutils::Dim dposL(displayFrame.left,
241                           displayFrame.top,
242                           (displayFrame.right - displayFrame.left) / 2,
243                           displayFrame.bottom - displayFrame.top);
244        ov.setPosition(dposL, destL);
245        ovutils::Dim dposR(0,
246                           displayFrame.top,
247                           (displayFrame.right - displayFrame.left) / 2,
248                           displayFrame.bottom - displayFrame.top);
249        ov.setPosition(dposR, destR);
250
251        ret = true;
252        if (!ov.commit(destL)) {
253            ALOGE("%s: commit fails for left", __FUNCTION__);
254            ret = false;
255        }
256        if (!ov.commit(destR)) {
257            ALOGE("%s: commit fails for right", __FUNCTION__);
258            ret = false;
259        }
260    }
261    return ret;
262}
263
264bool FBUpdateHighRes::draw(hwc_context_t *ctx, private_handle_t *hnd)
265{
266    if(!mModeOn) {
267        return true;
268    }
269    bool ret = true;
270    overlay::Overlay& ov = *(ctx->mOverlay);
271    ovutils::eDest destL = mDestLeft;
272    ovutils::eDest destR = mDestRight;
273    if (!ov.queueBuffer(hnd->fd, hnd->offset, destL)) {
274        ALOGE("%s: queue failed for left of dpy = %d",
275              __FUNCTION__, mDpy);
276        ret = false;
277    }
278    if (!ov.queueBuffer(hnd->fd, hnd->offset, destR)) {
279        ALOGE("%s: queue failed for right of dpy = %d",
280              __FUNCTION__, mDpy);
281        ret = false;
282    }
283    return ret;
284}
285
286//---------------------------------------------------------------------
287}; //namespace qhwc
288