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 | |
111 | typedef 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 | |
118 | typedef 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 | |
127 | struct 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 | |
157 | typedef 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 | |
164 | static pthread_cond_t hwc_cond = PTHREAD_COND_INITIALIZER; |
165 | static pthread_mutex_t hwc_mutex = PTHREAD_MUTEX_INITIALIZER; |
166 | |
167 | extern "C" int clock_nanosleep(clockid_t clock_id, int flags, |
168 | const struct timespec *request, struct timespec *remain); |
169 | int init_display(hwc_context_1_t* context,int displayType); |
170 | int uninit_display(hwc_context_1_t* context,int displayType); |
171 | |
172 | static 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 | |
184 | static 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 | |
195 | static 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 |
210 | static 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 | |
228 | static 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 | |
264 | static 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 | |
298 | static int hwc_device_open(const struct hw_module_t* module, const char* name, |
299 | struct hw_device_t** device); |
300 | |
301 | static struct hw_module_methods_t hwc_module_methods = { |
302 | open: hwc_device_open |
303 | }; |
304 | |
305 | hwc_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 |
320 | static 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 | |
325 | static 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 | |
343 | static 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 | |
430 | static 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 | |
464 | static 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 | |
473 | static 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 | |
480 | static 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 | |
503 | static 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 | |
521 | static 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 | |
583 | static 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 | |
668 | static 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 | |
712 | static 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 | /* |
732 | Still have bugs, don't use it. |
733 | */ |
734 | int 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 |
772 | int 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 | |
810 | static 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,×tamp) == 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 | |
837 | static 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 | |
860 | static 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 | |
871 | static 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 | |
923 | static 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 | |
930 | static 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 | |
957 | static 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 | |
995 | static 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 | |
1002 | static 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 | |
1009 | static 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 | |
1045 | static 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 | |
1115 | err_vsync: |
1116 | uninit_display(dev,HWC_DISPLAY_PRIMARY); |
1117 | err_get_module: |
1118 | if (dev) free(dev); |
1119 | |
1120 | return ret; |
1121 | } |
1122 | |
1123 | /* |
1124 | Operater of framebuffer |
1125 | */ |
1126 | int 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 | |
1189 | int 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 |