mirror of
https://github.com/libretro/RetroArch
synced 2025-03-29 13:20:30 +00:00
Completely new approach for threaded video.
Allows a good compromise between jitter and avoiding audio stutter.
This commit is contained in:
parent
8dc60fc3d5
commit
51b17039d4
@ -77,7 +77,7 @@ static void autosave_thread(void *data)
|
||||
|
||||
slock_lock(save->cond_lock);
|
||||
if (!save->quit)
|
||||
scond_wait_timeout(save->cond, save->cond_lock, save->interval * 1000);
|
||||
scond_wait_timeout(save->cond, save->cond_lock, save->interval * 1000000LL);
|
||||
slock_unlock(save->cond_lock);
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ enum thread_cmd
|
||||
CMD_ALIVE, // Blocking alive check. Used when paused.
|
||||
CMD_SET_ROTATION,
|
||||
CMD_READ_VIEWPORT,
|
||||
CMD_SET_NONBLOCK,
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
CMD_OVERLAY_ENABLE,
|
||||
@ -88,6 +87,12 @@ typedef struct thread_video
|
||||
|
||||
bool alive;
|
||||
bool focus;
|
||||
bool nonblock;
|
||||
|
||||
rarch_time_t last_time;
|
||||
rarch_time_t target_frame_time;
|
||||
unsigned hit_count;
|
||||
unsigned miss_count;
|
||||
|
||||
enum thread_cmd send_cmd;
|
||||
enum thread_cmd reply_cmd;
|
||||
@ -191,11 +196,6 @@ static void thread_loop(void *data)
|
||||
thread_reply(thr, CMD_FREE);
|
||||
return;
|
||||
|
||||
case CMD_SET_NONBLOCK:
|
||||
thr->driver->set_nonblock_state(thr->driver_data, thr->cmd_data.b);
|
||||
thread_reply(thr, CMD_SET_NONBLOCK);
|
||||
break;
|
||||
|
||||
case CMD_SET_ROTATION:
|
||||
thr->driver->set_rotation(thr->driver_data, thr->cmd_data.i);
|
||||
thread_reply(thr, CMD_SET_ROTATION);
|
||||
@ -397,6 +397,24 @@ static bool thread_frame(void *data, const void *frame_,
|
||||
uint8_t *dst = thr->frame.buffer;
|
||||
|
||||
slock_lock(thr->lock);
|
||||
|
||||
if (!thr->nonblock)
|
||||
{
|
||||
rarch_time_t target = thr->last_time + thr->target_frame_time;
|
||||
// Ideally, use absolute time, but that is only a good idea on POSIX.
|
||||
while (thr->frame.updated)
|
||||
{
|
||||
rarch_time_t current = rarch_get_time_usec();
|
||||
rarch_time_t delta = target - current;
|
||||
|
||||
if (delta <= 0)
|
||||
break;
|
||||
|
||||
if (!scond_wait_timeout(thr->cond_cmd, thr->lock, delta))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Drop frame if updated flag is still set, as thread is still working on last frame.
|
||||
if (!thr->frame.updated)
|
||||
{
|
||||
@ -418,9 +436,6 @@ static bool thread_frame(void *data, const void *frame_,
|
||||
|
||||
scond_signal(thr->cond_thread);
|
||||
|
||||
// If we are going to render menu,
|
||||
// we'll want to block to avoid stepping menu
|
||||
// at crazy speeds.
|
||||
#if defined(HAVE_RGUI) || defined(HAVE_RMENU)
|
||||
if (thr->texture.enable)
|
||||
{
|
||||
@ -428,20 +443,23 @@ static bool thread_frame(void *data, const void *frame_,
|
||||
scond_wait(thr->cond_cmd, thr->lock);
|
||||
}
|
||||
#endif
|
||||
thr->hit_count++;
|
||||
}
|
||||
else
|
||||
thr->miss_count++;
|
||||
|
||||
slock_unlock(thr->lock);
|
||||
|
||||
RARCH_PERFORMANCE_STOP(thread_frame);
|
||||
|
||||
thr->last_time = rarch_get_time_usec();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void thread_set_nonblock_state(void *data, bool state)
|
||||
{
|
||||
thread_video_t *thr = (thread_video_t*)data;
|
||||
thr->cmd_data.b = state;
|
||||
thread_send_cmd(thr, CMD_SET_NONBLOCK);
|
||||
thread_wait_reply(thr, CMD_SET_NONBLOCK);
|
||||
thr->nonblock = state;
|
||||
}
|
||||
|
||||
static bool thread_init(thread_video_t *thr, const video_info_t *info, const input_driver_t **input,
|
||||
@ -466,6 +484,9 @@ static bool thread_init(thread_video_t *thr, const video_info_t *info, const inp
|
||||
|
||||
memset(thr->frame.buffer, 0x80, max_size);
|
||||
|
||||
thr->target_frame_time = (rarch_time_t)roundf(1000000LL / g_settings.video.refresh_rate);
|
||||
thr->last_time = rarch_get_time_usec();
|
||||
|
||||
thr->thread = sthread_create(thread_loop, thr);
|
||||
if (!thr->thread)
|
||||
return false;
|
||||
@ -534,6 +555,9 @@ static void thread_free(void *data)
|
||||
scond_free(thr->cond_cmd);
|
||||
scond_free(thr->cond_thread);
|
||||
|
||||
RARCH_LOG("Threaded video stats: Frames pushed: %u, Frames dropped: %u.\n",
|
||||
thr->hit_count, thr->miss_count);
|
||||
|
||||
free(thr);
|
||||
}
|
||||
|
||||
|
14
thread.c
14
thread.c
@ -152,12 +152,12 @@ void scond_wait(scond_t *cond, slock_t *lock)
|
||||
slock_lock(lock);
|
||||
}
|
||||
|
||||
bool scond_wait_timeout(scond_t *cond, slock_t *lock, unsigned timeout_ms)
|
||||
bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us)
|
||||
{
|
||||
WaitForSingleObject(cond->event, 0);
|
||||
slock_unlock(lock);
|
||||
|
||||
DWORD res = WaitForSingleObject(cond->event, timeout_ms);
|
||||
DWORD res = WaitForSingleObject(cond->event, timeout_us / 1000);
|
||||
|
||||
slock_lock(lock);
|
||||
return res == WAIT_OBJECT_0;
|
||||
@ -289,7 +289,7 @@ void scond_wait(scond_t *cond, slock_t *lock)
|
||||
}
|
||||
|
||||
#ifndef RARCH_CONSOLE
|
||||
bool scond_wait_timeout(scond_t *cond, slock_t *lock, unsigned timeout_ms)
|
||||
bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us)
|
||||
{
|
||||
struct timespec now;
|
||||
|
||||
@ -305,11 +305,11 @@ bool scond_wait_timeout(scond_t *cond, slock_t *lock, unsigned timeout_ms)
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
#endif
|
||||
|
||||
now.tv_sec += timeout_ms / 1000;
|
||||
now.tv_nsec += timeout_ms * 1000000L;
|
||||
now.tv_sec += timeout_us / 1000000LL;
|
||||
now.tv_nsec += timeout_us * 1000LL;
|
||||
|
||||
now.tv_sec += now.tv_nsec / 1000000000L;
|
||||
now.tv_nsec = now.tv_nsec % 1000000000L;
|
||||
now.tv_sec += now.tv_nsec / 1000000000LL;
|
||||
now.tv_nsec = now.tv_nsec % 1000000000LL;
|
||||
|
||||
int ret = pthread_cond_timedwait(&cond->cond, &lock->lock, &now);
|
||||
return ret == 0;
|
||||
|
3
thread.h
3
thread.h
@ -17,6 +17,7 @@
|
||||
#define THREAD_H__
|
||||
|
||||
#include "boolean.h"
|
||||
#include <stdint.h>
|
||||
|
||||
// Implements the bare minimum needed for RetroArch. :)
|
||||
|
||||
@ -43,7 +44,7 @@ void scond_free(scond_t *cond);
|
||||
|
||||
void scond_wait(scond_t *cond, slock_t *lock);
|
||||
#ifndef RARCH_CONSOLE
|
||||
bool scond_wait_timeout(scond_t *cond, slock_t *lock, unsigned timeout_ms);
|
||||
bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us);
|
||||
#endif
|
||||
void scond_signal(scond_t *cond);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user