commit 68d3e353cc99ac2ca1e9e9f6642a687f3f4e97b7
parent dd490b380201d968d13db6b4cdbc52cf6cbdb14b
Author: falkTX <falktx@gmail.com>
Date: Tue, 7 Oct 2014 16:29:23 +0100
TESTING: Run NTK events on separate thread
Diffstat:
3 files changed, 201 insertions(+), 37 deletions(-)
diff --git a/dgl/ntk/NtkApp.hpp b/dgl/ntk/NtkApp.hpp
@@ -18,6 +18,8 @@
#define DGL_NTK_APP_HPP_INCLUDED
#include "../Base.hpp"
+#include "../../distrho/DistrhoUI.hpp"
+#include "../../distrho/extra/d_thread.hpp"
#ifdef override
# define override_defined
@@ -35,36 +37,65 @@
# undef override_defined
#endif
+struct ScopedDisplayLock {
+ ScopedDisplayLock()
+ {
+#ifdef DISTRHO_OS_LINUX
+ XLockDisplay(fl_display);
+#endif
+ }
+
+ ~ScopedDisplayLock()
+ {
+#ifdef DISTRHO_OS_LINUX
+ XUnlockDisplay(fl_display);
+#endif
+ }
+};
+
+// -----------------------------------------------------------------------
+
+namespace DISTRHO_NAMESPACE {
+ class UI;
+}
+
START_NAMESPACE_DGL
class NtkWindow;
+typedef DISTRHO_NAMESPACE::Mutex d_Mutex;
+typedef DISTRHO_NAMESPACE::MutexLocker d_MutexLocker;
+typedef DISTRHO_NAMESPACE::Thread d_Thread;
+typedef DISTRHO_NAMESPACE::UI d_UI;
+
// -----------------------------------------------------------------------
/**
DGL compatible App class that uses NTK instead of OpenGL.
@see App
*/
-class NtkApp
+class NtkApp : d_Thread
{
public:
/**
Constructor.
*/
NtkApp()
- : fIsRunning(true),
- fWindows()
+ : d_Thread("NtkApp"),
+ fWindows(),
+ fWindowMutex(),
+ fNextUI(),
+ fDoNextUI(false),
+ fInitialized(false)
{
- static bool initialized = false;
-
- if (! initialized)
- {
- initialized = true;
- fl_register_images();
#ifdef DISTRHO_OS_LINUX
- fl_open_display();
+ //XInitThreads();
#endif
- }
+
+ startThread();
+
+ for (; ! fInitialized;)
+ d_msleep(10);
}
/**
@@ -72,20 +103,15 @@ public:
*/
~NtkApp()
{
- DISTRHO_SAFE_ASSERT(! fIsRunning);
-
+ stopThread(-1);
fWindows.clear();
}
/**
Idle function.
- This calls the NTK event-loop once (and all idle callbacks).
+ This calls does nothing.
*/
- void idle()
- {
- Fl::check();
- Fl::flush();
- }
+ void idle() {}
/**
Run the application event-loop until all Windows are closed.
@@ -93,9 +119,8 @@ public:
*/
void exec()
{
- fIsRunning = true;
- Fl::run();
- fIsRunning = false;
+ while (isThreadRunning() && ! shouldThreadExit())
+ d_sleep(1);
}
/**
@@ -104,13 +129,7 @@ public:
*/
void quit()
{
- fIsRunning = false;
-
- for (std::list<Fl_Double_Window*>::reverse_iterator rit = fWindows.rbegin(), rite = fWindows.rend(); rit != rite; ++rit)
- {
- Fl_Double_Window* const window(*rit);
- window->hide();
- }
+ signalThreadShouldExit();
}
/**
@@ -119,23 +138,91 @@ public:
*/
bool isQuiting() const noexcept
{
- return !fIsRunning;
+ if (isThreadRunning() && ! shouldThreadExit())
+ return false;
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ Create UI on our separate thread.
+ Blocks until the UI is created and returns it.
+ */
+ d_UI* createUI(void* const func)
+ {
+ DISTRHO_SAFE_ASSERT_RETURN(isThreadRunning(), nullptr);
+ DISTRHO_SAFE_ASSERT_RETURN(! fDoNextUI, nullptr);
+
+ fNextUI.create = true;
+ fNextUI.func = (NextUI::UiFunc)func;
+ fDoNextUI = true;
+
+ for (; fDoNextUI;)
+ d_msleep(10);
+
+ return fNextUI.ui;
+ }
+
+ /**
+ Delete UI on our separate thread.
+ Blocks until the UI is deleted.
+ */
+ void deleteUI(d_UI* const ui)
+ {
+ DISTRHO_SAFE_ASSERT_RETURN(! fDoNextUI,);
+
+ fNextUI.create = false;
+ fNextUI.ui = ui;
+ fDoNextUI = true;
+
+ if (isThreadRunning())
+ {
+ for (; fDoNextUI;)
+ d_msleep(10);
+ }
+ else
+ {
+ fNextUI.run();
+ fDoNextUI = false;
+ }
}
+ // -------------------------------------------------------------------
+
private:
- bool fIsRunning;
- std::list<Fl_Double_Window*> fWindows;
+ struct NextUI {
+ typedef d_UI* (*UiFunc)();
- friend class NtkWindow;
+ bool create;
+
+ union {
+ UiFunc func;
+ d_UI* ui;
+ };
+
+ NextUI()
+ : create(false),
+ func(nullptr) {}
+
+ void run();
+ };
+
+ std::list<Fl_Double_Window*> fWindows;
+ d_Mutex fWindowMutex;
+ NextUI fNextUI;
+ volatile bool fDoNextUI;
+ volatile bool fInitialized;
/** @internal used by NtkWindow. */
void addWindow(Fl_Double_Window* const window)
{
DISTRHO_SAFE_ASSERT_RETURN(window != nullptr,);
- if (fWindows.size() == 0)
- fIsRunning = true;
+ if (fWindows.size() == 0 && ! isThreadRunning())
+ startThread();
+ const d_MutexLocker sl(fWindowMutex);
fWindows.push_back(window);
}
@@ -144,15 +231,59 @@ private:
{
DISTRHO_SAFE_ASSERT_RETURN(window != nullptr,);
+ const d_MutexLocker sl(fWindowMutex);
fWindows.remove(window);
if (fWindows.size() == 0)
- fIsRunning = false;
+ signalThreadShouldExit();
+ }
+
+ /** @internal */
+ void run() override
+ {
+ static bool initialized = false;
+
+ if (! initialized)
+ {
+ initialized = true;
+ fl_register_images();
+#ifdef DISTRHO_OS_LINUX
+ fl_open_display();
+#endif
+ }
+
+ fInitialized = true;
+
+ for (; ! shouldThreadExit();)
+ {
+ if (fDoNextUI)
+ {
+ const ScopedDisplayLock csdl;
+ fNextUI.run();
+ fDoNextUI = false;
+ }
+
+ const ScopedDisplayLock csdl;
+ Fl::check();
+ Fl::flush();
+
+ d_msleep(20);
+ }
+
+ const d_MutexLocker sl(fWindowMutex);
+ const ScopedDisplayLock csdl;
+
+ for (std::list<Fl_Double_Window*>::reverse_iterator rit = fWindows.rbegin(), rite = fWindows.rend(); rit != rite; ++rit)
+ {
+ Fl_Double_Window* const window(*rit);
+ window->hide();
+ }
}
+ friend class NtkWindow;
+
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NtkApp)
};
-
// -----------------------------------------------------------------------
END_NAMESPACE_DGL
diff --git a/distrho/DistrhoUIMain.cpp b/distrho/DistrhoUIMain.cpp
@@ -27,3 +27,28 @@
#elif defined(DISTRHO_PLUGIN_TARGET_VST)
// nothing
#endif
+
+#ifdef DGL_NTK_APP_HPP_INCLUDED
+
+START_NAMESPACE_DGL
+
+void NtkApp::NextUI::run()
+{
+ if (create)
+ {
+ d_stdout("Creating NTK UI in separate thread...");
+ d_UI* const ui2 = (func)();
+ ui = ui2;
+ }
+ else
+ {
+ d_stdout("Destroying NTK UI in separate thread...");
+ d_UI* const ui2 = ui;
+ ui = nullptr;
+ delete ui2;
+ }
+}
+
+END_NAMESPACE_DGL
+
+#endif
diff --git a/distrho/src/DistrhoUIInternal.hpp b/distrho/src/DistrhoUIInternal.hpp
@@ -141,7 +141,11 @@ UI* createUiWrapper(void* const dspPtr, UIWindow* const window)
{
d_lastUiDspPtr = dspPtr;
d_lastUiWindow = window;
+#if DISTRHO_UI_USE_NTK
+ UI* const ret = window->getApp().createUI((void*)createUI);
+#else
UI* const ret = createUI();
+#endif
d_lastUiDspPtr = nullptr;
d_lastUiWindow = nullptr;
return ret;
@@ -164,7 +168,11 @@ public:
~UIExporterWindow()
{
+#if DISTRHO_UI_USE_NTK
+ getApp().deleteUI(fUI);
+#else
delete fUI;
+#endif
}
UI* getUI() const noexcept