Răsfoiți Sursa

libobs: Use autoreleasepool for graphics thread

Apparently necessary to clean up macOS leaks.
jpark37 5 ani în urmă
părinte
comite
6aa50b3ef1
4 a modificat fișierele cu 138 adăugiri și 88 ștergeri
  1. 14 0
      libobs/obs-cocoa.m
  2. 20 0
      libobs/obs-internal.h
  3. 99 88
      libobs/obs-video.c
  4. 5 0
      libobs/obs.c

+ 14 - 0
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);
+	}
+}

+ 20 - 0
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);
 

+ 99 - 88
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);

+ 5 - 0
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;