blob: fa246421ee1503ea9f9af02814ebeefcda868a9f [file] [log] [blame]
Iliyan Malchev202a77d2012-06-11 14:41:12 -07001/*
2 * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
3
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of Code Aurora Forum, Inc. nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#define EXTDEBUG 0
31class ExtDispOnly {
32
33 enum ExternalOnlyMode {
34 EXT_ONLY_MODE_OFF = 0,
35 EXT_ONLY_MODE_ON = 1,
36 };
37
38 enum {
39 MAX_EXT_ONLY_LAYERS = 2,
40 };
41
42public:
43 /* Initialize, allocate data members */
44 static void init();
45
46 /* Deallocate data members */
47 static void destroy();
48
49 /* Closes all the overlay channels */
50 static void close();
51
52 /* Prepare overlay and configures mdp pipes */
53 static int prepare(hwc_context_t *ctx, hwc_layer_t *layer, int index,
54 bool waitForVsync);
55
56 /* Returns status of external-only mode */
57 static bool isModeOn();
58
59 /* Updates stats and pipe config related to external_only and external_block layers
60 * If we are staring or stopping this mode, update default mirroring.
61 */
62 static int update(hwc_context_t* ctx, hwc_layer_list_t* list);
63
64 /* Stores the locked handle for the buffer that was successfully queued */
65 static void storeLockedHandles(hwc_layer_list_t* list);
66
67 /* Queue buffers to mdp for display */
68 static int draw(hwc_context_t *ctx, hwc_layer_list_t *list);
69
70private:
71 /* Locks a buffer and marks it as locked */
72 static void lockBuffer(native_handle_t *hnd);
73
74 /* Unlocks a buffer and clears the locked flag */
75 static void unlockBuffer(native_handle_t *hnd);
76
77 /* Unlocks buffers queued in previous round (and displayed by now)
78 * Clears the handle cache.
79 */
80 static void unlockPreviousBuffers();
81
82 /* Closes the a range of overlay channels */
83 static void closeRange(int start);
84
85 /* Start default external mirroring */
86 static void startDefaultMirror(hwc_context_t* ctx);
87
88 /* Stop default external mirroring */
89 static void stopDefaultMirror(hwc_context_t* ctx);
90
91 /* Checks if external-only mode is starting */
92 static bool isExtModeStarting(hwc_context_t* ctx, const int&
93 numExtLayers);
94
95 /* Checks if external-only mode is stopping */
96 static bool isExtModeStopping(hwc_context_t* ctx, const int&
97 numExtLayers);
98
99 //Data members
100#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
101 static overlay::OverlayUI* sOvExtUI[MAX_EXT_ONLY_LAYERS];
102 static native_handle_t* sPreviousExtHandle[MAX_EXT_ONLY_LAYERS];
103 static ExternalOnlyMode sExtOnlyMode;
104 static int sNumExtOnlyLayers;
105 static bool sSkipLayerPresent;
106 static bool sBlockLayerPresent;
107 static int sBlockLayerIndex;
108#endif
109}; //class ExtDispOnly
110
111void ExtDispOnly::lockBuffer(native_handle_t *hnd) {
112#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
113 private_handle_t* phnd = (private_handle_t*)hnd;
114
115 //Genlock is reference counted and recursive.
116 //Do not accidently lock a locked buffer.
117 if(phnd && (phnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK)) {
118 LOGE_IF(EXTDEBUG, "%s: handle %p already locked", __func__, phnd);
119 return;
120 }
121 if (GENLOCK_FAILURE == genlock_lock_buffer(hnd, GENLOCK_READ_LOCK,
122 GENLOCK_MAX_TIMEOUT)) {
123 LOGE("%s: genlock_lock_buffer(READ) failed", __func__);
124 return;
125 }
126 phnd->flags |= private_handle_t::PRIV_FLAGS_HWC_LOCK;
127 LOGE_IF(EXTDEBUG, "%s: locked handle = %p", __func__, hnd);
128#endif
129}
130
131void ExtDispOnly::unlockBuffer(native_handle_t *hnd) {
132#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
133 //Check if buffer is still around
134 if(private_handle_t::validate(hnd) != 0) {
135 LOGE("%s Handle already deallocated", __func__);
136 return;
137 }
138
139 private_handle_t* phnd = (private_handle_t*)hnd;
140
141 //Check if buffer was locked in the first place
142 if((phnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK) == 0) {
143 LOGE("%s Handle not locked, cannot unlock", __func__);
144 return;
145 }
146
147 //Actually try to unlock
148 if (GENLOCK_FAILURE == genlock_unlock_buffer(hnd)) {
149 LOGE("%s: genlock_unlock_buffer failed", __func__);
150 return;
151 }
152
153 //Clear the locked flag
154 phnd->flags &= ~private_handle_t::PRIV_FLAGS_HWC_LOCK;
155 LOGE_IF(EXTDEBUG, "%s: unlocked handle = %p", __func__, hnd);
156#endif
157}
158
159void ExtDispOnly::unlockPreviousBuffers() {
160#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
161 for(int i = 0; (i < MAX_EXT_ONLY_LAYERS) && sPreviousExtHandle[i]; i++) {
162 LOGE_IF(EXTDEBUG, "%s", __func__);
163 ExtDispOnly::unlockBuffer(sPreviousExtHandle[i]);
164 sPreviousExtHandle[i] = NULL;
165 }
166#endif
167}
168
169void ExtDispOnly::init() {
170#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
171 for(int i = 0; i < MAX_EXT_ONLY_LAYERS; i++) {
172 sOvExtUI[i] = new overlay::OverlayUI();
173 sPreviousExtHandle[i] = NULL;
174 }
175 sExtOnlyMode = EXT_ONLY_MODE_OFF;
176 sNumExtOnlyLayers = 0;
177 sSkipLayerPresent = false;
178 sBlockLayerPresent = false;
179 sBlockLayerIndex = -1;
180 LOGE_IF(EXTDEBUG, "%s", __func__);
181#endif
182}
183
184void ExtDispOnly::destroy() {
185#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
186 for(int i = 0; i < MAX_EXT_ONLY_LAYERS; i++) {
187 delete sOvExtUI[i];
188 }
189#endif
190}
191
192void ExtDispOnly::closeRange(int start) {
193#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
194 for (int index = start; index < MAX_EXT_ONLY_LAYERS; index++) {
195 if(sPreviousExtHandle[index]) {
196 LOGE_IF(EXTDEBUG, "%s", __func__);
197 ExtDispOnly::unlockBuffer(sPreviousExtHandle[index]);
198 sPreviousExtHandle[index] = NULL;
199 }
200 sOvExtUI[index]->closeChannel();
201 }
202#endif
203}
204
205void inline ExtDispOnly::close() {
206#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
207 closeRange(0);
208#endif
209}
210
211int ExtDispOnly::prepare(hwc_context_t *ctx, hwc_layer_t *layer, int index,
212 bool waitForVsync) {
213#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
214 if(ctx->mHDMIEnabled == EXT_DISPLAY_OFF ||
215 ctx->pendingHDMI == true)
216 return -1;
217
218 if (ctx && sOvExtUI[index]) {
219 private_hwc_module_t* hwcModule = reinterpret_cast<
220 private_hwc_module_t*>(ctx->device.common.module);
221 if (!hwcModule) {
222 LOGE("%s null module", __func__);
223 return -1;
224 }
225 private_handle_t *hnd = (private_handle_t *)layer->handle;
226 if(!hnd) {
227 LOGE("%s handle null", __func__);
228 return -1;
229 }
230 overlay::OverlayUI *ovUI = sOvExtUI[index];
231 int ret = 0;
232 //int orientation = layer->transform;
233 //Assuming layers will always be source landscape
234 const int orientation = 0;
235 overlay_buffer_info info;
236 hwc_rect_t sourceCrop = layer->sourceCrop;
237 info.width = sourceCrop.right - sourceCrop.left;
238 info.height = sourceCrop.bottom - sourceCrop.top;
239 info.format = hnd->format;
240 info.size = hnd->size;
241
242
243 const int fbnum = ctx->mHDMIEnabled; //HDMI or WFD
244 const bool isFg = false;
245 //Just to differentiate zorders for different layers
246 const int zorder = index;
247 const bool isVGPipe = true;
248 ovUI->setSource(info, orientation);
249 ovUI->setDisplayParams(fbnum, waitForVsync, isFg, zorder, isVGPipe);
250 const int fbWidth = ovUI->getFBWidth();
251 const int fbHeight = ovUI->getFBHeight();
252 ovUI->setPosition(0, 0, fbWidth, fbHeight);
253 if(ovUI->commit() != overlay::NO_ERROR) {
254 LOGE("%s: Overlay Commit failed", __func__);
255 return -1;
256 }
257 }
258 LOGE_IF(EXTDEBUG, "%s", __func__);
259#endif
260 return overlay::NO_ERROR;
261}
262
263inline void ExtDispOnly::startDefaultMirror(hwc_context_t* ctx) {
264#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
265 hwc_composer_device_t* dev = (hwc_composer_device_t*) ctx;
266 private_hwc_module_t* hwcModule =
267 reinterpret_cast<private_hwc_module_t*>(dev->common.module);
268 framebuffer_device_t *fbDev = hwcModule->fbDevice;
269 if (fbDev) {
270 //mHDMIEnabled could be HDMI/WFD/NO EXTERNAL
271 fbDev->enableHDMIOutput(fbDev, ctx->mHDMIEnabled);
272 }
273#endif
274}
275
276inline void ExtDispOnly::stopDefaultMirror(hwc_context_t* ctx) {
277#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
278 hwc_composer_device_t* dev = (hwc_composer_device_t*) ctx;
279 private_hwc_module_t* hwcModule =
280 reinterpret_cast<private_hwc_module_t*>(dev->common.module);
281 framebuffer_device_t *fbDev = hwcModule->fbDevice;
282 if (fbDev) {
283 fbDev->enableHDMIOutput(fbDev, EXT_DISPLAY_OFF);
284 }
285#endif
286}
287
288inline bool ExtDispOnly::isExtModeStarting(hwc_context_t* ctx, const int&
289 numExtLayers) {
290#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
291 return ((sExtOnlyMode == EXT_ONLY_MODE_OFF) && numExtLayers);
292#endif
293 return false;
294}
295
296inline bool ExtDispOnly::isExtModeStopping(hwc_context_t* ctx, const int&
297 numExtLayers) {
298#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
299 return ((sExtOnlyMode == EXT_ONLY_MODE_ON) && (numExtLayers == 0));
300#endif
301 return false;
302}
303
304inline bool ExtDispOnly::isModeOn() {
305#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
306 return (sExtOnlyMode == EXT_ONLY_MODE_ON);
307#endif
308 return false;
309}
310
311int ExtDispOnly::update(hwc_context_t* ctx, hwc_layer_list_t* list) {
312#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
313 int aNumExtLayers = 0;
314 bool aSkipLayerPresent = false;
315 bool aBlockLayerPresent = false;
316 int aBlockLayerIndex = -1;
317
318 //Book-keeping done each cycle
319 for (size_t i = 0; i < list->numHwLayers; i++) {
320 private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
321 // Dont draw in this round
322 if(list->hwLayers[i].flags & HWC_SKIP_LAYER) {
323 aSkipLayerPresent = true;
324 }
325 if(hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY)) {
326 aNumExtLayers++;
327 // No way we can let this be drawn by GPU to fb0
328 if(list->hwLayers[i].flags & HWC_SKIP_LAYER) {
329 list->hwLayers[i].flags &= ~ HWC_SKIP_LAYER;
330 }
331 list->hwLayers[i].flags |= HWC_USE_EXT_ONLY;
332 list->hwLayers[i].compositionType = HWC_USE_OVERLAY;
333 list->hwLayers[i].hints &= ~HWC_HINT_CLEAR_FB;
334 //EXTERNAL_BLOCK is always an add-on
335 if(hnd && (hnd->flags &
336 private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK)) {
337 aBlockLayerPresent = true;
338 aBlockLayerIndex = i;
339 list->hwLayers[i].flags |= HWC_USE_EXT_BLOCK;
340 }
341 }
342 }
343
344 //Update Default mirroring state
345 if (isExtModeStarting(ctx, aNumExtLayers)) {
346 stopDefaultMirror(ctx);
347 } else if (isExtModeStopping(ctx, aNumExtLayers)) {
348 startDefaultMirror(ctx);
349 }
350
351 //Cache our stats
352 sExtOnlyMode = aNumExtLayers ? EXT_ONLY_MODE_ON : EXT_ONLY_MODE_OFF;
353 sNumExtOnlyLayers = aNumExtLayers;
354 sSkipLayerPresent = aSkipLayerPresent;
355 sBlockLayerPresent = aBlockLayerPresent;
356 sBlockLayerIndex = aBlockLayerIndex;
357
358 LOGE_IF(EXTDEBUG, "%s: numExtLayers = %d skipLayerPresent = %d", __func__,
359 aNumExtLayers, aSkipLayerPresent);
360 //If skip layer present return. Buffers to be unlocked in draw phase.
361 if(aSkipLayerPresent) {
362 return overlay::NO_ERROR;
363 }
364
365 //If External is not connected, dont setup pipes, just return
366 if(ctx->mHDMIEnabled == EXT_DISPLAY_OFF ||
367 ctx->pendingHDMI == true) {
368 ExtDispOnly::close();
369 return -1;
370 }
371
372
373 //Update pipes
374 bool waitForVsync = true;
375 bool index = 0;
376
377 if (aBlockLayerPresent) {
378 ExtDispOnly::closeRange(1);
379 ExtDispOnly::prepare(ctx, &(list->hwLayers[aBlockLayerIndex]),
380 index, waitForVsync);
381 } else if (aNumExtLayers) {
382 ExtDispOnly::closeRange(aNumExtLayers);
383 for (size_t i = 0; i < list->numHwLayers; i++) {
384 private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
385 if(hnd && hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY) {
386 waitForVsync = (index == (aNumExtLayers - 1));
387 ExtDispOnly::prepare(ctx, &(list->hwLayers[i]),
388 index, waitForVsync);
389 index++;
390 }
391 }
392 } else {
393 ExtDispOnly::close();
394 }
395#endif
396 return overlay::NO_ERROR;
397}
398
399void ExtDispOnly::storeLockedHandles(hwc_layer_list_t* list) {
400#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
401 int index = 0;
402 if(sBlockLayerPresent) {
403 private_handle_t *hnd = (private_handle_t *)
404 list->hwLayers[sBlockLayerIndex].handle;
405 if(list->hwLayers[sBlockLayerIndex].flags & HWC_USE_EXT_ONLY) {
406 if(!(hnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK)) {
407 ExtDispOnly::lockBuffer(hnd);
408 }
409 sPreviousExtHandle[index] = hnd;
410 LOGE_IF(EXTDEBUG, "%s BLOCK: handle = %p", __func__, hnd);
411 return;
412 }
413 }
414 for(int i = 0; i < list->numHwLayers; i++) {
415 private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
416 if(list->hwLayers[i].flags & HWC_USE_EXT_ONLY) {
417 if(!(hnd->flags & private_handle_t::PRIV_FLAGS_HWC_LOCK)) {
418 ExtDispOnly::lockBuffer(hnd);
419 }
420 sPreviousExtHandle[index] = hnd;
421 index++;
422 LOGE_IF(EXTDEBUG, "%s: handle = %p", __func__, hnd);
423 }
424 }
425#endif
426}
427
428int ExtDispOnly::draw(hwc_context_t *ctx, hwc_layer_list_t *list) {
429#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
430 LOGE_IF(EXTDEBUG, "%s", __func__);
431 if(ctx->mHDMIEnabled == EXT_DISPLAY_OFF ||
432 ctx->pendingHDMI == true) {
433 ExtDispOnly::close();
434 return -1;
435 }
436
437 int ret = overlay::NO_ERROR;
438 int index = 0;
439
440 //If skip layer present or list invalid unlock and return.
441 if(sSkipLayerPresent || list == NULL) {
442 ExtDispOnly::unlockPreviousBuffers();
443 return overlay::NO_ERROR;
444 }
445
446 if(sBlockLayerPresent) {
447 private_handle_t *hnd = (private_handle_t*)
448 list->hwLayers[sBlockLayerIndex].handle;
449 ExtDispOnly::lockBuffer(hnd);
450 ret = sOvExtUI[index]->queueBuffer(hnd);
451 if (ret) {
452 LOGE("%s queueBuffer failed", __func__);
453 // Unlock the locked buffer
454 ExtDispOnly::unlockBuffer(hnd);
455 ExtDispOnly::close();
456 return -1;
457 }
458 ExtDispOnly::unlockPreviousBuffers();
459 ExtDispOnly::storeLockedHandles(list);
460 return overlay::NO_ERROR;
461 }
462
463 for(int i = 0; i < list->numHwLayers; i++) {
464 private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
465 if(hnd && list->hwLayers[i].flags & HWC_USE_EXT_ONLY) {
466 overlay::OverlayUI *ovUI = sOvExtUI[index];
467 ExtDispOnly::lockBuffer(hnd);
468 ret = ovUI->queueBuffer(hnd);
469 if (ret) {
470 LOGE("%s queueBuffer failed", __func__);
471 // Unlock the all the currently locked buffers
472 for (int j = 0; j <= i; j++) {
473 private_handle_t *tmphnd =
474 (private_handle_t *)list->hwLayers[j].handle;
475 if(hnd && list->hwLayers[j].flags & HWC_USE_EXT_ONLY)
476 ExtDispOnly::unlockBuffer(tmphnd);
477 }
478 ExtDispOnly::close();
479 return -1;
480 }
481 index++;
482 }
483 }
484 ExtDispOnly::unlockPreviousBuffers();
485 ExtDispOnly::storeLockedHandles(list);
486#endif
487 return overlay::NO_ERROR;
488}
489
490#if defined (HDMI_DUAL_DISPLAY) && defined (USE_OVERLAY)
491overlay::OverlayUI* ExtDispOnly::sOvExtUI[MAX_EXT_ONLY_LAYERS];
492native_handle_t* ExtDispOnly::sPreviousExtHandle[MAX_EXT_ONLY_LAYERS];
493ExtDispOnly::ExternalOnlyMode ExtDispOnly::sExtOnlyMode;
494int ExtDispOnly::sNumExtOnlyLayers;
495bool ExtDispOnly::sSkipLayerPresent;
496bool ExtDispOnly::sBlockLayerPresent;
497int ExtDispOnly::sBlockLayerIndex;
498#endif