1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * Copyright (C) 2012-2013, The Linux Foundation. All rights reserved. 4 * 5 * Not a Contribution, Apache license notifications and license are 6 * retained for attribution purposes only. 7 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 21 #include <cutils/properties.h> 22 #include <utils/Log.h> 23 #include <fcntl.h> 24 #include <sys/ioctl.h> 25 #include <linux/msm_mdp.h> 26 #include <sys/resource.h> 27 #include <sys/prctl.h> 28 #include <poll.h> 29 #include "hwc_utils.h" 30 #include "string.h" 31 #include "external.h" 32 33 namespace qhwc { 34 35 #define HWC_VSYNC_THREAD_NAME "hwcVsyncThread" 36 #define MAX_SYSFS_FILE_PATH 255 37 38 int hwc_vsync_control(hwc_context_t* ctx, int dpy, int enable) 39 { 40 int ret = 0; 41 if(!ctx->vstate.fakevsync && 42 ioctl(ctx->dpyAttr[dpy].fd, MSMFB_OVERLAY_VSYNC_CTRL, 43 &enable) < 0) { 44 ALOGE("%s: vsync control failed. Dpy=%d, enable=%d : %s", 45 __FUNCTION__, dpy, enable, strerror(errno)); 46 ret = -errno; 47 } 48 return ret; 49 } 50 51 static void *vsync_loop(void *param) 52 { 53 hwc_context_t * ctx = reinterpret_cast<hwc_context_t *>(param); 54 55 char thread_name[64] = HWC_VSYNC_THREAD_NAME; 56 prctl(PR_SET_NAME, (unsigned long) &thread_name, 0, 0, 0); 57 setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY + 58 android::PRIORITY_MORE_FAVORABLE); 59 60 const int MAX_DATA = 64; 61 char vdata[MAX_DATA]; 62 bool logvsync = false; 63 64 struct pollfd pfd[2]; 65 int fb_fd[2]; 66 uint64_t timestamp[2]; 67 int num_displays; 68 69 char property[PROPERTY_VALUE_MAX]; 70 if(property_get("debug.hwc.fakevsync", property, NULL) > 0) { 71 if(atoi(property) == 1) 72 ctx->vstate.fakevsync = true; 73 } 74 75 if(property_get("debug.hwc.logvsync", property, 0) > 0) { 76 if(atoi(property) == 1) 77 logvsync = true; 78 } 79 80 if (ctx->mExtDisplay->getHDMIIndex() > 0) 81 num_displays = 2; 82 else 83 num_displays = 1; 84 85 char vsync_node_path[MAX_SYSFS_FILE_PATH]; 86 for (int dpy = HWC_DISPLAY_PRIMARY; dpy < num_displays; dpy++) { 87 snprintf(vsync_node_path, sizeof(vsync_node_path), 88 "/sys/class/graphics/fb%d/vsync_event", 89 dpy == HWC_DISPLAY_PRIMARY ? 0 : 90 ctx->mExtDisplay->getHDMIIndex()); 91 ALOGI("%s: Reading vsync for dpy=%d from %s", __FUNCTION__, dpy, 92 vsync_node_path); 93 fb_fd[dpy] = open(vsync_node_path, O_RDONLY); 94 95 if (fb_fd[dpy] < 0) { 96 // Make sure fb device is opened before starting this thread so this 97 // never happens. 98 ALOGE ("%s:not able to open vsync node for dpy=%d, %s", 99 __FUNCTION__, dpy, strerror(errno)); 100 if (dpy == HWC_DISPLAY_PRIMARY) { 101 ctx->vstate.fakevsync = true; 102 break; 103 } 104 } 105 // Read once from the fds to clear the first notify 106 pread(fb_fd[dpy], vdata , MAX_DATA, 0); 107 108 pfd[dpy].fd = fb_fd[dpy]; 109 if (pfd[dpy].fd >= 0) 110 pfd[dpy].events = POLLPRI | POLLERR; 111 } 112 113 if (LIKELY(!ctx->vstate.fakevsync)) { 114 do { 115 int err = poll(pfd, num_displays, -1); 116 if(err > 0) { 117 for (int dpy = HWC_DISPLAY_PRIMARY; dpy < num_displays; dpy++) { 118 if (pfd[dpy].revents & POLLPRI) { 119 int len = pread(pfd[dpy].fd, vdata, MAX_DATA, 0); 120 if (UNLIKELY(len < 0)) { 121 // If the read was just interrupted - it is not a 122 // fatal error. Just continue in this case 123 ALOGE ("%s: Unable to read vsync for dpy=%d : %s", 124 __FUNCTION__, dpy, strerror(errno)); 125 continue; 126 } 127 // extract timestamp 128 if (!strncmp(vdata, "VSYNC=", strlen("VSYNC="))) { 129 timestamp[dpy] = strtoull(vdata + strlen("VSYNC="), 130 NULL, 0); 131 } 132 // send timestamp to SurfaceFlinger 133 ALOGD_IF (logvsync, 134 "%s: timestamp %llu sent to SF for dpy=%d", 135 __FUNCTION__, timestamp[dpy], dpy); 136 ctx->proc->vsync(ctx->proc, dpy, timestamp[dpy]); 137 } 138 } 139 140 } else { 141 ALOGE("%s: vsync poll failed errno: %s", __FUNCTION__, 142 strerror(errno)); 143 continue; 144 } 145 } while (true); 146 147 } else { 148 149 //Fake vsync is used only when set explicitly through a property or when 150 //the vsync timestamp node cannot be opened at bootup. There is no 151 //fallback to fake vsync from the true vsync loop, ever, as the 152 //condition can easily escape detection. 153 //Also, fake vsync is delivered only for the primary display. 154 do { 155 usleep(16666); 156 timestamp[HWC_DISPLAY_PRIMARY] = systemTime(); 157 ctx->proc->vsync(ctx->proc, HWC_DISPLAY_PRIMARY, 158 timestamp[HWC_DISPLAY_PRIMARY]); 159 160 } while (true); 161 } 162 163 for (int dpy = HWC_DISPLAY_PRIMARY; dpy <= HWC_DISPLAY_EXTERNAL; dpy++ ) { 164 if(fb_fd[dpy] >= 0) 165 close (fb_fd[dpy]); 166 } 167 168 return NULL; 169 } 170 171 void init_vsync_thread(hwc_context_t* ctx) 172 { 173 int ret; 174 pthread_t vsync_thread; 175 ALOGI("Initializing VSYNC Thread"); 176 ret = pthread_create(&vsync_thread, NULL, vsync_loop, (void*) ctx); 177 if (ret) { 178 ALOGE("%s: failed to create %s: %s", __FUNCTION__, 179 HWC_VSYNC_THREAD_NAME, strerror(ret)); 180 } 181 } 182 183 }; //namespace 184