blob: daf3f80dfe49998c7c05ce92cffd54ed657b5a08 [file] [log] [blame]
Naseer Ahmedf48aef62012-07-20 09:05:53 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
Saurabh Shah56f610d2012-08-07 15:27:06 -07003 * Copyright (C) 2012, The Linux Foundation. All rights reserved.
Naseer Ahmedf48aef62012-07-20 09:05:53 -07004 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
Naseer Ahmed72cf9762012-07-21 12:17:13 -070018#define VIDEO_DEBUG 0
19#include <overlay.h>
20#include "hwc_qbuf.h"
Naseer Ahmedf48aef62012-07-20 09:05:53 -070021#include "hwc_video.h"
Saurabh Shah56f610d2012-08-07 15:27:06 -070022#include "external.h"
Naseer Ahmedf48aef62012-07-20 09:05:53 -070023
24namespace qhwc {
25
26#define FINAL_TRANSFORM_MASK 0x000F
Naseer Ahmedf48aef62012-07-20 09:05:53 -070027
28//Static Members
29ovutils::eOverlayState VideoOverlay::sState = ovutils::OV_CLOSED;
30int VideoOverlay::sYuvCount = 0;
31int VideoOverlay::sYuvLayerIndex = -1;
Naseer Ahmed4c588a22012-07-31 19:12:17 -070032bool VideoOverlay::sIsYuvLayerSkip = false;
33int VideoOverlay::sCCLayerIndex = -1;
Naseer Ahmedf48aef62012-07-20 09:05:53 -070034bool VideoOverlay::sIsModeOn = false;
Naseer Ahmedf48aef62012-07-20 09:05:53 -070035
36//Cache stats, figure out the state, config overlay
Naseer Ahmed5b6708a2012-08-02 13:46:08 -070037bool VideoOverlay::prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
Naseer Ahmedf48aef62012-07-20 09:05:53 -070038 sIsModeOn = false;
Naseer Ahmed96c4c952012-07-25 18:27:14 -070039 if(!ctx->mMDP.hasOverlay) {
Naseer Ahmed31da0b12012-07-31 18:55:33 -070040 ALOGD_IF(VIDEO_DEBUG,"%s, this hw doesnt support overlay", __FUNCTION__);
41 return false;
42 }
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -070043 if(sYuvLayerIndex == -1) {
44 return false;
45 }
Naseer Ahmedf48aef62012-07-20 09:05:53 -070046 chooseState(ctx);
47 //if the state chosen above is CLOSED, skip this block.
48 if(sState != ovutils::OV_CLOSED) {
Naseer Ahmed5b6708a2012-08-02 13:46:08 -070049 hwc_layer_1_t *yuvLayer = &list->hwLayers[sYuvLayerIndex];
50 hwc_layer_1_t *ccLayer = NULL;
Naseer Ahmed4c588a22012-07-31 19:12:17 -070051 if(sCCLayerIndex != -1)
52 ccLayer = &list->hwLayers[sCCLayerIndex];
53
54 if(configure(ctx, yuvLayer, ccLayer)) {
Saurabh Shah649cda62012-09-16 16:05:58 -070055 markFlags(yuvLayer, ccLayer);
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -070056 sIsModeOn = true;
Naseer Ahmedf48aef62012-07-20 09:05:53 -070057 }
58 }
59
60 ALOGD_IF(VIDEO_DEBUG, "%s: stats: yuvCount = %d, yuvIndex = %d,"
Naseer Ahmed4c588a22012-07-31 19:12:17 -070061 "IsYuvLayerSkip = %d, ccLayerIndex = %d, IsModeOn = %d",
62 __FUNCTION__, sYuvCount, sYuvLayerIndex,
63 sIsYuvLayerSkip, sCCLayerIndex, sIsModeOn);
Naseer Ahmedf48aef62012-07-20 09:05:53 -070064
65 return sIsModeOn;
66}
67
68void VideoOverlay::chooseState(hwc_context_t *ctx) {
69 ALOGD_IF(VIDEO_DEBUG, "%s: old state = %s", __FUNCTION__,
70 ovutils::getStateString(sState));
71
72 ovutils::eOverlayState newState = ovutils::OV_CLOSED;
Naseer Ahmedf48aef62012-07-20 09:05:53 -070073
74 //Support 1 video layer
75 if(sYuvCount == 1) {
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -070076 //Skip on primary, display on ext.
Naseer Ahmed4c588a22012-07-31 19:12:17 -070077 if(sIsYuvLayerSkip && ctx->mExtDisplay->getExternalDisplay()) {
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -070078 newState = ovutils::OV_2D_VIDEO_ON_TV;
Naseer Ahmed4c588a22012-07-31 19:12:17 -070079 } else if(sIsYuvLayerSkip) { //skip on primary, no ext
Naseer Ahmedf48aef62012-07-20 09:05:53 -070080 newState = ovutils::OV_CLOSED;
Naseer Ahmed72cf9762012-07-21 12:17:13 -070081 } else if(ctx->mExtDisplay->getExternalDisplay()) {
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -070082 //display on both
Naseer Ahmedf48aef62012-07-20 09:05:53 -070083 newState = ovutils::OV_2D_VIDEO_ON_PANEL_TV;
84 } else { //display on primary only
85 newState = ovutils::OV_2D_VIDEO_ON_PANEL;
86 }
87 }
88 sState = newState;
89 ALOGD_IF(VIDEO_DEBUG, "%s: new chosen state = %s", __FUNCTION__,
90 ovutils::getStateString(sState));
91}
92
Saurabh Shah649cda62012-09-16 16:05:58 -070093void VideoOverlay::markFlags(hwc_layer_1_t *yuvLayer, hwc_layer_1_t *ccLayer) {
Naseer Ahmedf48aef62012-07-20 09:05:53 -070094 switch(sState) {
95 case ovutils::OV_2D_VIDEO_ON_PANEL:
96 case ovutils::OV_2D_VIDEO_ON_PANEL_TV:
Saurabh Shah649cda62012-09-16 16:05:58 -070097 if(yuvLayer) {
98 yuvLayer->compositionType = HWC_OVERLAY;
99 yuvLayer->hints |= HWC_HINT_CLEAR_FB;
100 }
101 if(ccLayer) {
102 ccLayer->compositionType = HWC_OVERLAY;
103 }
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700104 break;
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700105 case ovutils::OV_2D_VIDEO_ON_TV:
Saurabh Shah649cda62012-09-16 16:05:58 -0700106 if(ccLayer) {
107 ccLayer->compositionType = HWC_OVERLAY;
108 }
109 break; //dont update video layer flags.
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700110 default:
111 break;
112 }
113}
114
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700115/* Helpers */
Naseer Ahmed5b6708a2012-08-02 13:46:08 -0700116bool configPrimVid(hwc_context_t *ctx, hwc_layer_1_t *layer) {
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700117 overlay::Overlay& ov = *(ctx->mOverlay);
118 private_handle_t *hnd = (private_handle_t *)layer->handle;
119 ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700120
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700121 ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
122 if (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
123 ovutils::setMdpFlags(mdpFlags,
124 ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
125 }
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700126
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700127 ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF;
128 if (ctx->numHwLayers == 1) {
129 isFgFlag = ovutils::IS_FG_SET;
130 }
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700131
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700132 ovutils::PipeArgs parg(mdpFlags,
133 info,
134 ovutils::ZORDER_0,
135 isFgFlag,
136 ovutils::ROT_FLAG_DISABLED);
137 ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg };
138 ov.setSource(pargs, ovutils::OV_PIPE0);
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700139
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700140 hwc_rect_t sourceCrop = layer->sourceCrop;
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700141 hwc_rect_t displayFrame = layer->displayFrame;
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700142
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700143 //Calculate the rect for primary based on whether the supplied position
144 //is within or outside bounds.
145 const int fbWidth =
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700146 ovutils::FrameBufferInfo::getInstance()->getWidth();
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700147 const int fbHeight =
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700148 ovutils::FrameBufferInfo::getInstance()->getHeight();
149
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700150 if( displayFrame.left < 0 ||
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700151 displayFrame.top < 0 ||
152 displayFrame.right > fbWidth ||
153 displayFrame.bottom > fbHeight) {
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700154 calculate_crop_rects(sourceCrop, displayFrame, fbWidth, fbHeight);
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700155 }
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700156
Saurabh Shah1023ce22012-09-05 18:45:59 -0700157 // source crop x,y,w,h
158 ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top,
159 sourceCrop.right - sourceCrop.left,
160 sourceCrop.bottom - sourceCrop.top);
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700161 //Only for Primary
162 ov.setCrop(dcrop, ovutils::OV_PIPE0);
163
164 int transform = layer->transform & FINAL_TRANSFORM_MASK;
165 ovutils::eTransform orient =
166 static_cast<ovutils::eTransform>(transform);
167 ov.setTransform(orient, ovutils::OV_PIPE0);
168
Saurabh Shah1023ce22012-09-05 18:45:59 -0700169 // position x,y,w,h
170 ovutils::Dim dpos(displayFrame.left,
171 displayFrame.top,
172 displayFrame.right - displayFrame.left,
173 displayFrame.bottom - displayFrame.top);
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700174 ov.setPosition(dpos, ovutils::OV_PIPE0);
175
176 if (!ov.commit(ovutils::OV_PIPE0)) {
177 ALOGE("%s: commit fails", __FUNCTION__);
178 return false;
179 }
180 return true;
181}
182
Naseer Ahmed5b6708a2012-08-02 13:46:08 -0700183bool configExtVid(hwc_context_t *ctx, hwc_layer_1_t *layer) {
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700184 overlay::Overlay& ov = *(ctx->mOverlay);
185 private_handle_t *hnd = (private_handle_t *)layer->handle;
186 ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
187
188 ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
189 if (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
190 ovutils::setMdpFlags(mdpFlags,
191 ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
192 }
193
194 ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF;
195 if (ctx->numHwLayers == 1) {
196 isFgFlag = ovutils::IS_FG_SET;
197 }
198
199 ovutils::PipeArgs parg(mdpFlags,
200 info,
201 ovutils::ZORDER_0,
202 isFgFlag,
203 ovutils::ROT_FLAG_DISABLED);
204 ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg };
205 ov.setSource(pargs, ovutils::OV_PIPE1);
206
207 hwc_rect_t sourceCrop = layer->sourceCrop;
208 // x,y,w,h
209 ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top,
210 sourceCrop.right - sourceCrop.left,
211 sourceCrop.bottom - sourceCrop.top);
212 //Only for External
213 ov.setCrop(dcrop, ovutils::OV_PIPE1);
214
215 // FIXME: Use source orientation for TV when source is portrait
216 //Only for External
217 ov.setTransform(0, ovutils::OV_PIPE1);
218
219 ovutils::Dim dpos;
220 hwc_rect_t displayFrame = layer->displayFrame;
221 dpos.x = displayFrame.left;
222 dpos.y = displayFrame.top;
223 dpos.w = (displayFrame.right - displayFrame.left);
224 dpos.h = (displayFrame.bottom - displayFrame.top);
225
226 //Only for External
227 ov.setPosition(dpos, ovutils::OV_PIPE1);
228
229 if (!ov.commit(ovutils::OV_PIPE1)) {
230 ALOGE("%s: commit fails", __FUNCTION__);
231 return false;
232 }
233 return true;
234}
235
Naseer Ahmed5b6708a2012-08-02 13:46:08 -0700236bool configExtCC(hwc_context_t *ctx, hwc_layer_1_t *layer) {
Naseer Ahmed4c588a22012-07-31 19:12:17 -0700237 if(layer == NULL)
238 return true;
239
240 overlay::Overlay& ov = *(ctx->mOverlay);
241 private_handle_t *hnd = (private_handle_t *)layer->handle;
242 ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
243 ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF;
244 ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
245 ovutils::PipeArgs parg(mdpFlags,
246 info,
247 ovutils::ZORDER_1,
248 isFgFlag,
249 ovutils::ROT_FLAG_DISABLED);
250 ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg };
251 ov.setSource(pargs, ovutils::OV_PIPE2);
252
253 hwc_rect_t sourceCrop = layer->sourceCrop;
254 // x,y,w,h
255 ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top,
256 sourceCrop.right - sourceCrop.left,
257 sourceCrop.bottom - sourceCrop.top);
258 //Only for External
259 ov.setCrop(dcrop, ovutils::OV_PIPE2);
260
261 // FIXME: Use source orientation for TV when source is portrait
262 //Only for External
263 ov.setTransform(0, ovutils::OV_PIPE2);
264
265 //Setting position same as crop
266 //FIXME stretch to full screen
267 ov.setPosition(dcrop, ovutils::OV_PIPE2);
268
269 if (!ov.commit(ovutils::OV_PIPE2)) {
270 ALOGE("%s: commit fails", __FUNCTION__);
271 return false;
272 }
273 return true;
274}
275
Naseer Ahmed5b6708a2012-08-02 13:46:08 -0700276bool VideoOverlay::configure(hwc_context_t *ctx, hwc_layer_1_t *yuvLayer,
277 hwc_layer_1_t *ccLayer) {
Naseer Ahmed4c588a22012-07-31 19:12:17 -0700278
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700279 bool ret = true;
280 if (LIKELY(ctx->mOverlay)) {
281 overlay::Overlay& ov = *(ctx->mOverlay);
282 // Set overlay state
283 ov.setState(sState);
284 switch(sState) {
285 case ovutils::OV_2D_VIDEO_ON_PANEL:
286 ret &= configPrimVid(ctx, yuvLayer);
287 break;
288 case ovutils::OV_2D_VIDEO_ON_PANEL_TV:
289 ret &= configExtVid(ctx, yuvLayer);
Naseer Ahmed4c588a22012-07-31 19:12:17 -0700290 ret &= configExtCC(ctx, ccLayer);
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700291 ret &= configPrimVid(ctx, yuvLayer);
292 break;
293 case ovutils::OV_2D_VIDEO_ON_TV:
294 ret &= configExtVid(ctx, yuvLayer);
Naseer Ahmed4c588a22012-07-31 19:12:17 -0700295 ret &= configExtCC(ctx, ccLayer);
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700296 break;
297 default:
298 return false;
299 }
300 } else {
301 //Ov null
302 return false;
303 }
304 return ret;
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700305}
306
Naseer Ahmed5b6708a2012-08-02 13:46:08 -0700307bool VideoOverlay::draw(hwc_context_t *ctx, hwc_display_contents_1_t *list)
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700308{
309 if(!sIsModeOn || sYuvLayerIndex == -1) {
310 return true;
311 }
312
Naseer Ahmed4c588a22012-07-31 19:12:17 -0700313 private_handle_t *hnd = (private_handle_t *)
314 list->hwLayers[sYuvLayerIndex].handle;
315
316 private_handle_t *cchnd = NULL;
317 if(sCCLayerIndex != -1) {
318 cchnd = (private_handle_t *)list->hwLayers[sCCLayerIndex].handle;
319 ctx->qbuf->lockAndAdd(cchnd);
320 }
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700321
322 // Lock this buffer for read.
323 ctx->qbuf->lockAndAdd(hnd);
Naseer Ahmed4c588a22012-07-31 19:12:17 -0700324
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700325 bool ret = true;
326 overlay::Overlay& ov = *(ctx->mOverlay);
327 ovutils::eOverlayState state = ov.getState();
328
329 switch (state) {
330 case ovutils::OV_2D_VIDEO_ON_PANEL_TV:
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700331 // Play external
332 if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE1)) {
333 ALOGE("%s: queueBuffer failed for external", __FUNCTION__);
334 ret = false;
335 }
Naseer Ahmed4c588a22012-07-31 19:12:17 -0700336 //Play CC on external
337 if (cchnd && !ov.queueBuffer(cchnd->fd, cchnd->offset,
338 ovutils::OV_PIPE2)) {
339 ALOGE("%s: queueBuffer failed for cc external", __FUNCTION__);
340 ret = false;
341 }
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700342 // Play primary
343 if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE0)) {
344 ALOGE("%s: queueBuffer failed for primary", __FUNCTION__);
345 ret = false;
346 }
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700347 break;
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700348 case ovutils::OV_2D_VIDEO_ON_PANEL:
349 // Play primary
350 if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE0)) {
351 ALOGE("%s: queueBuffer failed for primary", __FUNCTION__);
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700352 ret = false;
353 }
354 break;
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700355 case ovutils::OV_2D_VIDEO_ON_TV:
356 // Play external
357 if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE1)) {
358 ALOGE("%s: queueBuffer failed for external", __FUNCTION__);
359 ret = false;
360 }
Naseer Ahmed4c588a22012-07-31 19:12:17 -0700361 //Play CC on external
362 if (cchnd && !ov.queueBuffer(cchnd->fd, cchnd->offset,
363 ovutils::OV_PIPE2)) {
364 ALOGE("%s: queueBuffer failed for cc external", __FUNCTION__);
365 ret = false;
366 }
Naseer Ahmed4c588a22012-07-31 19:12:17 -0700367 break;
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700368 default:
369 ALOGE("%s Unused state %s", __FUNCTION__,
370 ovutils::getStateString(state));
371 break;
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700372 }
373
374 return ret;
375}
376
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700377}; //namespace qhwc