blob: 38ac695b76515813456d07bd1e0425ce4f562491 [file] [log] [blame]
Naseer Ahmedf48aef62012-07-20 09:05:53 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 * Copyright (C) 2012, Code Aurora Forum. All rights reserved.
4 *
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"
Naseer Ahmed72cf9762012-07-21 12:17:13 -070022#include "hwc_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)) {
Naseer Ahmedf48aef62012-07-20 09:05:53 -070055 markFlags(&list->hwLayers[sYuvLayerIndex]);
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
Naseer Ahmed5b6708a2012-08-02 13:46:08 -070093void VideoOverlay::markFlags(hwc_layer_1_t *layer) {
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:
97 layer->compositionType = HWC_OVERLAY;
98 layer->hints |= HWC_HINT_CLEAR_FB;
99 break;
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700100 case ovutils::OV_2D_VIDEO_ON_TV:
101 break; //dont update flags.
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700102 default:
103 break;
104 }
105}
106
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700107/* Helpers */
Naseer Ahmed5b6708a2012-08-02 13:46:08 -0700108bool configPrimVid(hwc_context_t *ctx, hwc_layer_1_t *layer) {
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700109 overlay::Overlay& ov = *(ctx->mOverlay);
110 private_handle_t *hnd = (private_handle_t *)layer->handle;
111 ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700112
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700113 ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
114 if (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
115 ovutils::setMdpFlags(mdpFlags,
116 ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
117 }
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700118
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700119 ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF;
120 if (ctx->numHwLayers == 1) {
121 isFgFlag = ovutils::IS_FG_SET;
122 }
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700123
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700124 ovutils::PipeArgs parg(mdpFlags,
125 info,
126 ovutils::ZORDER_0,
127 isFgFlag,
128 ovutils::ROT_FLAG_DISABLED);
129 ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg };
130 ov.setSource(pargs, ovutils::OV_PIPE0);
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700131
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700132 hwc_rect_t sourceCrop = layer->sourceCrop;
133 // x,y,w,h
134 ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top,
135 sourceCrop.right - sourceCrop.left,
136 sourceCrop.bottom - sourceCrop.top);
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700137
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700138 ovutils::Dim dpos;
139 hwc_rect_t displayFrame = layer->displayFrame;
140 dpos.x = displayFrame.left;
141 dpos.y = displayFrame.top;
142 dpos.w = (displayFrame.right - displayFrame.left);
143 dpos.h = (displayFrame.bottom - displayFrame.top);
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700144
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700145 //Calculate the rect for primary based on whether the supplied position
146 //is within or outside bounds.
147 const int fbWidth =
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700148 ovutils::FrameBufferInfo::getInstance()->getWidth();
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700149 const int fbHeight =
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700150 ovutils::FrameBufferInfo::getInstance()->getHeight();
151
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700152 if( displayFrame.left < 0 ||
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700153 displayFrame.top < 0 ||
154 displayFrame.right > fbWidth ||
155 displayFrame.bottom > fbHeight) {
156
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700157 calculate_crop_rects(sourceCrop, displayFrame, fbWidth, fbHeight);
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700158
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700159 //Update calculated width and height
160 dcrop.w = sourceCrop.right - sourceCrop.left;
161 dcrop.h = sourceCrop.bottom - sourceCrop.top;
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700162
Naseer Ahmed69476312012-07-31 19:13:19 -0700163 dpos.x = displayFrame.left;
164 dpos.y = displayFrame.top;
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700165 dpos.w = displayFrame.right - displayFrame.left;
166 dpos.h = displayFrame.bottom - displayFrame.top;
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700167 }
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700168
169 //Only for Primary
170 ov.setCrop(dcrop, ovutils::OV_PIPE0);
171
172 int transform = layer->transform & FINAL_TRANSFORM_MASK;
173 ovutils::eTransform orient =
174 static_cast<ovutils::eTransform>(transform);
175 ov.setTransform(orient, ovutils::OV_PIPE0);
176
177 ov.setPosition(dpos, ovutils::OV_PIPE0);
178
179 if (!ov.commit(ovutils::OV_PIPE0)) {
180 ALOGE("%s: commit fails", __FUNCTION__);
181 return false;
182 }
183 return true;
184}
185
Naseer Ahmed5b6708a2012-08-02 13:46:08 -0700186bool configExtVid(hwc_context_t *ctx, hwc_layer_1_t *layer) {
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700187 overlay::Overlay& ov = *(ctx->mOverlay);
188 private_handle_t *hnd = (private_handle_t *)layer->handle;
189 ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
190
191 ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
192 if (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
193 ovutils::setMdpFlags(mdpFlags,
194 ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
195 }
196
197 ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF;
198 if (ctx->numHwLayers == 1) {
199 isFgFlag = ovutils::IS_FG_SET;
200 }
201
202 ovutils::PipeArgs parg(mdpFlags,
203 info,
204 ovutils::ZORDER_0,
205 isFgFlag,
206 ovutils::ROT_FLAG_DISABLED);
207 ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg };
208 ov.setSource(pargs, ovutils::OV_PIPE1);
209
210 hwc_rect_t sourceCrop = layer->sourceCrop;
211 // x,y,w,h
212 ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top,
213 sourceCrop.right - sourceCrop.left,
214 sourceCrop.bottom - sourceCrop.top);
215 //Only for External
216 ov.setCrop(dcrop, ovutils::OV_PIPE1);
217
218 // FIXME: Use source orientation for TV when source is portrait
219 //Only for External
220 ov.setTransform(0, ovutils::OV_PIPE1);
221
222 ovutils::Dim dpos;
223 hwc_rect_t displayFrame = layer->displayFrame;
224 dpos.x = displayFrame.left;
225 dpos.y = displayFrame.top;
226 dpos.w = (displayFrame.right - displayFrame.left);
227 dpos.h = (displayFrame.bottom - displayFrame.top);
228
229 //Only for External
230 ov.setPosition(dpos, ovutils::OV_PIPE1);
231
232 if (!ov.commit(ovutils::OV_PIPE1)) {
233 ALOGE("%s: commit fails", __FUNCTION__);
234 return false;
235 }
236 return true;
237}
238
Naseer Ahmed5b6708a2012-08-02 13:46:08 -0700239bool configExtCC(hwc_context_t *ctx, hwc_layer_1_t *layer) {
Naseer Ahmed4c588a22012-07-31 19:12:17 -0700240 if(layer == NULL)
241 return true;
242
243 overlay::Overlay& ov = *(ctx->mOverlay);
244 private_handle_t *hnd = (private_handle_t *)layer->handle;
245 ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
246 ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF;
247 ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
248 ovutils::PipeArgs parg(mdpFlags,
249 info,
250 ovutils::ZORDER_1,
251 isFgFlag,
252 ovutils::ROT_FLAG_DISABLED);
253 ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg };
254 ov.setSource(pargs, ovutils::OV_PIPE2);
255
256 hwc_rect_t sourceCrop = layer->sourceCrop;
257 // x,y,w,h
258 ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top,
259 sourceCrop.right - sourceCrop.left,
260 sourceCrop.bottom - sourceCrop.top);
261 //Only for External
262 ov.setCrop(dcrop, ovutils::OV_PIPE2);
263
264 // FIXME: Use source orientation for TV when source is portrait
265 //Only for External
266 ov.setTransform(0, ovutils::OV_PIPE2);
267
268 //Setting position same as crop
269 //FIXME stretch to full screen
270 ov.setPosition(dcrop, ovutils::OV_PIPE2);
271
272 if (!ov.commit(ovutils::OV_PIPE2)) {
273 ALOGE("%s: commit fails", __FUNCTION__);
274 return false;
275 }
276 return true;
277}
278
Naseer Ahmed5b6708a2012-08-02 13:46:08 -0700279bool VideoOverlay::configure(hwc_context_t *ctx, hwc_layer_1_t *yuvLayer,
280 hwc_layer_1_t *ccLayer) {
Naseer Ahmed4c588a22012-07-31 19:12:17 -0700281
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700282 bool ret = true;
283 if (LIKELY(ctx->mOverlay)) {
284 overlay::Overlay& ov = *(ctx->mOverlay);
285 // Set overlay state
286 ov.setState(sState);
287 switch(sState) {
288 case ovutils::OV_2D_VIDEO_ON_PANEL:
289 ret &= configPrimVid(ctx, yuvLayer);
290 break;
291 case ovutils::OV_2D_VIDEO_ON_PANEL_TV:
292 ret &= configExtVid(ctx, yuvLayer);
Naseer Ahmed4c588a22012-07-31 19:12:17 -0700293 ret &= configExtCC(ctx, ccLayer);
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700294 ret &= configPrimVid(ctx, yuvLayer);
295 break;
296 case ovutils::OV_2D_VIDEO_ON_TV:
297 ret &= configExtVid(ctx, yuvLayer);
Naseer Ahmed4c588a22012-07-31 19:12:17 -0700298 ret &= configExtCC(ctx, ccLayer);
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700299 break;
300 default:
301 return false;
302 }
303 } else {
304 //Ov null
305 return false;
306 }
307 return ret;
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700308}
309
Naseer Ahmed5b6708a2012-08-02 13:46:08 -0700310bool VideoOverlay::draw(hwc_context_t *ctx, hwc_display_contents_1_t *list)
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700311{
312 if(!sIsModeOn || sYuvLayerIndex == -1) {
313 return true;
314 }
315
Naseer Ahmed4c588a22012-07-31 19:12:17 -0700316 private_handle_t *hnd = (private_handle_t *)
317 list->hwLayers[sYuvLayerIndex].handle;
318
319 private_handle_t *cchnd = NULL;
320 if(sCCLayerIndex != -1) {
321 cchnd = (private_handle_t *)list->hwLayers[sCCLayerIndex].handle;
322 ctx->qbuf->lockAndAdd(cchnd);
323 }
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700324
325 // Lock this buffer for read.
326 ctx->qbuf->lockAndAdd(hnd);
Naseer Ahmed4c588a22012-07-31 19:12:17 -0700327
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700328 bool ret = true;
329 overlay::Overlay& ov = *(ctx->mOverlay);
330 ovutils::eOverlayState state = ov.getState();
331
332 switch (state) {
333 case ovutils::OV_2D_VIDEO_ON_PANEL_TV:
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700334 // Play external
335 if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE1)) {
336 ALOGE("%s: queueBuffer failed for external", __FUNCTION__);
337 ret = false;
338 }
Naseer Ahmed4c588a22012-07-31 19:12:17 -0700339 //Play CC on external
340 if (cchnd && !ov.queueBuffer(cchnd->fd, cchnd->offset,
341 ovutils::OV_PIPE2)) {
342 ALOGE("%s: queueBuffer failed for cc external", __FUNCTION__);
343 ret = false;
344 }
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700345 // Play primary
346 if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE0)) {
347 ALOGE("%s: queueBuffer failed for primary", __FUNCTION__);
348 ret = false;
349 }
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700350 break;
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700351 case ovutils::OV_2D_VIDEO_ON_PANEL:
352 // Play primary
353 if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE0)) {
354 ALOGE("%s: queueBuffer failed for primary", __FUNCTION__);
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700355 ret = false;
356 }
357 break;
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700358 case ovutils::OV_2D_VIDEO_ON_TV:
359 // Play external
360 if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE1)) {
361 ALOGE("%s: queueBuffer failed for external", __FUNCTION__);
362 ret = false;
363 }
Naseer Ahmed4c588a22012-07-31 19:12:17 -0700364 //Play CC on external
365 if (cchnd && !ov.queueBuffer(cchnd->fd, cchnd->offset,
366 ovutils::OV_PIPE2)) {
367 ALOGE("%s: queueBuffer failed for cc external", __FUNCTION__);
368 ret = false;
369 }
Naseer Ahmed4c588a22012-07-31 19:12:17 -0700370 break;
Naseer Ahmed2cc53dd2012-07-31 19:11:48 -0700371 default:
372 ALOGE("%s Unused state %s", __FUNCTION__,
373 ovutils::getStateString(state));
374 break;
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700375 }
376
377 return ret;
378}
379
Naseer Ahmedf48aef62012-07-20 09:05:53 -0700380}; //namespace qhwc