blob: 180ab864ef3644d104c4f0992b186e7024e58317 [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
18#include "hwc_video.h"
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -070019#include "hwc_ext_observer.h"
Naseer Ahmedf48aef62012-07-20 09:05:53 -070020
21namespace qhwc {
22
23#define FINAL_TRANSFORM_MASK 0x000F
24#define VIDEO_DEBUG 0
25
26//Static Members
27ovutils::eOverlayState VideoOverlay::sState = ovutils::OV_CLOSED;
28int VideoOverlay::sYuvCount = 0;
29int VideoOverlay::sYuvLayerIndex = -1;
30bool VideoOverlay::sIsModeOn = false;
31bool VideoOverlay::sIsLayerSkip = false;
32
33//Cache stats, figure out the state, config overlay
34bool VideoOverlay::prepare(hwc_context_t *ctx, hwc_layer_list_t *list) {
35 sIsModeOn = false;
Naseer Ahmed31da0b12012-07-31 18:55:33 -070036 if(!ctx->hasOverlay) {
37 ALOGD_IF(VIDEO_DEBUG,"%s, this hw doesnt support overlay", __FUNCTION__);
38 return false;
39 }
Naseer Ahmedf48aef62012-07-20 09:05:53 -070040 chooseState(ctx);
41 //if the state chosen above is CLOSED, skip this block.
42 if(sState != ovutils::OV_CLOSED) {
43 if(configure(ctx, &list->hwLayers[sYuvLayerIndex])) {
44 markFlags(&list->hwLayers[sYuvLayerIndex]);
45 }
46 }
47
48 ALOGD_IF(VIDEO_DEBUG, "%s: stats: yuvCount = %d, yuvIndex = %d,"
49 "IsModeOn = %d, IsSkipLayer = %d", __FUNCTION__, sYuvCount,
50 sYuvLayerIndex, sIsModeOn, sIsLayerSkip);
51
52 return sIsModeOn;
53}
54
55void VideoOverlay::chooseState(hwc_context_t *ctx) {
56 ALOGD_IF(VIDEO_DEBUG, "%s: old state = %s", __FUNCTION__,
57 ovutils::getStateString(sState));
58
59 ovutils::eOverlayState newState = ovutils::OV_CLOSED;
60 //TODO check if device supports overlay and hdmi
61
62 //Support 1 video layer
63 if(sYuvCount == 1) {
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -070064 //Skip on primary, display on ext.
65 if(sIsLayerSkip && ctx->mExtDisplayObserver->getExternalDisplay()) {
Naseer Ahmedf48aef62012-07-20 09:05:53 -070066 //TODO
67 //VIDEO_ON_TV_ONLY
68 } else if(sIsLayerSkip) { //skip on primary, no ext
69 newState = ovutils::OV_CLOSED;
Naseer Ahmed0c8b7b52012-07-20 09:06:13 -070070 } else if(ctx->mExtDisplayObserver->getExternalDisplay()) {
71 //display on both
Naseer Ahmedf48aef62012-07-20 09:05:53 -070072 newState = ovutils::OV_2D_VIDEO_ON_PANEL_TV;
73 } else { //display on primary only
74 newState = ovutils::OV_2D_VIDEO_ON_PANEL;
75 }
76 }
77 sState = newState;
78 ALOGD_IF(VIDEO_DEBUG, "%s: new chosen state = %s", __FUNCTION__,
79 ovutils::getStateString(sState));
80}
81
82void VideoOverlay::markFlags(hwc_layer_t *layer) {
83 switch(sState) {
84 case ovutils::OV_2D_VIDEO_ON_PANEL:
85 case ovutils::OV_2D_VIDEO_ON_PANEL_TV:
86 layer->compositionType = HWC_OVERLAY;
87 layer->hints |= HWC_HINT_CLEAR_FB;
88 break;
89 //TODO
90 //case ovutils::OV_2D_VIDEO_ON_TV:
91 //just break, dont update flags.
92 default:
93 break;
94 }
95}
96
97bool VideoOverlay::configure(hwc_context_t *ctx, hwc_layer_t *layer)
98{
99 if (LIKELY(ctx->mOverlay)) {
100
101 overlay::Overlay& ov = *(ctx->mOverlay);
102 // Set overlay state
103 ov.setState(sState);
104
105 private_handle_t *hnd = (private_handle_t *)layer->handle;
106 ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
107
108 //TODO change this based on state.
109 ovutils::eDest dest = ovutils::OV_PIPE_ALL;
110
111 ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
112 if (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
113 ovutils::setMdpFlags(mdpFlags,
114 ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
115 }
116
117 ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF;
118 if (ctx->numHwLayers == 1) {
119 isFgFlag = ovutils::IS_FG_SET;
120 }
121
122 ovutils::PipeArgs parg(mdpFlags,
123 info,
124 ovutils::ZORDER_0,
125 isFgFlag,
126 ovutils::ROT_FLAG_DISABLED);
127 ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg };
128 ov.setSource(pargs, dest);
129
130 hwc_rect_t sourceCrop = layer->sourceCrop;
131 // x,y,w,h
132 ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top,
133 sourceCrop.right - sourceCrop.left,
134 sourceCrop.bottom - sourceCrop.top);
135 //Only for External
136 ov.setCrop(dcrop, ovutils::OV_PIPE1);
137
138 // FIXME: Use source orientation for TV when source is portrait
139 //Only for External
140 ov.setTransform(0, dest);
141
142 ovutils::Dim dpos;
143 hwc_rect_t displayFrame = layer->displayFrame;
144 dpos.x = displayFrame.left;
145 dpos.y = displayFrame.top;
146 dpos.w = (displayFrame.right - displayFrame.left);
147 dpos.h = (displayFrame.bottom - displayFrame.top);
148
149 //Only for External
150 ov.setPosition(dpos, ovutils::OV_PIPE1);
151
152 //Calculate the rect for primary based on whether the supplied position
153 //is within or outside bounds.
154 const int fbWidth =
155 ovutils::FrameBufferInfo::getInstance()->getWidth();
156 const int fbHeight =
157 ovutils::FrameBufferInfo::getInstance()->getHeight();
158
159 if( displayFrame.left < 0 ||
160 displayFrame.top < 0 ||
161 displayFrame.right > fbWidth ||
162 displayFrame.bottom > fbHeight) {
163
164 calculate_crop_rects(sourceCrop, displayFrame, fbWidth, fbHeight);
165
166 //Update calculated width and height
167 dcrop.w = sourceCrop.right - sourceCrop.left;
168 dcrop.h = sourceCrop.bottom - sourceCrop.top;
169
170 dpos.w = displayFrame.right - displayFrame.left;
171 dpos.h = displayFrame.bottom - displayFrame.top;
172 }
173
174 //Only for Primary
175 ov.setCrop(dcrop, ovutils::OV_PIPE0);
176
177 int transform = layer->transform & FINAL_TRANSFORM_MASK;
178 ovutils::eTransform orient =
179 static_cast<ovutils::eTransform>(transform);
180 ov.setTransform(orient, ovutils::OV_PIPE0);
181
182 ov.setPosition(dpos, ovutils::OV_PIPE0);
183
184 //Both prim and external
185 if (!ov.commit(dest)) {
186 ALOGE("%s: commit fails", __FUNCTION__);
187 return false;
188 }
189
190 sIsModeOn = true;
191 }
192 return sIsModeOn;
193}
194
195bool VideoOverlay::draw(hwc_context_t *ctx, hwc_layer_list_t *list)
196{
197 if(!sIsModeOn || sYuvLayerIndex == -1) {
198 return true;
199 }
200
201 private_handle_t *hnd =
202 (private_handle_t *)list->hwLayers[sYuvLayerIndex].handle;
203
204 // Lock this buffer for read.
205 ctx->qbuf->lockAndAdd(hnd);
206 bool ret = true;
207 overlay::Overlay& ov = *(ctx->mOverlay);
208 ovutils::eOverlayState state = ov.getState();
209
210 switch (state) {
211 case ovutils::OV_2D_VIDEO_ON_PANEL_TV:
212 case ovutils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
213 // Play external
214 if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE1)) {
215 ALOGE("%s: queueBuffer failed for external", __FUNCTION__);
216 ret = false;
217 }
218
219 // Play primary
220 if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE0)) {
221 ALOGE("%s: queueBuffer failed for primary", __FUNCTION__);
222 ret = false;
223 }
224
225 // Wait for external vsync to be done
226 if (!ov.waitForVsync(ovutils::OV_PIPE1)) {
227 ALOGE("%s: waitForVsync failed for external", __FUNCTION__);
228 ret = false;
229 }
230 break;
231 default:
232 // In most cases, displaying only to one (primary or external)
233 // so use OV_PIPE_ALL since overlay will ignore NullPipes
234 if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE_ALL)) {
235 ALOGE("%s: queueBuffer failed", __FUNCTION__);
236 ret = false;
237 }
238 break;
239 }
240
241 return ret;
242}
243
244
245}; //namespace qhwc