blob: 77402cc3317d61e98817ebe427a27507d1883521 [file] [log] [blame]
Naseer Ahmed29a26812012-06-14 00:56:20 -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_utils.h"
Naseer Ahmeda87da602012-07-01 23:54:19 -070019#define FINAL_TRANSFORM_MASK 0x000F
Naseer Ahmed29a26812012-06-14 00:56:20 -070020
21namespace qhwc {
22// Determine overlay state based on decoded video info
23static ovutils::eOverlayState determineOverlayState(hwc_context_t* ctx,
24 uint32_t bypassLayer,
25 uint32_t format)
26{
27 ovutils::eOverlayState state = ovutils::OV_CLOSED;
28
29 // Sanity check
30 if (!ctx) {
31 ALOGE("%s: NULL ctx", __FUNCTION__);
32 return state;
33 }
34
35 overlay::Overlay& ov = *(ctx->mOverlay);
36 state = ov.getState();
37
38 // If there are any bypassLayers, state is based on number of layers
39 if ((bypassLayer > 0) && (ctx->hdmiEnabled == EXT_TYPE_NONE)) {
40 if (bypassLayer == 1) {
41 state = ovutils::OV_BYPASS_1_LAYER;
42 } else if (bypassLayer == 2) {
43 state = ovutils::OV_BYPASS_2_LAYER;
44 } else if (bypassLayer == 3) {
45 state = ovutils::OV_BYPASS_3_LAYER;
46 }
47 return state;
48 }
49
50 // RGB is ambiguous for determining overlay state
51 if (ovutils::isRgb(ovutils::getMdpFormat(format))) {
52 return state;
53 }
54
55 // Content type is either 2D or 3D
56 uint32_t fmt3D = 0;//XXX: 3D - ovutils::getS3DFormat(format);
57
58 // Determine state based on the external display, content type, and hw type
59 if (ctx->hdmiEnabled == EXT_TYPE_HDMI) {
60 // External display is HDMI
61 if (fmt3D) {
62 // Content type is 3D
63 if (ovutils::is3DTV()) {
64 // TV panel type is 3D
65 state = ovutils::OV_3D_VIDEO_ON_3D_TV;
66 } else {
67 // TV panel type is 2D
68 state = ovutils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV;
69 }
70 } else {
71 // Content type is 2D
72 if (ovutils::FrameBufferInfo::getInstance()->supportTrueMirroring()) {
73 // True UI mirroring is supported
74 state = ovutils::OV_2D_TRUE_UI_MIRROR;
75 } else {
76 // True UI mirroring is not supported
77 state = ovutils::OV_2D_VIDEO_ON_PANEL_TV;
78 }
79 }
80 } else if (ctx->hdmiEnabled == EXT_TYPE_WIFI) {
81 // External display is Wifi (currently unsupported)
82 ALOGE("%s: WIFI external display is unsupported", __FUNCTION__);
83 return state;
84 } else {
85 // No external display (primary panel only)
86 if (fmt3D) {
87 // Content type is 3D
88 if (ovutils::usePanel3D()) {
89 // Primary panel type is 3D
90 state = ovutils::OV_3D_VIDEO_ON_3D_PANEL;
91 } else {
92 // Primary panel type is 2D
93 state = ovutils::OV_3D_VIDEO_ON_2D_PANEL;
94 }
95 } else {
96 // Content type is 2D
97 state = ovutils::OV_2D_VIDEO_ON_PANEL;
98 }
99 }
100
101 return state;
102}
103
104void setOverlayState(hwc_context_t *ctx, ovutils::eOverlayState state)
105{
106 if (!ctx) {
107 ALOGE("%s: NULL ctx", __FUNCTION__);
108 return;
109 }
110
111 overlay::Overlay *ov = ctx->mOverlay;
112 if (!ov) {
113 ALOGE("%s: NULL OV object", __FUNCTION__);
114 return;
115 }
116 ov->setState(state);
117}
118
119bool prepareOverlay(hwc_context_t *ctx, hwc_layer_t *layer)
120{
121 bool ret = false;
122 if (LIKELY(ctx->mOverlay)) {
123 private_handle_t *hnd = (private_handle_t *)layer->handle;
124 overlay::Overlay& ov = *(ctx->mOverlay);
125 ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
126
127 // Set overlay state
128 ovutils::eOverlayState state = determineOverlayState(ctx, 0, info.format);
129 setOverlayState(ctx, state);
130
131 ovutils::eDest dest = ovutils::OV_PIPE_ALL;
132
133 // In the true UI mirroring case, video needs to go to OV_PIPE0 (for
134 // primary) and OV_PIPE1 (for external)
135 if (state == ovutils::OV_2D_TRUE_UI_MIRROR) {
136 dest = static_cast<ovutils::eDest>(
137 ovutils::OV_PIPE0 | ovutils::OV_PIPE1);
138 }
139
140 // Order order order
141 // setSource - just setting source
142 // setParameter - changes src w/h/f accordingly
143 // setCrop - ROI - that is src_rect
144 // setPosition - need to do scaling
145 // commit - commit changes to mdp driver
146 // queueBuffer - not here, happens when draw is called
147
148 ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
149 if (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
150 ovutils::setMdpFlags(mdpFlags,
151 ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
152 }
153
154 // FIXME: Use source orientation for TV when source is portrait
155 int transform = layer->transform & FINAL_TRANSFORM_MASK;
156 ovutils::eTransform orient =
157 static_cast<ovutils::eTransform>(transform);
158
159 ovutils::eWait waitFlag = ovutils::NO_WAIT;
160 if (ctx->skipComposition == true) {
161 waitFlag = ovutils::WAIT;
162 }
163
164 ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF;
165 if (ctx->numHwLayers == 1) {
166 isFgFlag = ovutils::IS_FG_SET;
167 }
168
169 ovutils::PipeArgs parg(mdpFlags,
170 orient,
171 info,
172 waitFlag,
173 ovutils::ZORDER_0,
174 isFgFlag,
175 ovutils::ROT_FLAG_DISABLED);
176 ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg };
177 ret = ov.setSource(pargs, dest);
178 if (!ret) {
179 ALOGE("%s: setSource failed", __FUNCTION__);
180 return ret;
181 }
182
183 const ovutils::Params prms (ovutils::OVERLAY_TRANSFORM, orient);
184 ret = ov.setParameter(prms, dest);
185 if (!ret) {
186 ALOGE("%s: setParameter failed transform %x", __FUNCTION__, orient);
187 return ret;
188 }
189
190 hwc_rect_t sourceCrop = layer->sourceCrop;
191 // x,y,w,h
192 ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top, // x, y
193 sourceCrop.right - sourceCrop.left, // w
194 sourceCrop.bottom - sourceCrop.top);// h
195 ret = ov.setCrop(dcrop, dest);
196 if (!ret) {
197 ALOGE("%s: setCrop failed", __FUNCTION__);
198 return ret;
199 }
200
201 int orientation = 0;
202 ovutils::Dim dim;
203 hwc_rect_t displayFrame = layer->displayFrame;
204 dim.x = displayFrame.left;
205 dim.y = displayFrame.top;
206 dim.w = (displayFrame.right - displayFrame.left);
207 dim.h = (displayFrame.bottom - displayFrame.top);
208 dim.o = orientation;
209
210 ret = ov.setPosition(dim, dest);
211 if (!ret) {
212 ALOGE("%s: setPosition failed", __FUNCTION__);
213 return ret;
214 }
215 if (!ov.commit(dest)) {
216 ALOGE("%s: commit fails", __FUNCTION__);
217 return false;
218 }
219 }
220 return true;
221}
222
223bool drawLayerUsingOverlay(hwc_context_t *ctx, hwc_layer_t *layer)
224{
225 private_handle_t *hnd = (private_handle_t *)layer->handle;
226
227 // Lock this buffer for read.
228 ctx->qbuf->lockAndAdd(hnd);
229 bool ret = true;
230 overlay::Overlay& ov = *(ctx->mOverlay);
231 ovutils::eOverlayState state = ov.getState();
232
233 // Differentiate between states that need to wait for vsync
234 switch (state) {
235 case ovutils::OV_2D_VIDEO_ON_PANEL_TV:
236 case ovutils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
237 case ovutils::OV_2D_TRUE_UI_MIRROR:
238 // If displaying on both primary and external, must play each
239 // pipe individually since wait for vsync needs to be done at
240 // the end. Do the following:
241 // - Play external
242 // - Play primary
243 // - Wait for external vsync to be done
244 // NOTE: In these states
245 // - primary VG = OV_PIPE0
246 // - external VG = OV_PIPE1
247 // - external RGB = OV_PIPE2
248 // - Only in true UI mirroring case, played by fb
249
250 // Same FD for both primary and external VG pipes
251 ov.setMemoryId(hnd->fd, static_cast<ovutils::eDest>(
252 ovutils::OV_PIPE0 | ovutils::OV_PIPE1));
253
254 // Play external
255 if (!ov.queueBuffer(hnd->offset, ovutils::OV_PIPE1)) {
256 ALOGE("%s: queueBuffer failed for external", __FUNCTION__);
257 ret = false;
258 }
259
260 // Play primary
261 if (!ov.queueBuffer(hnd->offset, ovutils::OV_PIPE0)) {
262 ALOGE("%s: queueBuffer failed for primary", __FUNCTION__);
263 ret = false;
264 }
265
266 // Wait for external vsync to be done
267 if (!ov.waitForVsync(ovutils::OV_PIPE1)) {
268 ALOGE("%s: waitForVsync failed for external", __FUNCTION__);
269 ret = false;
270 }
271 break;
272 default:
273 // In most cases, displaying only to one (primary or external)
274 // so use OV_PIPE_ALL since overlay will ignore NullPipes
275 ov.setMemoryId(hnd->fd, ovutils::OV_PIPE_ALL);
276 if (!ov.queueBuffer(hnd->offset, ovutils::OV_PIPE_ALL)) {
277 ALOGE("%s: queueBuffer failed", __FUNCTION__);
278 ret = false;
279 }
280 break;
281 }
282
283 if (!ret) {
284 ALOGE("%s: failed", __FUNCTION__);
285 }
286 return ret;
287}
288
289void cleanOverlays(hwc_context_t *ctx )
290{
291 //XXX: handle for HDMI
292 if(0 == ctx->yuvBufferCount)
293 setOverlayState(ctx, ovutils::OV_CLOSED);
294}
295}; //namespace qhwc