2018-08-15 23:01:54 +08:00
|
|
|
#include "fps_counter.h"
|
2018-02-15 18:10:58 +08:00
|
|
|
|
2019-11-28 04:11:40 +08:00
|
|
|
#include <assert.h>
|
2018-02-15 18:10:58 +08:00
|
|
|
|
2019-11-24 18:53:00 +08:00
|
|
|
#include "util/log.h"
|
2018-02-15 18:10:58 +08:00
|
|
|
|
2021-07-04 22:50:19 +08:00
|
|
|
#define FPS_COUNTER_INTERVAL SC_TICK_FROM_SEC(1)
|
2019-06-07 22:55:19 +08:00
|
|
|
|
|
|
|
bool
|
2019-03-03 03:09:56 +08:00
|
|
|
fps_counter_init(struct fps_counter *counter) {
|
2021-02-01 01:24:35 +08:00
|
|
|
bool ok = sc_mutex_init(&counter->mutex);
|
|
|
|
if (!ok) {
|
2019-06-07 22:55:19 +08:00
|
|
|
return false;
|
|
|
|
}
|
2018-02-15 18:10:58 +08:00
|
|
|
|
2021-02-01 01:24:35 +08:00
|
|
|
ok = sc_cond_init(&counter->state_cond);
|
|
|
|
if (!ok) {
|
|
|
|
sc_mutex_destroy(&counter->mutex);
|
2019-06-07 22:55:19 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-02-01 01:24:35 +08:00
|
|
|
counter->thread_started = false;
|
2020-04-03 01:16:33 +08:00
|
|
|
atomic_init(&counter->started, 0);
|
2019-06-07 22:55:19 +08:00
|
|
|
// no need to initialize the other fields, they are unused until started
|
|
|
|
|
|
|
|
return true;
|
2018-02-15 18:10:58 +08:00
|
|
|
}
|
|
|
|
|
2019-03-03 03:09:56 +08:00
|
|
|
void
|
2019-06-07 22:55:19 +08:00
|
|
|
fps_counter_destroy(struct fps_counter *counter) {
|
2021-02-01 01:24:35 +08:00
|
|
|
sc_cond_destroy(&counter->state_cond);
|
|
|
|
sc_mutex_destroy(&counter->mutex);
|
2018-02-15 18:10:58 +08:00
|
|
|
}
|
|
|
|
|
2020-04-03 01:16:33 +08:00
|
|
|
static inline bool
|
|
|
|
is_started(struct fps_counter *counter) {
|
|
|
|
return atomic_load_explicit(&counter->started, memory_order_acquire);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
set_started(struct fps_counter *counter, bool started) {
|
|
|
|
atomic_store_explicit(&counter->started, started, memory_order_release);
|
|
|
|
}
|
|
|
|
|
2019-06-07 22:55:19 +08:00
|
|
|
// must be called with mutex locked
|
2019-03-03 03:09:56 +08:00
|
|
|
static void
|
|
|
|
display_fps(struct fps_counter *counter) {
|
2019-06-07 22:55:19 +08:00
|
|
|
unsigned rendered_per_second =
|
2021-07-04 22:50:19 +08:00
|
|
|
counter->nr_rendered * SC_TICK_FREQ / FPS_COUNTER_INTERVAL;
|
2018-02-15 18:10:58 +08:00
|
|
|
if (counter->nr_skipped) {
|
2019-06-07 22:55:19 +08:00
|
|
|
LOGI("%u fps (+%u frames skipped)", rendered_per_second,
|
2019-03-03 03:09:56 +08:00
|
|
|
counter->nr_skipped);
|
2018-02-15 18:10:58 +08:00
|
|
|
} else {
|
2019-06-07 22:55:19 +08:00
|
|
|
LOGI("%u fps", rendered_per_second);
|
2018-02-15 18:10:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-07 22:55:19 +08:00
|
|
|
// must be called with mutex locked
|
2019-03-03 03:09:56 +08:00
|
|
|
static void
|
2019-06-07 22:55:19 +08:00
|
|
|
check_interval_expired(struct fps_counter *counter, uint32_t now) {
|
|
|
|
if (now < counter->next_timestamp) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
display_fps(counter);
|
|
|
|
counter->nr_rendered = 0;
|
|
|
|
counter->nr_skipped = 0;
|
|
|
|
// add a multiple of the interval
|
|
|
|
uint32_t elapsed_slices =
|
2021-07-04 22:50:19 +08:00
|
|
|
(now - counter->next_timestamp) / FPS_COUNTER_INTERVAL + 1;
|
|
|
|
counter->next_timestamp += FPS_COUNTER_INTERVAL * elapsed_slices;
|
2019-06-07 22:55:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
run_fps_counter(void *data) {
|
|
|
|
struct fps_counter *counter = data;
|
|
|
|
|
2021-02-01 01:24:35 +08:00
|
|
|
sc_mutex_lock(&counter->mutex);
|
2019-06-07 22:55:19 +08:00
|
|
|
while (!counter->interrupted) {
|
2020-04-03 01:16:33 +08:00
|
|
|
while (!counter->interrupted && !is_started(counter)) {
|
2021-02-01 01:24:35 +08:00
|
|
|
sc_cond_wait(&counter->state_cond, &counter->mutex);
|
2019-06-07 22:55:19 +08:00
|
|
|
}
|
2020-04-03 01:16:33 +08:00
|
|
|
while (!counter->interrupted && is_started(counter)) {
|
2021-07-04 22:50:19 +08:00
|
|
|
sc_tick now = sc_tick_now();
|
2019-06-07 22:55:19 +08:00
|
|
|
check_interval_expired(counter, now);
|
|
|
|
|
|
|
|
// ignore the reason (timeout or signaled), we just loop anyway
|
2021-07-04 23:04:20 +08:00
|
|
|
sc_cond_timedwait(&counter->state_cond, &counter->mutex,
|
|
|
|
counter->next_timestamp);
|
2019-06-07 22:55:19 +08:00
|
|
|
}
|
|
|
|
}
|
2021-02-01 01:24:35 +08:00
|
|
|
sc_mutex_unlock(&counter->mutex);
|
2019-06-07 22:55:19 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
fps_counter_start(struct fps_counter *counter) {
|
2021-02-01 01:24:35 +08:00
|
|
|
sc_mutex_lock(&counter->mutex);
|
2021-07-04 22:50:19 +08:00
|
|
|
counter->next_timestamp = sc_tick_now() + FPS_COUNTER_INTERVAL;
|
2019-06-07 22:55:19 +08:00
|
|
|
counter->nr_rendered = 0;
|
|
|
|
counter->nr_skipped = 0;
|
2021-02-01 01:24:35 +08:00
|
|
|
sc_mutex_unlock(&counter->mutex);
|
2019-06-07 22:55:19 +08:00
|
|
|
|
2020-04-03 01:16:33 +08:00
|
|
|
set_started(counter, true);
|
2021-02-01 01:24:35 +08:00
|
|
|
sc_cond_signal(&counter->state_cond);
|
|
|
|
|
|
|
|
// counter->thread_started and counter->thread are always accessed from the
|
|
|
|
// same thread, no need to lock
|
|
|
|
if (!counter->thread_started) {
|
|
|
|
bool ok = sc_thread_create(&counter->thread, run_fps_counter,
|
2021-12-10 04:32:11 +08:00
|
|
|
"scrcpy-fps", counter);
|
2021-02-01 01:24:35 +08:00
|
|
|
if (!ok) {
|
2019-06-07 22:55:19 +08:00
|
|
|
LOGE("Could not start FPS counter thread");
|
|
|
|
return false;
|
|
|
|
}
|
2021-02-01 01:24:35 +08:00
|
|
|
|
|
|
|
counter->thread_started = true;
|
2019-06-07 22:55:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fps_counter_stop(struct fps_counter *counter) {
|
2020-04-03 01:16:33 +08:00
|
|
|
set_started(counter, false);
|
2021-02-01 01:24:35 +08:00
|
|
|
sc_cond_signal(&counter->state_cond);
|
2019-06-07 22:55:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
fps_counter_is_started(struct fps_counter *counter) {
|
2020-04-03 01:16:33 +08:00
|
|
|
return is_started(counter);
|
2019-06-07 22:55:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fps_counter_interrupt(struct fps_counter *counter) {
|
2021-02-01 01:24:35 +08:00
|
|
|
if (!counter->thread_started) {
|
2019-06-07 22:55:19 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-02-01 01:24:35 +08:00
|
|
|
sc_mutex_lock(&counter->mutex);
|
2019-06-07 22:55:19 +08:00
|
|
|
counter->interrupted = true;
|
2021-02-01 01:24:35 +08:00
|
|
|
sc_mutex_unlock(&counter->mutex);
|
2019-06-07 22:55:19 +08:00
|
|
|
// wake up blocking wait
|
2021-02-01 01:24:35 +08:00
|
|
|
sc_cond_signal(&counter->state_cond);
|
2019-06-07 22:55:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fps_counter_join(struct fps_counter *counter) {
|
2021-02-01 01:24:35 +08:00
|
|
|
if (counter->thread_started) {
|
2021-05-17 00:26:20 +08:00
|
|
|
// interrupted must be set by the thread calling join(), so no need to
|
|
|
|
// lock for the assertion
|
|
|
|
assert(counter->interrupted);
|
|
|
|
|
2021-02-01 01:24:35 +08:00
|
|
|
sc_thread_join(&counter->thread, NULL);
|
2018-02-15 18:10:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-03 03:09:56 +08:00
|
|
|
void
|
|
|
|
fps_counter_add_rendered_frame(struct fps_counter *counter) {
|
2020-04-03 01:16:33 +08:00
|
|
|
if (!is_started(counter)) {
|
2019-06-07 22:55:19 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-02-01 01:24:35 +08:00
|
|
|
sc_mutex_lock(&counter->mutex);
|
2021-07-04 22:50:19 +08:00
|
|
|
sc_tick now = sc_tick_now();
|
2019-06-07 22:55:19 +08:00
|
|
|
check_interval_expired(counter, now);
|
2018-02-15 18:10:58 +08:00
|
|
|
++counter->nr_rendered;
|
2021-02-01 01:24:35 +08:00
|
|
|
sc_mutex_unlock(&counter->mutex);
|
2018-02-15 18:10:58 +08:00
|
|
|
}
|
|
|
|
|
2019-03-03 03:09:56 +08:00
|
|
|
void
|
|
|
|
fps_counter_add_skipped_frame(struct fps_counter *counter) {
|
2020-04-03 01:16:33 +08:00
|
|
|
if (!is_started(counter)) {
|
2019-06-07 22:55:19 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-02-01 01:24:35 +08:00
|
|
|
sc_mutex_lock(&counter->mutex);
|
2021-07-04 22:50:19 +08:00
|
|
|
sc_tick now = sc_tick_now();
|
2019-06-07 22:55:19 +08:00
|
|
|
check_interval_expired(counter, now);
|
2018-02-15 18:10:58 +08:00
|
|
|
++counter->nr_skipped;
|
2021-02-01 01:24:35 +08:00
|
|
|
sc_mutex_unlock(&counter->mutex);
|
2018-02-15 18:10:58 +08:00
|
|
|
}
|