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