summaryrefslogtreecommitdiff
path: root/hwc1.4/hwcomposer.cpp (plain)
blob: 8f5075468c1fffa43e73a6da395e6d856d3c4c46
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "HWComposer"
19#include <hardware/hardware.h>
20
21#include <fcntl.h>
22#include <math.h>
23#include <poll.h>
24#include <pthread.h>
25#include <stdio.h>
26#include <stdlib.h>
27
28#include <sys/ioctl.h>
29#include <sys/mman.h>
30#include <sys/time.h>
31#include <sys/types.h>
32#include <errno.h>
33#include <sys/resource.h>
34
35#include <EGL/egl.h>
36
37#define HWC_REMOVE_DEPRECATED_VERSIONS 1
38
39#include <cutils/compiler.h>
40#include <cutils/log.h>
41#include <cutils/atomic.h>
42#include <cutils/properties.h>
43
44#include <utils/String8.h>
45#include <hardware/gralloc.h>
46#include <hardware/hwcomposer.h>
47#include <hardware_legacy/uevent.h>
48#include <utils/String8.h>
49
50#include <EGL/egl.h>
51#include <utils/Vector.h>
52#include <utils/Timers.h>
53#include <system/graphics.h>
54#include <sync/sync.h>
55// for private_handle_t
56#include <gralloc_priv.h>
57#include <gralloc_helper.h>
58
59#if WITH_LIBPLAYER_MODULE
60#include <Amavutils.h>
61#endif
62#include "../tvp/OmxUtil.h"
63
64#ifndef LOGD
65#define LOGD ALOGD
66#endif
67
68///Defines for debug statements - Macro LOG_TAG needs to be defined in the respective files
69#define HWC_LOGVA(str) ALOGV_IF(chk_int_prop("sys.hwc.debuglevel") >=6,"%5d %s - " str, __LINE__,__FUNCTION__);
70#define HWC_LOGVB(str,...) ALOGV_IF(chk_int_prop("sys.hwc.debuglevel") >=6,"%5d %s - " str, __LINE__, __FUNCTION__, __VA_ARGS__);
71#define HWC_LOGDA(str) ALOGD_IF(chk_int_prop("sys.hwc.debuglevel") >=5,"%5d %s - " str, __LINE__,__FUNCTION__);
72#define HWC_LOGDB(str, ...) ALOGD_IF(chk_int_prop("sys.hwc.debuglevel") >=5,"%5d %s - " str, __LINE__, __FUNCTION__, __VA_ARGS__);
73#define HWC_LOGIA(str) ALOGI_IF(chk_int_prop("sys.hwc.debuglevel") >=4,"%5d %s - " str, __LINE__, __FUNCTION__);
74#define HWC_LOGIB(str, ...) ALOGI_IF(chk_int_prop("sys.hwc.debuglevel") >=4,"%5d %s - " str, __LINE__,__FUNCTION__, __VA_ARGS__);
75#define HWC_LOGWA(str) ALOGW_IF(chk_int_prop("sys.hwc.debuglevel") >=3,"%5d %s - " str, __LINE__, __FUNCTION__);
76#define HWC_LOGWB(str, ...) ALOGW_IF(chk_int_prop("sys.hwc.debuglevel") >=3,"%5d %s - " str, __LINE__,__FUNCTION__, __VA_ARGS__);
77#define HWC_LOGEA(str) ALOGE_IF(chk_int_prop("sys.hwc.debuglevel") >=2,"%5d %s - " str, __LINE__, __FUNCTION__);
78#define HWC_LOGEB(str, ...) ALOGE_IF(chk_int_prop("sys.hwc.debuglevel") >=2,"%5d %s - " str, __LINE__,__FUNCTION__, __VA_ARGS__);
79
80#define LOG_FUNCTION_NAME HWC_LOGVA("ENTER");
81#define LOG_FUNCTION_NAME_EXIT HWC_LOGVA("EXIT");
82#define DBG_LOGA(str) ALOGI_IF(chk_int_prop("sys.hwc.debuglevel") >=4,"%10s-%5d %s - " str, HWC_BUILD_NAME, __LINE__,__FUNCTION__)
83#define DBG_LOGB(str, ...) ALOGI_IF(chk_int_prop("sys.hwc.debuglevel") >=4,"%10s-%5d %s - " str, HWC_BUILD_NAME, __LINE__,__FUNCTION__, __VA_ARGS__);
84
85#define SYSFS_AMVIDEO_CURIDX "/sys/module/amvideo/parameters/cur_dev_idx"
86#define SYSFS_DISPLAY_MODE "/sys/class/display/mode"
87#define SYSFS_FB0_FREE_SCALE "/sys/class/graphics/fb0/free_scale"
88#define SYSFS_FB1_FREE_SCALE "/sys/class/graphics/fb0/free_scale"
89#define SYSFS_VIDEO_AXIS "/sys/class/video/axis"
90#define SYSFS_VIDEOBUFUSED "/sys/class/amstream/videobufused"
91#define SYSFS_WINDOW_AXIS "/sys/class/graphics/fb0/window_axis"
92
93#define MAX_SUPPORT_DISPLAYS HWC_NUM_PHYSICAL_DISPLAY_TYPES
94
95#ifdef SINGLE_EXTERNAL_DISPLAY_USE_FB1
96#undef ENABLE_CURSOR_LAYER
97#define CHK_SKIP_DISPLAY_FB0(dispIdx) \
98 if (pdev->display_ctxs[HWC_DISPLAY_EXTERNAL].connected\
99 && dispIdx == HWC_DISPLAY_PRIMARY) {\
100 continue;\
101 }
102#else
103#define ENABLE_CURSOR_LAYER 1//cursor layer supported in hwc 1.4
104#define CHK_SKIP_DISPLAY_FB0(dispIdx) //nothing to do
105#endif
106
107#define get_display_info(ctx,disp) \
108 display_context_t * display_ctx = &(ctx->display_ctxs[disp]);\
109 framebuffer_info_t* fbinfo = &(display_ctx->fb_info);
110
111typedef struct cursor_context_t{
112 bool blank;
113 struct framebuffer_info_t cb_info;
114 void *cbuffer;
115 bool show;
116}cursor_context_t;
117
118typedef struct display_context_t{
119 bool connected;
120 struct framebuffer_info_t fb_info;
121 struct private_handle_t* fb_hnd;
122#ifdef ENABLE_CURSOR_LAYER
123 struct cursor_context_t cursor_ctx;
124#endif
125}display_context_t;
126
127struct hwc_context_1_t {
128 hwc_composer_device_1_t base;
129
130 /* our private state goes below here */
131 hwc_layer_1_t const* saved_layer;
132 unsigned saved_transform;
133 int saved_left;
134 int saved_top;
135 int saved_right;
136 int saved_bottom;
137
138 //vsync.
139 int32_t vsync_period;
140 int vsync_enable;
141 pthread_t vsync_thread;
142
143 bool blank_status;
144
145 //video buf is used flag
146 char video_buf_used[32];
147 //hdmi output mode
148 char mode[32];
149
150 const hwc_procs_t *procs;
151 pthread_t hotplug_thread;
152
153 private_module_t *gralloc_module;
154 display_context_t display_ctxs[MAX_SUPPORT_DISPLAYS];
155};
156
157typedef struct hwc_uevent_data {
158 int len;
159 char buf[1024];
160 char name[128];
161 char state[128];
162} hwc_uevent_data_t;
163
164static pthread_cond_t hwc_cond = PTHREAD_COND_INITIALIZER;
165static pthread_mutex_t hwc_mutex = PTHREAD_MUTEX_INITIALIZER;
166
167extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
168 const struct timespec *request, struct timespec *remain);
169int init_display(hwc_context_1_t* context,int displayType);
170int uninit_display(hwc_context_1_t* context,int displayType);
171
172static bool chk_bool_prop(const char* prop) {
173 char val[PROPERTY_VALUE_MAX];
174
175 memset(val, 0, sizeof(val));
176 if (property_get(prop, val, "false") && strcmp(val, "true") == 0) {
177 ALOGD("prop: %s is %s",prop, val);
178 return true;
179 }
180
181 return false;
182}
183
184static int chk_int_prop(const char* prop) {
185 char val[PROPERTY_VALUE_MAX];
186
187 memset(val, 0, sizeof(val));
188 if (property_get(prop, val, "2")) {
189 //ALOGV("prop: %s is %s",prop, val);
190 return atoi(val);
191 }
192 return 0;
193}
194
195static int chk_and_dup(int fence) {
196 if (fence < 0) {
197 HWC_LOGWB("not a vliad fence %d",fence);
198 return -1;
199 }
200
201 int dup_fence = dup(fence);
202 if (dup_fence < 0) {
203 HWC_LOGWB("fence dup failed: %s", strerror(errno));
204 }
205
206 return dup_fence;
207}
208
209#if WITH_LIBPLAYER_MODULE
210static bool chk_sysfs_status(const char* sysfstr, char* lastr, int size) {
211 char val[32];
212 char *p = lastr;
213
214 memset(val, 0, sizeof(val));
215 if (amsysfs_get_sysfs_str(sysfstr, val, sizeof(val)) == 0) {
216 HWC_LOGVB("val: %s, lastr: %s",val, p);
217 if ((strcmp(val, p) != 0)) {
218 memset(p, 0, size);
219 strcpy(p, val);
220 return true;
221 }
222 }
223
224 return false;
225}
226#endif
227
228static int32_t chk_output_mode(char* curmode) {
229 int modefd = open(SYSFS_DISPLAY_MODE, O_RDONLY);
230 if (modefd < 0) {
231 HWC_LOGEB("open (%s) fail", SYSFS_DISPLAY_MODE);
232 return -1;
233 }
234
235 char outputmode[32] = {0};
236 read(modefd, outputmode, 31);
237 close(modefd);
238 modefd = -1;
239
240 //check if need update vsync.
241 if (strcmp(outputmode, curmode) == 0) {
242 HWC_LOGVB("outputmode didn't change %s", curmode);
243 return 0;
244 }
245
246 strcpy(curmode, outputmode);
247
248 int32_t period = 16666666;
249 if (strstr(outputmode, "50hz") != NULL) {
250 period = (int32_t)(1e9 / 50);
251 } else if (strstr(outputmode, "30hz") != NULL) {
252 period = (int32_t)(1e9 / 30);
253 } else if (strstr(outputmode, "25hz") != NULL) {
254 period = (int32_t)(1e9 / 25);
255 } else if ((strstr(outputmode, "24hz") != NULL) || (strstr(outputmode, "smpte") != NULL)) {
256 period = (int32_t)(1e9 / 24);
257 } else
258 HWC_LOGDB("displaymode (%s) doesn't specify HZ", curmode);
259
260 HWC_LOGVB("get new outputmode (%s) new period (%ld)", curmode, period);
261 return period;
262}
263
264static bool chk_vinfo(hwc_context_1_t* ctx, int disp) {
265 get_display_info(ctx, disp);
266 if (fbinfo != NULL && fbinfo->fd >= 0) {
267 struct fb_var_screeninfo vinfo;
268 if (ioctl(fbinfo->fd, FBIOGET_VSCREENINFO, &vinfo) == -1)
269 {
270 ALOGE("FBIOGET_VSCREENINFO error!!!");
271 return -errno;
272 }
273
274 if (vinfo.xres != fbinfo->info.xres
275 || vinfo.yres != fbinfo->info.yres
276 || vinfo.width != fbinfo->info.width
277 || vinfo.height != fbinfo->info.height) {
278 if (int(vinfo.width) <= 16 || int(vinfo.height) <= 9) {
279 // the driver doesn't return that information
280 // default to 160 dpi
281 vinfo.width = ((vinfo.xres * 25.4f)/160.0f + 0.5f);
282 vinfo.height = ((vinfo.yres * 25.4f)/160.0f + 0.5f);
283 }
284 fbinfo->xdpi = (vinfo.xres * 25.4f) / vinfo.width;
285 fbinfo->ydpi = (vinfo.yres * 25.4f) / vinfo.height;
286
287 fbinfo->info.xres = vinfo.xres;
288 fbinfo->info.yres = vinfo.yres;
289 fbinfo->info.width = vinfo.width;
290 fbinfo->info.height = vinfo.height;
291
292 return true;
293 }
294 }
295 return false;
296}
297
298static int hwc_device_open(const struct hw_module_t* module, const char* name,
299 struct hw_device_t** device);
300
301static struct hw_module_methods_t hwc_module_methods = {
302 open: hwc_device_open
303};
304
305hwc_module_t HAL_MODULE_INFO_SYM = {
306 common: {
307 tag: HARDWARE_MODULE_TAG,
308 version_major: 1,
309 version_minor: 0,
310 id: HWC_HARDWARE_MODULE_ID,
311 name: "hwcomposer module",
312 author: "Amlogic",
313 methods: &hwc_module_methods,
314 dso : NULL,
315 reserved : {0},
316 }
317 };
318
319#if 0
320static void dump_handle(private_handle_t *h) {
321 //ALOGV("\t\tformat = %d, width = %u, height = %u, stride = %u, vstride = %u",
322 // h->format, h->width, h->height, h->stride, h->vstride);
323}
324
325static void dump_layer(hwc_layer_1_t const *l) {
326 HWC_LOGVB("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, "
327 "{%d,%d,%d,%d}, {%d,%d,%d,%d}",
328 l->compositionType, l->flags, l->handle, l->transform,
329 l->blending,
330 l->sourceCrop.left,
331 l->sourceCrop.top,
332 l->sourceCrop.right,
333 l->sourceCrop.bottom,
334 l->displayFrame.left,
335 l->displayFrame.top,
336 l->displayFrame.right,
337 l->displayFrame.bottom);
338
339 if (l->handle && !(l->flags & HWC_SKIP_LAYER)) dump_handle(private_handle_t::dynamicCast(l->handle));
340}
341#endif
342
343static void hwc_overlay_compose(hwc_context_1_t *dev, hwc_layer_1_t const* l) {
344 int angle;
345 struct hwc_context_1_t* ctx = (struct hwc_context_1_t*)dev;
346
347#if WITH_LIBPLAYER_MODULE
348 static char last_val[32] = "0";
349 static char last_axis[32] = "0";
350 static char last_mode[32] = {0};
351 static char last_free_scale[32] = {0};
352 static char last_window_axis[50] = {0};
353 bool vpp_changed = false;
354 bool axis_changed = false;
355 bool mode_changed = false;
356 bool free_scale_changed = false;
357 bool window_axis_changed =false;
358
359 if (chk_bool_prop("ro.vout.dualdisplay4")) {
360 vpp_changed = chk_sysfs_status(SYSFS_AMVIDEO_CURIDX, last_val, 32);
361 }
362
363 mode_changed = chk_sysfs_status(SYSFS_DISPLAY_MODE, last_mode, 32);
364
365 free_scale_changed = chk_sysfs_status(SYSFS_FB0_FREE_SCALE, last_free_scale, 32);
366#ifdef SINGLE_EXTERNAL_DISPLAY_USE_FB1
367 if (ctx->display_ctxs[HWC_DISPLAY_EXTERNAL].connected)
368 free_scale_changed = chk_sysfs_status(SYSFS_FB1_FREE_SCALE, last_free_scale, 32);
369#endif
370
371 axis_changed = chk_sysfs_status(SYSFS_VIDEO_AXIS, last_axis, 32);
372 window_axis_changed = chk_sysfs_status(SYSFS_WINDOW_AXIS, last_window_axis, 50);
373
374 if ((ctx->saved_layer == l) &&
375 (ctx->saved_transform == l->transform) &&
376 (ctx->saved_left == l->displayFrame.left) &&
377 (ctx->saved_top == l->displayFrame.top) &&
378 (ctx->saved_right == l->displayFrame.right) &&
379 (ctx->saved_bottom == l->displayFrame.bottom) &&
380 !vpp_changed && !mode_changed && !axis_changed && !free_scale_changed && !window_axis_changed) {
381 return;
382 }
383
384 switch (l->transform) {
385 case 0:
386 angle = 0;
387 break;
388 case HAL_TRANSFORM_ROT_90:
389 angle = 90;
390 break;
391 case HAL_TRANSFORM_ROT_180:
392 angle = 180;
393 break;
394 case HAL_TRANSFORM_ROT_270:
395 angle = 270;
396 break;
397 default:
398 return;
399 }
400
401 amvideo_utils_set_virtual_position(l->displayFrame.left,
402 l->displayFrame.top,
403 l->displayFrame.right - l->displayFrame.left,
404 l->displayFrame.bottom - l->displayFrame.top,
405 angle);
406
407 /* the screen mode from Android framework should always be set to normal mode
408 * to match the relationship between the UI and video overlay window position.
409 */
410 /*set screen_mode in amvideo_utils_set_virtual_position(),pls check in libplayer*/
411 //amvideo_utils_set_screen_mode(0);
412#endif
413
414 ctx->saved_layer = l;
415 ctx->saved_transform = l->transform;
416 ctx->saved_left = l->displayFrame.left;
417 ctx->saved_top = l->displayFrame.top;
418 ctx->saved_right = l->displayFrame.right;
419 ctx->saved_bottom = l->displayFrame.bottom;
420
421#if WITH_LIBPLAYER_MODULE
422 memset(last_axis, 0, sizeof(last_axis));
423
424 if (amsysfs_get_sysfs_str(SYSFS_VIDEO_AXIS, last_axis, sizeof(last_axis)) == 0) {
425 HWC_LOGDB("****last video axis is: %s",last_axis);
426 }
427#endif
428}
429
430static void hwc_dump(hwc_composer_device_1* dev, char *buff, int buff_len) {
431 if (buff_len <= 0) return;
432
433 struct hwc_context_1_t *pdev = (struct hwc_context_1_t *)dev;
434
435 android::String8 result;
436
437 for (int i = 0; i < MAX_SUPPORT_DISPLAYS; i++) {
438 get_display_info(pdev,i);
439
440 if (display_ctx->connected) {
441 result.appendFormat(" %8s Display connected: %3s\n",
442 HWC_DISPLAY_EXTERNAL == i ? "External":"Primiary", display_ctx->connected ? "Yes" : "No");
443 result.appendFormat(" w=%u, h=%u, xdpi=%f, ydpi=%f, osdIdx=%d, vsync_period=%d, video_buf_used: %s\n",
444 fbinfo->info.xres,
445 fbinfo->info.yres,
446 fbinfo->xdpi,
447 fbinfo->ydpi,
448 fbinfo->fbIdx,
449 pdev->vsync_period,
450 pdev->video_buf_used);
451 }
452 }
453
454 //result.append(
455 // " type | handle | color | blend | format | position | size | gsc \n"
456 // "----------+----------|----------+-------+--------+---------------+---------------------\n");
457 // 8_______ | 8_______ | 8_______ | 5____ | 6_____ | [5____,5____] | [5____,5____] | 3__ \n"
458
459 result.append("\n");
460
461 strlcpy(buff, result.string(), buff_len);
462}
463
464static int hwc_blank(struct hwc_composer_device_1 *dev, int disp, int blank) {
465 struct hwc_context_1_t *pdev = (struct hwc_context_1_t *)dev;
466
467 //TODO: need impl
468 if (disp == HWC_DISPLAY_PRIMARY) pdev->blank_status = ( blank ? true : false);
469
470 return 0;
471}
472
473static int hwc_setPowerMode(struct hwc_composer_device_1*, int, int) {
474 LOG_FUNCTION_NAME
475 //TODO:
476 LOG_FUNCTION_NAME_EXIT
477 return 0;
478}
479
480static int hwc_query(struct hwc_composer_device_1* dev, int what, int *value) {
481 LOG_FUNCTION_NAME
482
483 struct hwc_context_1_t *pdev = (struct hwc_context_1_t *)dev;
484
485 switch (what) {
486 case HWC_BACKGROUND_LAYER_SUPPORTED:
487 // we support the background layer
488 value[0] = 1;
489 break;
490 case HWC_VSYNC_PERIOD:
491 // vsync period in nanosecond
492 value[0] = pdev->vsync_period;
493 break;
494 default:
495 // unsupported query
496 return -EINVAL;
497 }
498
499 LOG_FUNCTION_NAME_EXIT
500 return 0;
501}
502
503static int hwc_eventControl(struct hwc_composer_device_1* dev,
504 int,
505 int event,
506 int enabled) {
507 struct hwc_context_1_t* ctx = (struct hwc_context_1_t *)dev;
508
509 switch (event)
510 {
511 case HWC_EVENT_VSYNC:
512 ctx->vsync_enable = enabled;
513 pthread_mutex_lock(&hwc_mutex);
514 pthread_cond_signal(&hwc_cond);
515 pthread_mutex_unlock(&hwc_mutex);
516 return 0;
517 }
518 return -EINVAL;
519}
520
521static int hwc_prepare(struct hwc_composer_device_1 *dev,
522 size_t numDisplays,
523 hwc_display_contents_1_t** displays) {
524 int err = 0;
525 size_t i = 0;
526 hwc_context_1_t *pdev = (hwc_context_1_t *)dev;
527 hwc_display_contents_1_t *display_content = NULL;
528
529 if (!numDisplays || !displays) return 0;
530
531 LOG_FUNCTION_NAME
532 //retireFenceFd will close in surfaceflinger, just reset it.
533 for (i = 0; i < numDisplays; i++) {
534 CHK_SKIP_DISPLAY_FB0();
535
536 display_content = displays[i];
537 if ( display_content ) {
538 display_content->retireFenceFd = -1;
539 for (size_t j=0 ; j< display_content->numHwLayers ; j++) {
540 hwc_layer_1_t* l = &display_content->hwLayers[j];
541
542#ifdef ENABLE_CURSOR_LAYER
543 if (l->flags & HWC_IS_CURSOR_LAYER) {
544 if (i == HWC_DISPLAY_PRIMARY) {
545 l->hints = HWC_HINT_CLEAR_FB;
546 HWC_LOGDA("This is a Cursor layer");
547 l->compositionType = HWC_CURSOR_OVERLAY;
548 continue;
549 } else {
550 HWC_LOGDA("This is not a primary display's Cursor layer, need to set composition type to gles");
551 // l->compositionType = HWC_FRAMEBUFFER;
552 }
553 }
554#endif
555
556 if (i == HWC_DISPLAY_PRIMARY && l->compositionType == HWC_SIDEBAND && l->sidebandStream) {
557 //TODO: we just transact SIDEBAND to OVERLAY now;
558 HWC_LOGVA("get HWC_SIDEBAND layer, just change to overlay");
559 l->hints = HWC_HINT_CLEAR_FB;
560 l->compositionType = HWC_OVERLAY;
561 continue;
562 }
563
564 if (i == HWC_DISPLAY_PRIMARY && l->handle) {
565 private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(l->handle);
566 if (hnd->flags & private_handle_t::PRIV_FLAGS_OSD_VIDEO_OMX) {
567 l->hints = HWC_HINT_OSD_VIDEO_OMX;
568 }
569 if (hnd->flags & private_handle_t::PRIV_FLAGS_VIDEO_OVERLAY) {
570 l->hints = HWC_HINT_CLEAR_FB;
571 l->compositionType = HWC_OVERLAY;
572 continue;
573 }
574 }
575 }
576 }
577 }
578
579 LOG_FUNCTION_NAME_EXIT
580 return 0;
581}
582
583static int fb_post(hwc_context_1_t *pdev,
584 hwc_display_contents_1_t* contents, int display_type) {
585 int err = 0;
586 size_t i = 0;
587
588#ifdef ENABLE_CURSOR_LAYER
589 cursor_context_t * cursor_ctx = &(pdev->display_ctxs[HWC_DISPLAY_PRIMARY].cursor_ctx);
590 framebuffer_info_t* cbinfo = &(cursor_ctx->cb_info);
591 bool cursor_show = false;
592#endif
593
594 for (i = 0; i < contents->numHwLayers; i++) {
595#ifdef ENABLE_CURSOR_LAYER
596 //deal cursor layer
597 if (display_type == HWC_DISPLAY_PRIMARY && contents->hwLayers[i].flags & HWC_IS_CURSOR_LAYER) {
598 hwc_layer_1_t *layer = &(contents->hwLayers[i]);
599 if (private_handle_t::validate(layer->handle) < 0) break;
600 private_handle_t *hnd = (private_handle_t *)layer->handle;
601
602 HWC_LOGDB("This is a Sprite, hnd->stride is %d, hnd->height is %d", hnd->stride, hnd->height);
603 if (cbinfo->info.xres != (unsigned int)hnd->stride || cbinfo->info.yres != (unsigned int)hnd->height) {
604 HWC_LOGDB("disp: %d cursor need to redrew", display_type);
605 update_cursor_buffer_locked(cbinfo, hnd->stride, hnd->height);
606 cursor_ctx->cbuffer = mmap(NULL, hnd->size, PROT_READ|PROT_WRITE, MAP_SHARED, cbinfo->fd, 0);
607 if (cursor_ctx->cbuffer != MAP_FAILED) {
608 memcpy(cursor_ctx->cbuffer, hnd->base, hnd->size);
609 munmap(cursor_ctx->cbuffer, hnd->size);
610 HWC_LOGDA("setCursor ok");
611 } else {
612 HWC_LOGEA("buffer mmap fail");
613 }
614 }
615 cursor_show = true;
616 }
617#endif
618
619 //deal framebuffer target layer
620 if (contents->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) {
621 hwc_layer_1_t *layer = &(contents->hwLayers[i]);
622 if (private_handle_t::validate(layer->handle) < 0) break;
623
624 //deal with virtural display fence
625 if (display_type == HWC_DISPLAY_VIRTUAL) {
626 layer->releaseFenceFd = layer->acquireFenceFd;
627 contents->retireFenceFd = contents->outbufAcquireFenceFd;
628
629 HWC_LOGVB("HWC_DISPLAY_VIRTUAL Get release fence %d, retire fence %d, outbufAcquireFenceFd %d",
630 layer->releaseFenceFd,
631 contents->retireFenceFd, contents->outbufAcquireFenceFd);
632 continue;
633 }
634
635 get_display_info(pdev, display_type);
636 layer->releaseFenceFd = fb_post_with_fence_locked(fbinfo,layer->handle,layer->acquireFenceFd);
637
638 if (layer->releaseFenceFd >= 0) {
639 //layer->releaseFenceFd = releaseFence;
640 contents->retireFenceFd = chk_and_dup(layer->releaseFenceFd);
641
642 HWC_LOGVB("Get release fence %d, retire fence %d",
643 layer->releaseFenceFd,
644 contents->retireFenceFd);
645 } else {
646 HWC_LOGEB("No valid release_fence returned. %d ",layer->releaseFenceFd);
647 //-1 means no fence, less than -1 is some error
648 if (layer->releaseFenceFd < -1) err = layer->releaseFenceFd;
649 contents->retireFenceFd = layer->releaseFenceFd = -1;
650 }
651 }
652 }
653
654#ifdef ENABLE_CURSOR_LAYER
655 //finally we need to update cursor's blank status
656 if (display_type == HWC_DISPLAY_PRIMARY
657 && cbinfo->fd > 0 && (cursor_show != cursor_ctx->show) ) {
658 cursor_ctx->show = cursor_show;
659 HWC_LOGVB("UPDATE FB1 status to %d ",cursor_show);
660 ioctl(cbinfo->fd, FBIOBLANK, !cursor_ctx->show);
661 }
662#endif
663
664 return err;
665}
666
667
668static int hwc_set(struct hwc_composer_device_1 *dev,
669 size_t numDisplays, hwc_display_contents_1_t** displays) {
670 int err = 0;
671 size_t i = 0, j = 0;
672 hwc_context_1_t *pdev = (hwc_context_1_t *)dev;
673 hwc_display_contents_1_t *display_content = NULL;
674
675 if (!numDisplays || !displays) return 0;
676
677 LOG_FUNCTION_NAME
678 //TODO: need improve the way to set video axis.
679#if WITH_LIBPLAYER_MODULE
680 for (i = 0; i < numDisplays; i++) {
681 CHK_SKIP_DISPLAY_FB0();
682 display_content = displays[i];
683 if (display_content) {
684 for (j = 0; j < display_content->numHwLayers; j++) {
685 hwc_layer_1_t* l = &display_content->hwLayers[j];
686 if (l->compositionType == HWC_OVERLAY) {
687 hwc_overlay_compose(pdev, l);
688 }
689 }
690 }
691 }
692
693#endif
694
695 for (i=0;i<numDisplays;i++) {
696 CHK_SKIP_DISPLAY_FB0();
697 display_content = displays[i];
698 if (display_content) {
699 if (i <= HWC_DISPLAY_VIRTUAL) {
700 //physic display
701 err = fb_post(pdev,display_content,i);
702 } else {
703 HWC_LOGEB("display %d is not supported",i);
704 }
705 }
706 }
707
708 LOG_FUNCTION_NAME_EXIT
709 return err;
710}
711
712static int hwc_close(hw_device_t *device) {
713 struct hwc_context_1_t *dev = (struct hwc_context_1_t *)device;
714
715 LOG_FUNCTION_NAME
716
717 pthread_kill(dev->vsync_thread, SIGTERM);
718 pthread_join(dev->vsync_thread, NULL);
719
720 uninit_display(dev,HWC_DISPLAY_PRIMARY);
721 uninit_display(dev,HWC_DISPLAY_EXTERNAL);
722
723 if (dev) free(dev);
724
725 LOG_FUNCTION_NAME_EXIT
726 return 0;
727}
728
729//#define USE_HW_VSYNC
730#ifdef USE_HW_VSYNC
731/*
732Still have bugs, don't use it.
733*/
734int wait_next_vsync(struct hwc_context_1_t* ctx, nsecs_t* vsync_timestamp) {
735 static nsecs_t previewTime = 0;
736 nsecs_t vsyncDiff=0;
737 const nsecs_t period = ctx->vsync_period;
738 //we will delay hw vsync if missing one vsync interrupt isr.
739 int ret = 0;
740
741 if (ioctl(ctx->display_ctxs[0].fb_info.fd, FBIO_WAITFORVSYNC, &ret) == -1) {
742 HWC_LOGEB("ioctrl error %d",ctx->display_ctxs[0].fb_info.fd);
743 ret=-1;
744 } else {
745 if (ret == 1) {
746 *vsync_timestamp = systemTime(CLOCK_MONOTONIC);
747 vsyncDiff=*vsync_timestamp - previewTime;
748 if (previewTime != 0) HWC_LOGEB("wait for vsync success %lld",vsyncDiff);
749 vsyncDiff%=period;
750 if (vsyncDiff > 500000) {
751 nsecs_t sleep ;
752 sleep = (period - vsyncDiff);
753 *vsync_timestamp+=sleep;
754 struct timespec spec;
755 spec.tv_sec = *vsync_timestamp / 1000000000;
756 spec.tv_nsec = *vsync_timestamp % 1000000000;
757 clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);
758 }
759 previewTime = *vsync_timestamp;
760 ret=0;
761 } else {
762 HWC_LOGEA("wait for vsync fail");
763 ret=-1;
764 }
765 }
766 return ret;
767}
768
769#else
770
771//software
772int wait_next_vsync(struct hwc_context_1_t* ctx, nsecs_t* vsync_timestamp) {
773 static nsecs_t vsync_time = 0;
774 static nsecs_t old_vsync_period = 0;
775 nsecs_t sleep;
776 nsecs_t now = systemTime(CLOCK_MONOTONIC);
777
778 //cal the last vsync time with old period
779 if (ctx->vsync_period != old_vsync_period) {
780 if (old_vsync_period > 0) {
781 vsync_time = vsync_time +
782 ((now - vsync_time) / old_vsync_period) * old_vsync_period;
783 }
784 old_vsync_period = ctx->vsync_period;
785 }
786
787 //set to next vsync time
788 vsync_time +=ctx->vsync_period;
789
790 // we missed, find where the next vsync should be
791 if (vsync_time - now < 0) {
792 vsync_time = now + (ctx->vsync_period -
793 ((now - vsync_time) % ctx->vsync_period));
794 }
795
796 struct timespec spec;
797 spec.tv_sec = vsync_time / 1000000000;
798 spec.tv_nsec = vsync_time % 1000000000;
799
800 int err;
801 do {
802 err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);
803 } while (err<0 && errno == EINTR);
804 *vsync_timestamp = vsync_time;
805
806 return err;
807}
808#endif
809
810static void *hwc_vsync_thread(void *data) {
811 struct hwc_context_1_t* ctx = (struct hwc_context_1_t*)data;
812 nsecs_t timestamp;
813
814 setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY-1);
815 sleep(2);
816
817 while (true) {
818 pthread_mutex_lock(&hwc_mutex);
819 while (ctx->vsync_enable == false) {
820 pthread_cond_wait(&hwc_cond, &hwc_mutex);
821 }
822 pthread_mutex_unlock(&hwc_mutex);
823
824 if (wait_next_vsync(ctx,&timestamp) == 0) {
825 if (ctx->procs) ctx->procs->vsync(ctx->procs, 0, timestamp);
826 }
827 }
828
829 return NULL;
830}
831
832//#ifdef WITH_EXTERNAL_DISPLAY
833//#define SIMULATE_HOT_PLUG 1
834#define HDMI_UEVENT "DEVPATH=/devices/virtual/switch/hdmi_audio"
835#define HDMI_POWER_UEVENT "DEVPATH=/devices/virtual/switch/hdmi_power"
836
837static bool isMatch(hwc_uevent_data_t* ueventData, const char* matchName) {
838 bool matched = false;
839 // Consider all zero-delimited fields of the buffer.
840 const char* field = ueventData->buf;
841 const char* end = ueventData->buf + ueventData->len + 1;
842 do {
843 if (strstr(field, matchName)) {
844 HWC_LOGEB("Matched uevent message with pattern: %s", matchName);
845 matched = true;
846 }
847 //SWITCH_STATE=1, SWITCH_NAME=hdmi
848 else if (strstr(field, "SWITCH_STATE=")) {
849 strcpy(ueventData->state, field + strlen("SWITCH_STATE="));
850 }
851 else if (strstr(field, "SWITCH_NAME=")) {
852 strcpy(ueventData->name, field + strlen("SWITCH_NAME="));
853 }
854 field += strlen(field) + 1;
855 } while (field != end);
856
857 return matched;
858}
859
860static bool chk_external_conect() {
861#ifdef SIMULATE_HOT_PLUG
862 HWC_LOGDA("Simulate hot plug");
863 return chk_bool_prop("debug.connect_external");
864#else
865 //TODO:need to check hotplug callback for different device.
866 //Should consider different device.
867 return chk_bool_prop("sys.sf.hotplug");
868#endif
869}
870
871static void *hwc_hotplug_thread(void *data) {
872 struct hwc_context_1_t* ctx = (struct hwc_context_1_t*)data;
873 bool fpsChanged = false, sizeChanged = false;
874 //use uevent instead of usleep, because it has some delay
875 hwc_uevent_data_t u_data;
876 memset(&u_data, 0, sizeof(hwc_uevent_data_t));
877 int fd = uevent_init();
878
879 while (fd > 0) {
880 if (ctx->procs) {
881 fpsChanged = false;
882 sizeChanged = false;
883 u_data.len= uevent_next_event(u_data.buf, sizeof(u_data.buf) - 1);
884 if (u_data.len <= 0)
885 continue;
886
887 u_data.buf[u_data.len] = '\0';
888#if 0
889 //change@/devices/virtual/switch/hdmi ACTION=change DEVPATH=/devices/virtual/switch/hdmi
890 //SUBSYSTEM=switch SWITCH_NAME=hdmi SWITCH_STATE=0 SEQNUM=2791
891 char printBuf[1024] = {0};
892 memcpy(printBuf, u_data.buf, u_data.len);
893 for (int i = 0; i < u_data.len; i++) {
894 if (printBuf[i] == 0x0)
895 printBuf[i] = ' ';
896 }
897 HWC_LOGEB("Received uevent message: %s", printBuf);
898#endif
899 if (isMatch(&u_data, HDMI_UEVENT)) {
900 //HWC_LOGEB("HDMI switch_state: %s switch_name: %s\n", u_data.state, u_data.name);
901 if ((!strcmp(u_data.name, "hdmi_audio")) &&
902 (!strcmp(u_data.state, "1"))) {
903 // update vsync period if neccessry
904 nsecs_t newperiod = chk_output_mode(ctx->mode);
905 // check if vsync period is changed
906 if (newperiod > 0 && newperiod != ctx->vsync_period) {
907 ctx->vsync_period = newperiod;
908 fpsChanged = true;
909 }
910 sizeChanged = chk_vinfo(ctx, HWC_DISPLAY_PRIMARY);
911 if (fpsChanged || sizeChanged) {
912 ctx->procs->hotplug(ctx->procs, HWC_DISPLAY_PRIMARY, 1);
913 }
914 }
915 }
916 }
917 }
918
919 return NULL;
920}
921//#endif
922
923static void hwc_registerProcs(hwc_composer_device_1 *dev,
924 hwc_procs_t const* procs) {
925 struct hwc_context_1_t* ctx = (struct hwc_context_1_t*)dev;
926
927 if (ctx) ctx->procs = procs;
928}
929
930static int hwc_getDisplayConfigs(hwc_composer_device_1_t *dev,
931 int disp ,uint32_t *config ,size_t *numConfigs) {
932 struct hwc_context_1_t* ctx = (struct hwc_context_1_t*)dev;
933
934 if (*numConfigs == 0) return 0;
935
936 LOG_FUNCTION_NAME
937
938 get_display_info(ctx,disp);
939
940 if (disp == HWC_DISPLAY_PRIMARY) {
941 config[0] = 0;
942 *numConfigs = 1;
943 return 0;
944 } else if (disp == HWC_DISPLAY_EXTERNAL) {
945 HWC_LOGEB("hwc_getDisplayConfigs:connect = %d",display_ctx->connected);
946 if (!display_ctx->connected) return -EINVAL;
947
948 config[0] = 0;
949 *numConfigs = 1;
950 return 0;
951 }
952
953 LOG_FUNCTION_NAME_EXIT
954 return -EINVAL;
955}
956
957static int hwc_getDisplayAttributes(hwc_composer_device_1_t *dev,
958 int disp, uint32_t, const uint32_t *attributes, int32_t *values) {
959 struct hwc_context_1_t* ctx = (struct hwc_context_1_t*)dev;
960
961 LOG_FUNCTION_NAME
962
963 get_display_info(ctx,disp);
964
965 for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
966 switch (attributes[i]) {
967 case HWC_DISPLAY_VSYNC_PERIOD:
968 values[i] = ctx->vsync_period;
969 break;
970 case HWC_DISPLAY_WIDTH:
971 values[i] = fbinfo->info.xres;
972 break;
973 case HWC_DISPLAY_HEIGHT:
974 values[i] = fbinfo->info.yres;
975 break;
976 case HWC_DISPLAY_DPI_X:
977 values[i] = fbinfo->xdpi*1000;
978 break;
979 case HWC_DISPLAY_DPI_Y:
980 values[i] = fbinfo->ydpi*1000;
981 break;
982 default:
983 HWC_LOGEB("unknown display attribute %u", attributes[i]);
984 values[i] = -EINVAL;
985 break;
986 }
987 }
988
989 LOG_FUNCTION_NAME_EXIT
990
991 return 0;
992}
993
994
995static int hwc_getActiveConfig(struct hwc_composer_device_1*, int) {
996 LOG_FUNCTION_NAME
997 //TODO:
998 LOG_FUNCTION_NAME_EXIT
999 return 0;
1000}
1001
1002static int hwc_setActiveConfig(struct hwc_composer_device_1*, int, int) {
1003 LOG_FUNCTION_NAME
1004 //TODO:
1005 LOG_FUNCTION_NAME_EXIT
1006 return 0;
1007}
1008
1009static int hwc_setCursorPositionAsync(struct hwc_composer_device_1 *dev, int disp,
1010 int x_pos, int y_pos) {
1011 LOG_FUNCTION_NAME
1012
1013#ifdef ENABLE_CURSOR_LAYER
1014 if (disp == HWC_DISPLAY_PRIMARY) {
1015 int err = 0, i = 0;
1016 struct fb_cursor cinfo;
1017 struct hwc_context_1_t* ctx = (struct hwc_context_1_t*)dev;
1018 cursor_context_t * cursor_ctx = &(ctx->display_ctxs[disp].cursor_ctx);
1019 framebuffer_info_t* cbinfo = &(cursor_ctx->cb_info);
1020
1021 if (cbinfo->fd < 0) {
1022 HWC_LOGEB("hwc_setCursorPositionAsync fd=%d", cbinfo->fd );
1023 }else {
1024 cinfo.hot.x = x_pos;
1025 cinfo.hot.y = y_pos;
1026 // if (disp == HWC_DISPLAY_PRIMARY) {
1027 HWC_LOGDB("hwc_setCursorPositionAsync x_pos=%d, y_pos=%d", cinfo.hot.x, cinfo.hot.y);
1028 ioctl(cbinfo->fd, FBIO_CURSOR, &cinfo);
1029 /*} else if(disp == HWC_DISPLAY_EXTERNAL) {
1030 // TODO:
1031 HWC_LOGDA("hwc_setCursorPositionAsync external display need show cursor too! ");
1032 //ioctl(cbinfo->fd, FBIO_CURSOR, &cinfo);
1033 }*/
1034 }
1035 } else {
1036 HWC_LOGEA("It is not a primary display should not come in here!");
1037 }
1038#endif
1039
1040 LOG_FUNCTION_NAME_EXIT
1041 return 0;
1042}
1043
1044
1045static int hwc_device_open(const struct hw_module_t* module, const char* name,
1046 struct hw_device_t** device) {
1047 int ret;
1048
1049 if (strcmp(name, HWC_HARDWARE_COMPOSER)) return -EINVAL;
1050
1051 struct hwc_context_1_t *dev;
1052 dev = (struct hwc_context_1_t *)malloc(sizeof(*dev));
1053 memset(dev, 0, sizeof(*dev));
1054
1055 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
1056 (const struct hw_module_t **)&dev->gralloc_module)) {
1057 HWC_LOGEA("failed to get gralloc hw module");
1058 ret = -EINVAL;
1059 goto err_get_module;
1060 }
1061
1062 //init primiary display
1063 //default is alwasy false,will check it in hot plug.
1064 init_display(dev,HWC_DISPLAY_PRIMARY);
1065
1066 // willchanged to use hw vsync.
1067 dev->vsync_period = chk_output_mode(dev->mode);
1068
1069 dev->base.common.tag = HARDWARE_DEVICE_TAG;
1070 dev->base.common.version = HWC_DEVICE_API_VERSION_1_4;
1071 dev->base.common.module = const_cast<hw_module_t *>(module);
1072 dev->base.common.close = hwc_close;
1073
1074 dev->base.prepare = hwc_prepare;
1075 dev->base.set = hwc_set;
1076 dev->base.eventControl = hwc_eventControl;
1077 //++hwc 1.4 abandon api
1078 dev->base.blank = hwc_blank;
1079 //--hwc 1.4 abandon api
1080 dev->base.query = hwc_query;
1081 dev->base.registerProcs = hwc_registerProcs;
1082
1083 dev->base.dump = hwc_dump;
1084 dev->base.getDisplayConfigs = hwc_getDisplayConfigs;
1085 dev->base.getDisplayAttributes = hwc_getDisplayAttributes;
1086 //++hwc 1.4 new apis
1087 dev->base.setPowerMode = hwc_setPowerMode;
1088 dev->base.getActiveConfig = hwc_getActiveConfig;
1089 dev->base.setActiveConfig = hwc_setActiveConfig;
1090 dev->base.setCursorPositionAsync = hwc_setCursorPositionAsync;
1091 //--hwc 1.4 new apis
1092 dev->vsync_enable = false;
1093 dev->blank_status = false;
1094 *device = &dev->base.common;
1095
1096 ret = pthread_create(&dev->vsync_thread, NULL, hwc_vsync_thread, dev);
1097 if (ret) {
1098 HWC_LOGEB("failed to start vsync thread: %s", strerror(ret));
1099 ret = -ret;
1100 goto err_vsync;
1101 }
1102
1103//#ifdef WITH_EXTERNAL_DISPLAY
1104 //temp solution, will change to use uevnet from kernel
1105 ret = pthread_create(&dev->hotplug_thread, NULL, hwc_hotplug_thread, dev);
1106 if (ret) {
1107 HWC_LOGEB("failed to start hotplug thread: %s", strerror(ret));
1108 ret = -ret;
1109 goto err_vsync;
1110 }
1111//#endif
1112
1113 return 0;
1114
1115err_vsync:
1116 uninit_display(dev,HWC_DISPLAY_PRIMARY);
1117err_get_module:
1118 if (dev) free(dev);
1119
1120 return ret;
1121}
1122
1123/*
1124Operater of framebuffer
1125*/
1126int init_display(hwc_context_1_t* context,int displayType) {
1127 get_display_info(context, displayType);
1128
1129 if (display_ctx->connected) return 0;
1130
1131 pthread_mutex_lock(&hwc_mutex);
1132
1133 if ( !display_ctx->fb_hnd ) {
1134 //init information from osd.
1135 fbinfo->displayType = displayType;
1136 fbinfo->fbIdx = getOsdIdx(fbinfo->displayType);
1137 int err = init_frame_buffer_locked(fbinfo);
1138 int bufferSize = fbinfo->finfo.line_length * fbinfo->info.yres;
1139 HWC_LOGDB("init_frame_buffer get fbinfo->fbIdx (%d) fbinfo->info.xres (%d) fbinfo->info.yres (%d)",fbinfo->fbIdx, fbinfo->info.xres,fbinfo->info.yres);
1140 int usage = 0;
1141 if (displayType > 0) usage |= GRALLOC_USAGE_EXTERNAL_DISP;
1142
1143 //Register the framebuffer to gralloc module
1144 display_ctx->fb_hnd = new private_handle_t(private_handle_t::PRIV_FLAGS_FRAMEBUFFER, usage, fbinfo->fbSize, 0,
1145 0, fbinfo->fd, bufferSize, 0);
1146 context->gralloc_module->base.registerBuffer(&(context->gralloc_module->base),display_ctx->fb_hnd);
1147 HWC_LOGDB("init_frame_buffer get frame size %d usage %d",bufferSize,usage);
1148 }
1149
1150 display_ctx->connected = true;
1151 pthread_mutex_unlock(&hwc_mutex);
1152
1153#ifdef ENABLE_CURSOR_LAYER
1154 if (displayType == HWC_DISPLAY_PRIMARY) {
1155 // init cursor framebuffer
1156 cursor_context_t* cursor_ctx = &(display_ctx->cursor_ctx);
1157 cursor_ctx->show = false;
1158 framebuffer_info_t* cbinfo = &(cursor_ctx->cb_info);
1159 cbinfo->fd = -1;
1160
1161 //init information from cursor framebuffer.
1162 cbinfo->fbIdx = displayType*2+1;
1163 if (1 != cbinfo->fbIdx && 3 != cbinfo->fbIdx) {
1164 HWC_LOGEB("invalid fb index: %d, need to check!",cbinfo->fbIdx);
1165 return 0;
1166 }
1167 int err = init_cursor_buffer_locked(cbinfo);
1168 if (err != 0) {
1169 HWC_LOGEA("init_cursor_buffer_locked failed, need to check!");
1170 return 0;
1171 }
1172 HWC_LOGDB("init_cursor_buffer get cbinfo->fbIdx (%d) cbinfo->info.xres (%d) cbinfo->info.yres (%d)",
1173 cbinfo->fbIdx,
1174 cbinfo->info.xres,
1175 cbinfo->info.yres);
1176
1177 if ( cbinfo->fd >= 0) {
1178 HWC_LOGDA("init_cursor_buffer success!");
1179 }else{
1180 HWC_LOGEA("init_cursor_buffer fail!");
1181 }
1182 }
1183#endif
1184
1185
1186 return 0;
1187}
1188
1189int uninit_display(hwc_context_1_t* context, int displayType) {
1190 get_display_info(context, displayType);
1191
1192 if (!display_ctx->connected) {
1193 return 0;
1194 }
1195
1196 pthread_mutex_lock(&hwc_mutex);
1197 display_ctx->connected = false;
1198 pthread_mutex_unlock(&hwc_mutex);
1199
1200 return 0;
1201}
1202
1203