1 /* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. 2 * 3 * Redistribution and use in source and binary forms, with or without 4 * modification, are permitted provided that the following conditions are 5 * met: 6 * * Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * * Redistributions in binary form must reproduce the above 9 * copyright notice, this list of conditions and the following 10 * disclaimer in the documentation and/or other materials provided 11 * with the distribution. 12 * * Neither the name of The Linux Foundation nor the names of its 13 * contributors may be used to endorse or promote products derived 14 * from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 */ 29 30 #define LOG_TAG "QCameraDisplay" 31 32 // To remove 33 #include <cutils/properties.h> 34 35 // Camera dependencies 36 #include "QCamera2HWI.h" 37 #include "QCameraDisplay.h" 38 39 extern "C" { 40 #include "mm_camera_dbg.h" 41 } 42 43 #define CAMERA_VSYNC_WAIT_MS 33 // Used by vsync thread to wait for vsync timeout. 44 #define DISPLAY_EVENT_RECEIVER_ARRAY_SIZE 1 45 #define DISPLAY_DEFAULT_FPS 60 46 47 namespace qcamera { 48 49 /*=========================================================================== 50 * FUNCTION : vsyncEventReceiverCamera 51 * 52 * DESCRIPTION: Computes average vsync interval. Called by display 53 * event handler for every vsync event. 54 * 55 * PARAMETERS : 56 * @fd : file descriptor 57 * @events : events 58 * @data : pointer to user data provided during call back registration. 59 * 60 * RETURN : always returns 1 61 *==========================================================================*/ 62 int QCameraDisplay::vsyncEventReceiverCamera(__unused int fd, 63 __unused int events, void* data) { 64 android::DisplayEventReceiver::Event buffer[DISPLAY_EVENT_RECEIVER_ARRAY_SIZE]; 65 QCameraDisplay* pQCameraDisplay = (QCameraDisplay *) data; 66 ssize_t n; 67 68 while ((n = pQCameraDisplay->mDisplayEventReceiver.getEvents(buffer, 69 DISPLAY_EVENT_RECEIVER_ARRAY_SIZE)) > 0) { 70 for (int i = 0 ; i < n ; i++) { 71 if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { 72 pQCameraDisplay->computeAverageVsyncInterval(buffer[i].header.timestamp); 73 } 74 } 75 } 76 return 1; 77 } 78 79 /*=========================================================================== 80 * FUNCTION : vsyncThreadCamera 81 * 82 * DESCRIPTION: Thread registers a call back function for every vsync event 83 * waits on the looper for the next vsync. 84 * 85 * PARAMETERS : 86 * @data : receives vsync_info_t structure. 87 * 88 * RETURN : NULL.Just to fullfill the type requirement of thread function. 89 *==========================================================================*/ 90 void* QCameraDisplay::vsyncThreadCamera(void * data) 91 { 92 QCameraDisplay* pQCameraDisplay = (QCameraDisplay *) data; 93 android::sp<Looper> looper; 94 95 looper = new android::Looper(false); 96 status_t status = pQCameraDisplay->mDisplayEventReceiver.initCheck(); 97 if (status != NO_ERROR) { 98 LOGE("Initialization of DisplayEventReceiver failed with status: %d", status); 99 return NULL; 100 } 101 looper->addFd(pQCameraDisplay->mDisplayEventReceiver.getFd(), 0, ALOOPER_EVENT_INPUT, 102 QCameraDisplay::vsyncEventReceiverCamera, pQCameraDisplay); 103 pQCameraDisplay->mDisplayEventReceiver.setVsyncRate(1); 104 while(pQCameraDisplay->mThreadExit == 0) 105 { 106 looper->pollOnce(CAMERA_VSYNC_WAIT_MS); 107 } 108 return NULL; 109 } 110 111 /*=========================================================================== 112 * FUNCTION : ~QCameraDisplay 113 * 114 * DESCRIPTION: constructor of QCameraDisplay 115 * 116 * PARAMETERS : none 117 * 118 * RETURN : none 119 *==========================================================================*/ 120 QCameraDisplay::QCameraDisplay() 121 : mVsyncTimeStamp(0), 122 mAvgVsyncInterval(0), 123 mOldTimeStamp(0), 124 mVsyncHistoryIndex(0), 125 mAdditionalVsyncOffsetForWiggle(0), 126 mThreadExit(0), 127 mNum_vsync_from_vfe_isr_to_presentation_timestamp(0), 128 mSet_timestamp_num_ms_prior_to_vsync(0), 129 mVfe_and_mdp_freq_wiggle_filter_max_ms(0), 130 mVfe_and_mdp_freq_wiggle_filter_min_ms(0) 131 { 132 int rc = NO_ERROR; 133 134 memset(&mVsyncIntervalHistory, 0, sizeof(mVsyncIntervalHistory)); 135 rc = pthread_create(&mVsyncThreadCameraHandle, NULL, vsyncThreadCamera, (void *)this); 136 if (rc == NO_ERROR) { 137 char value[PROPERTY_VALUE_MAX]; 138 nsecs_t default_vsync_interval; 139 pthread_setname_np(mVsyncThreadCameraHandle, "CAM_Vsync_Thread"); 140 // Read a list of properties used for tuning 141 property_get("persist.camera.disp.num_vsync", value, "4"); 142 mNum_vsync_from_vfe_isr_to_presentation_timestamp = atoi(value); 143 property_get("persist.camera.disp.ms_to_vsync", value, "2"); 144 mSet_timestamp_num_ms_prior_to_vsync = atoi(value); 145 property_get("persist.camera.disp.filter_max", value, "2"); 146 mVfe_and_mdp_freq_wiggle_filter_max_ms = atoi(value); 147 property_get("persist.camera.disp.filter_min", value, "4"); 148 mVfe_and_mdp_freq_wiggle_filter_min_ms = atoi(value); 149 property_get("persist.camera.disp.fps", value, "60"); 150 if (atoi(value) > 0) { 151 default_vsync_interval= s2ns(1) / atoi(value); 152 } else { 153 default_vsync_interval= s2ns(1) / DISPLAY_DEFAULT_FPS; 154 } 155 for (int i=0; i < CAMERA_NUM_VSYNC_INTERVAL_HISTORY; i++) { 156 mVsyncIntervalHistory[i] = default_vsync_interval; 157 } 158 LOGD("display jitter num_vsync_from_vfe_isr_to_presentation_timestamp %u \ 159 set_timestamp_num_ms_prior_to_vsync %u", 160 mNum_vsync_from_vfe_isr_to_presentation_timestamp, 161 mSet_timestamp_num_ms_prior_to_vsync); 162 LOGD("display jitter vfe_and_mdp_freq_wiggle_filter_max_ms %u \ 163 vfe_and_mdp_freq_wiggle_filter_min_ms %u", 164 mVfe_and_mdp_freq_wiggle_filter_max_ms, 165 mVfe_and_mdp_freq_wiggle_filter_min_ms); 166 } else { 167 mVsyncThreadCameraHandle = 0; 168 } 169 } 170 171 /*=========================================================================== 172 * FUNCTION : ~QCameraDisplay 173 * 174 * DESCRIPTION: destructor of QCameraDisplay 175 * 176 * PARAMETERS : none 177 * 178 * RETURN : none 179 *==========================================================================*/ 180 QCameraDisplay::~QCameraDisplay() 181 { 182 mThreadExit = 1; 183 if (mVsyncThreadCameraHandle != 0) { 184 pthread_join(mVsyncThreadCameraHandle, NULL); 185 } 186 } 187 188 /*=========================================================================== 189 * FUNCTION : computeAverageVsyncInterval 190 * 191 * DESCRIPTION: Computes average vsync interval using current and previously 192 * stored vsync data. 193 * 194 * PARAMETERS : current vsync time stamp 195 * 196 * RETURN : none 197 *==========================================================================*/ 198 void QCameraDisplay::computeAverageVsyncInterval(nsecs_t currentVsyncTimeStamp) 199 { 200 nsecs_t sum; 201 nsecs_t vsyncMaxOutlier; 202 nsecs_t vsyncMinOutlier; 203 204 mVsyncTimeStamp = currentVsyncTimeStamp; 205 if (mOldTimeStamp) { 206 // Compute average vsync interval using current and previously stored vsync data. 207 // Leave the max and min vsync interval from history in computing the average. 208 mVsyncIntervalHistory[mVsyncHistoryIndex] = currentVsyncTimeStamp - mOldTimeStamp; 209 mVsyncHistoryIndex++; 210 mVsyncHistoryIndex = mVsyncHistoryIndex % CAMERA_NUM_VSYNC_INTERVAL_HISTORY; 211 sum = mVsyncIntervalHistory[0]; 212 vsyncMaxOutlier = mVsyncIntervalHistory[0]; 213 vsyncMinOutlier = mVsyncIntervalHistory[0]; 214 for (int j=1; j<CAMERA_NUM_VSYNC_INTERVAL_HISTORY; j++) { 215 sum += mVsyncIntervalHistory[j]; 216 if (vsyncMaxOutlier < mVsyncIntervalHistory[j]) { 217 vsyncMaxOutlier = mVsyncIntervalHistory[j]; 218 } else if (vsyncMinOutlier > mVsyncIntervalHistory[j]) { 219 vsyncMinOutlier = mVsyncIntervalHistory[j]; 220 } 221 } 222 sum = sum - vsyncMaxOutlier - vsyncMinOutlier; 223 mAvgVsyncInterval = sum / (CAMERA_NUM_VSYNC_INTERVAL_HISTORY - 2); 224 } 225 mOldTimeStamp = currentVsyncTimeStamp; 226 } 227 228 /*=========================================================================== 229 * FUNCTION : computePresentationTimeStamp 230 * 231 * DESCRIPTION: Computes presentation time stamp using vsync interval 232 * and last vsync time stamp and few other tunable variables 233 * to place the time stamp at the expected future vsync 234 * 235 * PARAMETERS : current frame time stamp set by VFE when buffer copy done. 236 * 237 * RETURN : time stamp in future or 0 in case of failure. 238 *==========================================================================*/ 239 nsecs_t QCameraDisplay::computePresentationTimeStamp(nsecs_t frameTimeStamp) 240 { 241 nsecs_t moveToNextVsync; 242 nsecs_t keepInCurrentVsync; 243 nsecs_t timeDifference = 0; 244 nsecs_t presentationTimeStamp = 0; 245 int expectedVsyncOffset = 0; 246 int vsyncOffset; 247 248 if ( (mAvgVsyncInterval != 0) && (mVsyncTimeStamp != 0) ) { 249 // Compute presentation time stamp in future as per the following formula 250 // future time stamp = vfe time stamp + N * average vsync interval 251 // Adjust the time stamp so that it is placed few milliseconds before 252 // the expected vsync. 253 // Adjust the time stamp for the period where vsync time stamp and VFE 254 // timstamp cross over due difference in fps. 255 presentationTimeStamp = frameTimeStamp + 256 (mNum_vsync_from_vfe_isr_to_presentation_timestamp * mAvgVsyncInterval); 257 if (presentationTimeStamp > mVsyncTimeStamp) { 258 timeDifference = presentationTimeStamp - mVsyncTimeStamp; 259 moveToNextVsync = mAvgVsyncInterval - mVfe_and_mdp_freq_wiggle_filter_min_ms; 260 keepInCurrentVsync = mAvgVsyncInterval - mVfe_and_mdp_freq_wiggle_filter_max_ms; 261 vsyncOffset = timeDifference % mAvgVsyncInterval; 262 expectedVsyncOffset = mAvgVsyncInterval - 263 mSet_timestamp_num_ms_prior_to_vsync - vsyncOffset; 264 if (vsyncOffset > moveToNextVsync) { 265 mAdditionalVsyncOffsetForWiggle = mAvgVsyncInterval; 266 } else if (vsyncOffset < keepInCurrentVsync) { 267 mAdditionalVsyncOffsetForWiggle = 0; 268 } 269 LOGD("vsyncTimeStamp: %llu presentationTimeStamp: %llu expectedVsyncOffset: %d \ 270 timeDifference: %llu vsyncffset: %d avgvsync: %llu \ 271 additionalvsyncOffsetForWiggle: %llu", 272 mVsyncTimeStamp, presentationTimeStamp, expectedVsyncOffset, 273 timeDifference, vsyncOffset, mAvgVsyncInterval, 274 mAdditionalVsyncOffsetForWiggle); 275 } 276 presentationTimeStamp = presentationTimeStamp + expectedVsyncOffset + 277 mAdditionalVsyncOffsetForWiggle; 278 } 279 return presentationTimeStamp; 280 } 281 282 }; // namespace qcamera 283