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