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