mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-09-20 04:42:18 +02:00
libobs: Add task scheduling features
(This commit also modifies the UI) Adds the ability to schedule tasks for certain threads
This commit is contained in:
parent
9f00350688
commit
8de20ab3be
@ -1327,6 +1327,17 @@ void OBSApp::Exec(VoidFunc func)
|
||||
func();
|
||||
}
|
||||
|
||||
static void ui_task_handler(obs_task_t task, void *param, bool wait)
|
||||
{
|
||||
auto doTask = [=]() {
|
||||
/* to get clang-format to behave */
|
||||
task(param);
|
||||
};
|
||||
QMetaObject::invokeMethod(App(), "Exec",
|
||||
wait ? WaitConnection() : Qt::AutoConnection,
|
||||
Q_ARG(VoidFunc, doTask));
|
||||
}
|
||||
|
||||
bool OBSApp::OBSInit()
|
||||
{
|
||||
ProfileScope("OBSApp::OBSInit");
|
||||
@ -1338,6 +1349,8 @@ bool OBSApp::OBSInit()
|
||||
if (!StartupOBS(locale.c_str(), GetProfilerNameStore()))
|
||||
return false;
|
||||
|
||||
obs_set_ui_task_handler(ui_task_handler);
|
||||
|
||||
#ifdef _WIN32
|
||||
bool browserHWAccel =
|
||||
config_get_bool(globalConfig, "General", "BrowserHWAccel");
|
||||
|
@ -2267,6 +2267,9 @@ void OBSBasic::ClearHotkeys()
|
||||
|
||||
OBSBasic::~OBSBasic()
|
||||
{
|
||||
/* clear out UI event queue */
|
||||
QApplication::sendPostedEvents(App());
|
||||
|
||||
if (updateCheckThread && updateCheckThread->isRunning())
|
||||
updateCheckThread->wait();
|
||||
|
||||
|
@ -234,6 +234,11 @@ struct obs_tex_frame {
|
||||
bool released;
|
||||
};
|
||||
|
||||
struct obs_task_info {
|
||||
obs_task_t task;
|
||||
void *param;
|
||||
};
|
||||
|
||||
struct obs_core_video {
|
||||
graphics_t *graphics;
|
||||
gs_stagesurf_t *copy_surfaces[NUM_TEXTURES][NUM_CHANNELS];
|
||||
@ -306,6 +311,9 @@ struct obs_core_video {
|
||||
gs_effect_t *deinterlace_yadif_2x_effect;
|
||||
|
||||
struct obs_video_info ovi;
|
||||
|
||||
pthread_mutex_t task_mutex;
|
||||
struct circlebuf tasks;
|
||||
};
|
||||
|
||||
struct audio_monitor;
|
||||
@ -420,6 +428,8 @@ struct obs_core {
|
||||
struct obs_core_audio audio;
|
||||
struct obs_core_data data;
|
||||
struct obs_core_hotkeys hotkeys;
|
||||
|
||||
obs_task_handler_t ui_task_handler;
|
||||
};
|
||||
|
||||
extern struct obs_core *obs;
|
||||
|
@ -816,6 +816,25 @@ static void clear_gpu_frame_data(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
extern THREAD_LOCAL bool is_graphics_thread;
|
||||
|
||||
static void execute_graphics_tasks(void)
|
||||
{
|
||||
struct obs_core_video *video = &obs->video;
|
||||
bool tasks_remaining = true;
|
||||
|
||||
while (tasks_remaining) {
|
||||
pthread_mutex_lock(&video->task_mutex);
|
||||
if (video->tasks.size) {
|
||||
struct obs_task_info info;
|
||||
circlebuf_pop_front(&video->tasks, &info, sizeof(info));
|
||||
info.task(info.param);
|
||||
}
|
||||
tasks_remaining = !!video->tasks.size;
|
||||
pthread_mutex_unlock(&video->task_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *tick_sources_name = "tick_sources";
|
||||
static const char *render_displays_name = "render_displays";
|
||||
static const char *output_frame_name = "output_frame";
|
||||
@ -832,6 +851,8 @@ void *obs_graphics_thread(void *param)
|
||||
bool raw_was_active = false;
|
||||
bool was_active = false;
|
||||
|
||||
is_graphics_thread = true;
|
||||
|
||||
obs->video.video_time = os_gettime_ns();
|
||||
obs->video.video_frame_interval_ns = interval;
|
||||
|
||||
@ -883,6 +904,8 @@ void *obs_graphics_thread(void *param)
|
||||
last_time = tick_sources(obs->video.video_time, last_time);
|
||||
profile_end(tick_sources_name);
|
||||
|
||||
execute_graphics_tasks();
|
||||
|
||||
#ifdef _WIN32
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
|
80
libobs/obs.c
80
libobs/obs.c
@ -426,6 +426,8 @@ static int obs_init_video(struct obs_video_info *ovi)
|
||||
return OBS_VIDEO_FAIL;
|
||||
if (pthread_mutex_init(&video->gpu_encoder_mutex, NULL) < 0)
|
||||
return OBS_VIDEO_FAIL;
|
||||
if (pthread_mutex_init(&video->task_mutex, NULL) < 0)
|
||||
return OBS_VIDEO_FAIL;
|
||||
|
||||
errorcode = pthread_create(&video->video_thread, NULL,
|
||||
obs_graphics_thread, obs);
|
||||
@ -521,6 +523,10 @@ static void obs_free_video(void)
|
||||
pthread_mutex_init_value(&video->gpu_encoder_mutex);
|
||||
da_free(video->gpu_encoders);
|
||||
|
||||
pthread_mutex_destroy(&video->task_mutex);
|
||||
pthread_mutex_init_value(&video->task_mutex);
|
||||
circlebuf_free(&video->tasks);
|
||||
|
||||
video->gpu_encoder_active = 0;
|
||||
video->cur_texture = 0;
|
||||
}
|
||||
@ -843,6 +849,7 @@ static bool obs_init(const char *locale, const char *module_config_path,
|
||||
|
||||
pthread_mutex_init_value(&obs->audio.monitoring_mutex);
|
||||
pthread_mutex_init_value(&obs->video.gpu_encoder_mutex);
|
||||
pthread_mutex_init_value(&obs->video.task_mutex);
|
||||
|
||||
obs->name_store_owned = !store;
|
||||
obs->name_store = store ? store : profiler_name_store_create();
|
||||
@ -2577,3 +2584,76 @@ bool obs_nv12_tex_active(void)
|
||||
|
||||
return video->using_nv12_tex;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* task stuff */
|
||||
|
||||
struct task_wait_info {
|
||||
obs_task_t task;
|
||||
void *param;
|
||||
os_event_t *event;
|
||||
};
|
||||
|
||||
static void task_wait_callback(void *param)
|
||||
{
|
||||
struct task_wait_info *info = param;
|
||||
info->task(info->param);
|
||||
os_event_signal(info->event);
|
||||
}
|
||||
|
||||
THREAD_LOCAL bool is_graphics_thread = false;
|
||||
|
||||
static bool in_task_thread(enum obs_task_type type)
|
||||
{
|
||||
/* NOTE: OBS_TASK_UI is handled independently */
|
||||
|
||||
if (type == OBS_TASK_GRAPHICS)
|
||||
return is_graphics_thread;
|
||||
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
void obs_queue_task(enum obs_task_type type, obs_task_t task, void *param,
|
||||
bool wait)
|
||||
{
|
||||
if (!obs)
|
||||
return;
|
||||
|
||||
if (type == OBS_TASK_UI) {
|
||||
if (obs->ui_task_handler) {
|
||||
obs->ui_task_handler(task, param, wait);
|
||||
} else {
|
||||
blog(LOG_ERROR, "UI task could not be queued, "
|
||||
"there's no UI task handler!");
|
||||
}
|
||||
} else {
|
||||
if (in_task_thread(type)) {
|
||||
task(param);
|
||||
} else if (wait) {
|
||||
struct task_wait_info info = {
|
||||
.task = task,
|
||||
.param = param,
|
||||
};
|
||||
|
||||
os_event_init(&info.event, OS_EVENT_TYPE_MANUAL);
|
||||
obs_queue_task(type, task_wait_callback, &info, false);
|
||||
os_event_wait(info.event);
|
||||
os_event_destroy(info.event);
|
||||
} else {
|
||||
struct obs_core_video *video = &obs->video;
|
||||
struct obs_task_info info = {task, param};
|
||||
|
||||
pthread_mutex_lock(&video->task_mutex);
|
||||
circlebuf_push_back(&video->tasks, &info, sizeof(info));
|
||||
pthread_mutex_unlock(&video->task_mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void obs_set_ui_task_handler(obs_task_handler_t handler)
|
||||
{
|
||||
if (!obs)
|
||||
return;
|
||||
obs->ui_task_handler = handler;
|
||||
}
|
||||
|
13
libobs/obs.h
13
libobs/obs.h
@ -745,6 +745,19 @@ EXPORT void obs_apply_private_data(obs_data_t *settings);
|
||||
EXPORT void obs_set_private_data(obs_data_t *settings);
|
||||
EXPORT obs_data_t *obs_get_private_data(void);
|
||||
|
||||
typedef void (*obs_task_t)(void *param);
|
||||
|
||||
enum obs_task_type {
|
||||
OBS_TASK_UI,
|
||||
OBS_TASK_GRAPHICS,
|
||||
};
|
||||
|
||||
EXPORT void obs_queue_task(enum obs_task_type type, obs_task_t task,
|
||||
void *param, bool wait);
|
||||
|
||||
typedef void (*obs_task_handler_t)(obs_task_t task, void *param, bool wait);
|
||||
EXPORT void obs_set_ui_task_handler(obs_task_handler_t handler);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* View context */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user