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  *==========================================================================*/
vsyncEventReceiverCamera(__unused int fd,__unused int events,void * data)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  *==========================================================================*/
vsyncThreadCamera(void * data)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  *==========================================================================*/
QCameraDisplay()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  *==========================================================================*/
~QCameraDisplay()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  *==========================================================================*/
computeAverageVsyncInterval(nsecs_t currentVsyncTimeStamp)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  *==========================================================================*/
computePresentationTimeStamp(nsecs_t frameTimeStamp)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