1 /*
2 * Copyright (C) 2016 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_TAG "hwc.cf_x86"
18 #define HWC_REMOVE_DEPRECATED_VERSIONS 1
19
20 #include "hwcomposer.h"
21
22 #include <errno.h>
23 #include <stdio.h>
24 #include <sys/resource.h>
25 #include <sys/time.h>
26 #include <string>
27
28 #include <log/log.h>
29
30 namespace cvd {
31
hwc_vsync_thread(void * data)32 void* hwc_vsync_thread(void* data) {
33 struct hwc_composer_device_data_t* pdev =
34 (struct hwc_composer_device_data_t*)data;
35 setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
36
37 int64_t base_timestamp = pdev->vsync_base_timestamp;
38 int64_t last_logged = base_timestamp / 1e9;
39 int sent = 0;
40 int last_sent = 0;
41 static const int log_interval = 60;
42 void (*vsync_proc)(const struct hwc_procs*, int, int64_t) = nullptr;
43 bool log_no_procs = true, log_no_vsync = true;
44 while (true) {
45 struct timespec rt;
46 if (clock_gettime(CLOCK_MONOTONIC, &rt) == -1) {
47 ALOGE("%s:%d error in vsync thread clock_gettime: %s", __FILE__, __LINE__,
48 strerror(errno));
49 }
50 int64_t timestamp = int64_t(rt.tv_sec) * 1e9 + rt.tv_nsec;
51 // Given now's timestamp calculate the time of the next timestamp.
52 timestamp += pdev->vsync_period_ns -
53 (timestamp - base_timestamp) % pdev->vsync_period_ns;
54
55 rt.tv_sec = timestamp / 1e9;
56 rt.tv_nsec = timestamp % static_cast<int32_t>(1e9);
57 int err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &rt, NULL);
58 if (err == -1) {
59 ALOGE("error in vsync thread: %s", strerror(errno));
60 if (errno == EINTR) {
61 continue;
62 }
63 }
64
65 // The vsync thread is started on device open, it may run before the
66 // registerProcs callback has a chance to be called, so we need to make sure
67 // procs is not NULL before dereferencing it.
68 if (pdev && pdev->procs) {
69 vsync_proc = pdev->procs->vsync;
70 } else if (log_no_procs) {
71 log_no_procs = false;
72 ALOGI("procs is not set yet, unable to deliver vsync event");
73 }
74 if (vsync_proc) {
75 vsync_proc(const_cast<hwc_procs_t*>(pdev->procs), 0, timestamp);
76 ++sent;
77 } else if (log_no_vsync) {
78 log_no_vsync = false;
79 ALOGE("vsync callback is null (but procs was already set)");
80 }
81 if (rt.tv_sec - last_logged > log_interval) {
82 ALOGI("Sent %d syncs in %ds", sent - last_sent, log_interval);
83 last_logged = rt.tv_sec;
84 last_sent = sent;
85 }
86 }
87
88 return NULL;
89 }
90
91 } // namespace cvd
92