|  | // Copyright 2019 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "fps_counter.h" | 
|  |  | 
|  | #include <stddef.h> | 
|  | #include <stdio.h> | 
|  | #include <sys/time.h> | 
|  |  | 
|  | // Return current time in milliseconds. | 
|  | static double | 
|  | time_now_seconds(void * opaque) | 
|  | { | 
|  | struct timeval tm; | 
|  | gettimeofday(&tm, NULL); | 
|  | return tm.tv_sec * 1.0 + (tm.tv_usec / 1e9); | 
|  | } | 
|  |  | 
|  | // Set this to 0 to disable unit-testing support. | 
|  | #define SUPPORT_UNIT_TESTING 1 | 
|  |  | 
|  | #if SUPPORT_UNIT_TESTING | 
|  |  | 
|  | static fps_counter_clock_callback_t s_clock_callback = &time_now_seconds; | 
|  | static void *                       s_clock_opaque   = NULL; | 
|  |  | 
|  | // Ensure that the implementation uses |clock_callback(clock_opaque)| to get | 
|  | // the current time during unit-testing. | 
|  | void | 
|  | fps_counter_set_clock_for_testing(fps_counter_clock_callback_t clock_callback, void * clock_opaque) | 
|  | { | 
|  | if (!clock_callback) | 
|  | { | 
|  | clock_callback = &time_now_seconds; | 
|  | clock_opaque   = NULL; | 
|  | } | 
|  | s_clock_callback = clock_callback; | 
|  | s_clock_opaque   = clock_opaque; | 
|  | } | 
|  |  | 
|  | #define GET_CLOCK_SECONDS() s_clock_callback(s_clock_opaque) | 
|  | #else  // !SUPPORT_UNIT_TESTING | 
|  | #define GET_CLOCK_SECONDS() time_now_seconds(NULL) | 
|  | #endif  // !SUPPORT_UNIT_TESTING | 
|  |  | 
|  | #define SECONDS_INCREMENT 4.0 | 
|  |  | 
|  | void | 
|  | fps_counter_start(fps_counter_t * fps) | 
|  | { | 
|  | fps->current_fps      = 0.; | 
|  | fps->start_time       = GET_CLOCK_SECONDS(); | 
|  | fps->next_time        = fps->start_time + SECONDS_INCREMENT; | 
|  | fps->frame_count      = 0; | 
|  | fps->frame_count_prev = 0; | 
|  | } | 
|  |  | 
|  | bool | 
|  | fps_counter_tick(fps_counter_t * fps) | 
|  | { | 
|  | fps->frame_count++; | 
|  |  | 
|  | double now_secs = GET_CLOCK_SECONDS(); | 
|  | if (now_secs < fps->next_time) | 
|  | return false; | 
|  |  | 
|  | fps->current_fps      = (fps->frame_count - fps->frame_count_prev) / (now_secs - fps->start_time); | 
|  | fps->frame_count_prev = fps->frame_count; | 
|  | fps->start_time       = fps->next_time; | 
|  | while (fps->next_time <= now_secs) | 
|  | fps->next_time += SECONDS_INCREMENT; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool | 
|  | fps_counter_stop(fps_counter_t * fps) | 
|  | { | 
|  | if (fps->frame_count > fps->frame_count_prev) | 
|  | return fps_counter_tick(fps); | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void | 
|  | fps_counter_tick_and_print(fps_counter_t * fps) | 
|  | { | 
|  | if (fps_counter_tick(fps)) | 
|  | { | 
|  | printf("FPS: %1.f\n", fps->current_fps); | 
|  | fflush(stdout); | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | fps_counter_stop_and_print(fps_counter_t * fps) | 
|  | { | 
|  | if (fps->frame_count > fps->frame_count_prev) | 
|  | fps_counter_tick_and_print(fps); | 
|  | } |