diff --git a/libobs/obs-cocoa.m b/libobs/obs-cocoa.m index 71cfaba00b7c552582c9f2bc6da7e4d10d8042b9..d5df16af5451c66c7e8c9660245d5870e0e7978c 100644 --- a/libobs/obs-cocoa.m +++ b/libobs/obs-cocoa.m @@ -1804,3 +1804,17 @@ bool obs_hotkeys_platform_is_pressed(obs_hotkeys_platform_t *plat, return false; } + +void *obs_graphics_thread_autorelease(void *param) +{ + @autoreleasepool { + return obs_graphics_thread(param); + } +} + +bool obs_graphics_thread_loop_autorelease(struct obs_graphics_context *context) +{ + @autoreleasepool { + return obs_graphics_thread_loop(context); + } +} diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h index 94013d6985bd2da6e510c8d90a1e0245fcf98d7c..38b8cba6ff25f4ada48a57044688a936e774edbf 100644 --- a/libobs/obs-internal.h +++ b/libobs/obs-internal.h @@ -434,7 +434,27 @@ struct obs_core { extern struct obs_core *obs; +struct obs_graphics_context { + uint64_t last_time; + uint64_t interval; + uint64_t frame_time_total_ns; + uint64_t fps_total_ns; + uint32_t fps_total_frames; +#ifdef _WIN32 + bool gpu_was_active; +#endif + bool raw_was_active; + bool was_active; + const char *video_thread_name; +}; + extern void *obs_graphics_thread(void *param); +extern bool obs_graphics_thread_loop(struct obs_graphics_context *context); +#ifdef __APPLE__ +extern void *obs_graphics_thread_autorelease(void *param); +extern bool +obs_graphics_thread_loop_autorelease(struct obs_graphics_context *context); +#endif extern gs_effect_t *obs_load_effect(gs_effect_t **effect, const char *file); diff --git a/libobs/obs-video.c b/libobs/obs-video.c index 82b37b492bd889b6310798783fac3d650ab58dd4..f1c01932038794ae146a431caa503f7644d40231 100644 --- a/libobs/obs-video.c +++ b/libobs/obs-video.c @@ -921,124 +921,135 @@ static void uninit_winrt_state(struct winrt_state *winrt) static const char *tick_sources_name = "tick_sources"; static const char *render_displays_name = "render_displays"; static const char *output_frame_name = "output_frame"; -void *obs_graphics_thread(void *param) +bool obs_graphics_thread_loop(struct obs_graphics_context *context) { -#ifdef _WIN32 - struct winrt_state winrt; - init_winrt_state(&winrt); -#endif // #ifdef _WIN32 + /* defer loop break to clean up sources */ + const bool stop_requested = video_output_stopped(obs->video.video); - uint64_t last_time = 0; - uint64_t interval = video_output_get_frame_time(obs->video.video); - uint64_t frame_time_total_ns = 0; - uint64_t fps_total_ns = 0; - uint32_t fps_total_frames = 0; + uint64_t frame_start = os_gettime_ns(); + uint64_t frame_time_ns; + bool raw_active = obs->video.raw_active > 0; #ifdef _WIN32 - bool gpu_was_active = false; + const bool gpu_active = obs->video.gpu_encoder_active > 0; + const bool active = raw_active || gpu_active; +#else + const bool gpu_active = 0; + const bool active = raw_active; #endif - bool raw_was_active = false; - bool was_active = false; - is_graphics_thread = true; + if (!context->was_active && active) + clear_base_frame_data(); + if (!context->raw_was_active && raw_active) + clear_raw_frame_data(); +#ifdef _WIN32 + if (!context->gpu_was_active && gpu_active) + clear_gpu_frame_data(); - obs->video.video_time = os_gettime_ns(); - obs->video.video_frame_interval_ns = interval; + context->gpu_was_active = gpu_active; +#endif + context->raw_was_active = raw_active; + context->was_active = active; - os_set_thread_name("libobs: graphics thread"); + profile_start(context->video_thread_name); - const char *video_thread_name = profile_store_name( - obs_get_profiler_name_store(), - "obs_graphics_thread(%g" NBSP "ms)", interval / 1000000.); - profile_register_root(video_thread_name, interval); + gs_enter_context(obs->video.graphics); + gs_begin_frame(); + gs_leave_context(); - srand((unsigned int)time(NULL)); + profile_start(tick_sources_name); + context->last_time = + tick_sources(obs->video.video_time, context->last_time); + profile_end(tick_sources_name); - for (;;) { - /* defer loop break to clean up sources */ - const bool stop_requested = - video_output_stopped(obs->video.video); + execute_graphics_tasks(); - uint64_t frame_start = os_gettime_ns(); - uint64_t frame_time_ns; - bool raw_active = obs->video.raw_active > 0; #ifdef _WIN32 - const bool gpu_active = obs->video.gpu_encoder_active > 0; - const bool active = raw_active || gpu_active; -#else - const bool gpu_active = 0; - const bool active = raw_active; + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } #endif - if (!was_active && active) - clear_base_frame_data(); - if (!raw_was_active && raw_active) - clear_raw_frame_data(); -#ifdef _WIN32 - if (!gpu_was_active && gpu_active) - clear_gpu_frame_data(); + profile_start(output_frame_name); + output_frame(raw_active, gpu_active); + profile_end(output_frame_name); - gpu_was_active = gpu_active; -#endif - raw_was_active = raw_active; - was_active = active; + profile_start(render_displays_name); + render_displays(); + profile_end(render_displays_name); - profile_start(video_thread_name); + frame_time_ns = os_gettime_ns() - frame_start; - gs_enter_context(obs->video.graphics); - gs_begin_frame(); - gs_leave_context(); + profile_end(context->video_thread_name); - profile_start(tick_sources_name); - last_time = tick_sources(obs->video.video_time, last_time); - profile_end(tick_sources_name); + profile_reenable_thread(); - execute_graphics_tasks(); + video_sleep(&obs->video, raw_active, gpu_active, &obs->video.video_time, + context->interval); -#ifdef _WIN32 - MSG msg; - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } -#endif + context->frame_time_total_ns += frame_time_ns; + context->fps_total_ns += (obs->video.video_time - context->last_time); + context->fps_total_frames++; - profile_start(output_frame_name); - output_frame(raw_active, gpu_active); - profile_end(output_frame_name); + if (context->fps_total_ns >= 1000000000ULL) { + obs->video.video_fps = + (double)context->fps_total_frames / + ((double)context->fps_total_ns / 1000000000.0); + obs->video.video_avg_frame_time_ns = + context->frame_time_total_ns / + (uint64_t)context->fps_total_frames; - profile_start(render_displays_name); - render_displays(); - profile_end(render_displays_name); + context->frame_time_total_ns = 0; + context->fps_total_ns = 0; + context->fps_total_frames = 0; + } - frame_time_ns = os_gettime_ns() - frame_start; + return !stop_requested; +} - profile_end(video_thread_name); +void *obs_graphics_thread(void *param) +{ +#ifdef _WIN32 + struct winrt_state winrt; + init_winrt_state(&winrt); +#endif // #ifdef _WIN32 - profile_reenable_thread(); + is_graphics_thread = true; - video_sleep(&obs->video, raw_active, gpu_active, - &obs->video.video_time, interval); + const uint64_t interval = video_output_get_frame_time(obs->video.video); - frame_time_total_ns += frame_time_ns; - fps_total_ns += (obs->video.video_time - last_time); - fps_total_frames++; + obs->video.video_time = os_gettime_ns(); + obs->video.video_frame_interval_ns = interval; - if (fps_total_ns >= 1000000000ULL) { - obs->video.video_fps = - (double)fps_total_frames / - ((double)fps_total_ns / 1000000000.0); - obs->video.video_avg_frame_time_ns = - frame_time_total_ns / - (uint64_t)fps_total_frames; + os_set_thread_name("libobs: graphics thread"); - frame_time_total_ns = 0; - fps_total_ns = 0; - fps_total_frames = 0; - } + const char *video_thread_name = profile_store_name( + obs_get_profiler_name_store(), + "obs_graphics_thread(%g" NBSP "ms)", interval / 1000000.); + profile_register_root(video_thread_name, interval); - if (stop_requested) - break; - } + srand((unsigned int)time(NULL)); + + struct obs_graphics_context context; + context.interval = video_output_get_frame_time(obs->video.video); + context.frame_time_total_ns = 0; + context.fps_total_ns = 0; + context.fps_total_frames = 0; + context.last_time = 0; +#ifdef _WIN32 + context.gpu_was_active = false; +#endif + context.raw_was_active = false; + context.was_active = false; + context.video_thread_name = video_thread_name; + +#ifdef __APPLE__ + while (obs_graphics_thread_loop_autorelease(&context)) +#else + while (obs_graphics_thread_loop(&context)) +#endif + ; #ifdef _WIN32 uninit_winrt_state(&winrt); diff --git a/libobs/obs.c b/libobs/obs.c index b4815951fcd73e4ef68b2393c243417cdf6d725b..0d939f7603dc479055f3de684ed49d77d4fd3f37 100644 --- a/libobs/obs.c +++ b/libobs/obs.c @@ -429,8 +429,13 @@ static int obs_init_video(struct obs_video_info *ovi) if (pthread_mutex_init(&video->task_mutex, NULL) < 0) return OBS_VIDEO_FAIL; +#ifdef __APPLE__ + errorcode = pthread_create(&video->video_thread, NULL, + obs_graphics_thread_autorelease, obs); +#else errorcode = pthread_create(&video->video_thread, NULL, obs_graphics_thread, obs); +#endif if (errorcode != 0) return OBS_VIDEO_FAIL;