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