Browse Source

TESTING: Run NTK events on separate thread

gh-pages
falkTX 10 years ago
parent
commit
68d3e353cc
3 changed files with 201 additions and 37 deletions
  1. +168
    -37
      dgl/ntk/NtkApp.hpp
  2. +25
    -0
      distrho/DistrhoUIMain.cpp
  3. +8
    -0
      distrho/src/DistrhoUIInternal.hpp

+ 168
- 37
dgl/ntk/NtkApp.hpp View File

@@ -18,6 +18,8 @@
#define DGL_NTK_APP_HPP_INCLUDED #define DGL_NTK_APP_HPP_INCLUDED


#include "../Base.hpp" #include "../Base.hpp"
#include "../../distrho/DistrhoUI.hpp"
#include "../../distrho/extra/d_thread.hpp"


#ifdef override #ifdef override
# define override_defined # define override_defined
@@ -35,36 +37,65 @@
# undef override_defined # undef override_defined
#endif #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 START_NAMESPACE_DGL


class NtkWindow; 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. DGL compatible App class that uses NTK instead of OpenGL.
@see App @see App
*/ */
class NtkApp
class NtkApp : d_Thread
{ {
public: public:
/** /**
Constructor. Constructor.
*/ */
NtkApp() 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 #ifdef DISTRHO_OS_LINUX
fl_open_display();
//XInitThreads();
#endif #endif
}

startThread();

for (; ! fInitialized;)
d_msleep(10);
} }


/** /**
@@ -72,20 +103,15 @@ public:
*/ */
~NtkApp() ~NtkApp()
{ {
DISTRHO_SAFE_ASSERT(! fIsRunning);

stopThread(-1);
fWindows.clear(); fWindows.clear();
} }


/** /**
Idle function. 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. Run the application event-loop until all Windows are closed.
@@ -93,9 +119,8 @@ public:
*/ */
void exec() void exec()
{ {
fIsRunning = true;
Fl::run();
fIsRunning = false;
while (isThreadRunning() && ! shouldThreadExit())
d_sleep(1);
} }


/** /**
@@ -104,13 +129,7 @@ public:
*/ */
void quit() 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 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: 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. */ /** @internal used by NtkWindow. */
void addWindow(Fl_Double_Window* const window) void addWindow(Fl_Double_Window* const window)
{ {
DISTRHO_SAFE_ASSERT_RETURN(window != nullptr,); 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); fWindows.push_back(window);
} }


@@ -144,15 +231,59 @@ private:
{ {
DISTRHO_SAFE_ASSERT_RETURN(window != nullptr,); DISTRHO_SAFE_ASSERT_RETURN(window != nullptr,);


const d_MutexLocker sl(fWindowMutex);
fWindows.remove(window); fWindows.remove(window);


if (fWindows.size() == 0) 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) DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NtkApp)
}; };

// ----------------------------------------------------------------------- // -----------------------------------------------------------------------


END_NAMESPACE_DGL END_NAMESPACE_DGL


+ 25
- 0
distrho/DistrhoUIMain.cpp View File

@@ -27,3 +27,28 @@
#elif defined(DISTRHO_PLUGIN_TARGET_VST) #elif defined(DISTRHO_PLUGIN_TARGET_VST)
// nothing // nothing
#endif #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

+ 8
- 0
distrho/src/DistrhoUIInternal.hpp View File

@@ -141,7 +141,11 @@ UI* createUiWrapper(void* const dspPtr, UIWindow* const window)
{ {
d_lastUiDspPtr = dspPtr; d_lastUiDspPtr = dspPtr;
d_lastUiWindow = window; d_lastUiWindow = window;
#if DISTRHO_UI_USE_NTK
UI* const ret = window->getApp().createUI((void*)createUI);
#else
UI* const ret = createUI(); UI* const ret = createUI();
#endif
d_lastUiDspPtr = nullptr; d_lastUiDspPtr = nullptr;
d_lastUiWindow = nullptr; d_lastUiWindow = nullptr;
return ret; return ret;
@@ -164,7 +168,11 @@ public:


~UIExporterWindow() ~UIExporterWindow()
{ {
#if DISTRHO_UI_USE_NTK
getApp().deleteUI(fUI);
#else
delete fUI; delete fUI;
#endif
} }


UI* getUI() const noexcept UI* getUI() const noexcept


Loading…
Cancel
Save