Browse Source

Merge pull request #9435 from norihiro/qtdisplay-destroy-at-surface-event-3

Fix crash at render_display while shutdown on macOS
Lain 2 years ago
parent
commit
fee4f2dc48
3 changed files with 24 additions and 45 deletions
  1. 7 39
      UI/qt-display.cpp
  2. 7 2
      UI/qt-display.hpp
  3. 10 4
      UI/window-basic-main.cpp

+ 7 - 39
UI/qt-display.cpp

@@ -13,15 +13,11 @@
 #include <Windows.h>
 #endif
 
-#ifdef ENABLE_WAYLAND
-#include <obs-nix-platform.h>
-
 class SurfaceEventFilter : public QObject {
 	OBSQTDisplay *display;
-	int mTimerId;
 
 public:
-	SurfaceEventFilter(OBSQTDisplay *src) : display(src), mTimerId(0) {}
+	SurfaceEventFilter(OBSQTDisplay *src) : display(src) {}
 
 protected:
 	bool eventFilter(QObject *obj, QEvent *event) override
@@ -35,22 +31,12 @@ protected:
 				static_cast<QPlatformSurfaceEvent *>(event);
 
 			switch (surfaceEvent->surfaceEventType()) {
-			case QPlatformSurfaceEvent::SurfaceCreated:
-				if (display->windowHandle()->isExposed())
-					createOBSDisplay();
-				else
-					mTimerId = startTimer(67); // Arbitrary
-				break;
 			case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed:
 				display->DestroyDisplay();
 				break;
 			default:
 				break;
 			}
-
-			break;
-		case QEvent::Expose:
-			createOBSDisplay();
 			break;
 		default:
 			break;
@@ -58,25 +44,8 @@ protected:
 
 		return result;
 	}
-
-	void timerEvent(QTimerEvent *) override
-	{
-		createOBSDisplay(display->isVisible());
-	}
-
-private:
-	void createOBSDisplay(bool force = false)
-	{
-		display->CreateDisplay(force);
-		if (mTimerId > 0) {
-			killTimer(mTimerId);
-			mTimerId = 0;
-		}
-	}
 };
 
-#endif
-
 static inline long long color_to_int(const QColor &color)
 {
 	auto shift = [&](unsigned val, int shift) {
@@ -130,11 +99,7 @@ OBSQTDisplay::OBSQTDisplay(QWidget *parent, Qt::WindowFlags flags)
 	connect(windowHandle(), &QWindow::visibleChanged, windowVisible);
 	connect(windowHandle(), &QWindow::screenChanged, screenChanged);
 
-#ifdef ENABLE_WAYLAND
-	if (obs_get_nix_platform() == OBS_NIX_PLATFORM_WAYLAND)
-		windowHandle()->installEventFilter(
-			new SurfaceEventFilter(this));
-#endif
+	windowHandle()->installEventFilter(new SurfaceEventFilter(this));
 }
 
 QColor OBSQTDisplay::GetDisplayBackgroundColor() const
@@ -157,12 +122,15 @@ void OBSQTDisplay::UpdateDisplayBackgroundColor()
 	obs_display_set_background_color(display, backgroundColor);
 }
 
-void OBSQTDisplay::CreateDisplay(bool force)
+void OBSQTDisplay::CreateDisplay()
 {
 	if (display)
 		return;
 
-	if (!windowHandle()->isExposed() && !force)
+	if (destroying)
+		return;
+
+	if (!windowHandle()->isExposed())
 		return;
 
 	QSize size = GetPixelSize(this);

+ 7 - 2
UI/qt-display.hpp

@@ -12,6 +12,7 @@ class OBSQTDisplay : public QWidget {
 				   SetDisplayBackgroundColor)
 
 	OBSDisplay display;
+	bool destroying = false;
 
 	virtual void paintEvent(QPaintEvent *event) override;
 	virtual void moveEvent(QMoveEvent *event) override;
@@ -37,8 +38,12 @@ public:
 	QColor GetDisplayBackgroundColor() const;
 	void SetDisplayBackgroundColor(const QColor &color);
 	void UpdateDisplayBackgroundColor();
-	void CreateDisplay(bool force = false);
-	void DestroyDisplay() { display = nullptr; };
+	void CreateDisplay();
+	void DestroyDisplay()
+	{
+		display = nullptr;
+		destroying = true;
+	};
 
 	void OnMove();
 	void OnDisplayChange();

+ 10 - 4
UI/window-basic-main.cpp

@@ -5128,6 +5128,16 @@ void OBSBasic::closeEvent(QCloseEvent *event)
 
 	closing = true;
 
+	/* While closing, a resize event to OBSQTDisplay could be triggered.
+	 * The graphics thread on macOS dispatches a lambda function to be
+	 * executed asynchronously in the main thread. However, the display is
+	 * sometimes deleted before the lambda function is actually executed.
+	 * To avoid such a case, destroy displays earlier than others such as
+	 * deleting browser docks. */
+	ui->preview->DestroyDisplay();
+	if (program)
+		program->DestroyDisplay();
+
 	if (outputHandler->VirtualCamActive())
 		outputHandler->StopVirtualCam();
 
@@ -5154,10 +5164,6 @@ void OBSBasic::closeEvent(QCloseEvent *event)
 
 	delete extraBrowsers;
 
-	ui->preview->DestroyDisplay();
-	if (program)
-		program->DestroyDisplay();
-
 	config_set_string(App()->GlobalConfig(), "BasicWindow", "DockState",
 			  saveState().toBase64().constData());