From bef3828ce2c7e0fe00437965c6bcde5398ca7f0a Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Thu, 28 Apr 2011 10:45:44 +0100 Subject: [PATCH] VST mouse hook fix. AU assertion fix. --- juce_amalgamated.cpp | 318 +++++++++--------- juce_amalgamated.h | 44 +-- .../plugin_client/VST/juce_VST_Wrapper.cpp | 17 +- .../formats/juce_AudioUnitPluginFormat.mm | 11 +- src/core/juce_StandardHeader.h | 2 +- .../special/juce_OpenGLComponent.cpp | 311 ++++++++--------- .../components/special/juce_OpenGLComponent.h | 42 +-- src/native/mac/juce_mac_OpenGLComponent.mm | 2 +- 8 files changed, 372 insertions(+), 375 deletions(-) diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index ddc47e1975..69fdc1892f 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -31827,11 +31827,10 @@ namespace AudioUnitFormatHelpers const String osTypeToString (OSType type) { - char s[4]; - s[0] = (char) (((uint32) type) >> 24); - s[1] = (char) (((uint32) type) >> 16); - s[2] = (char) (((uint32) type) >> 8); - s[3] = (char) ((uint32) type); + const juce_wchar s[4] = { (juce_wchar) (((uint32) type) >> 24), + (juce_wchar) (((uint32) type) >> 16), + (juce_wchar) (((uint32) type) >> 8), + (juce_wchar) ((uint32) type) }; return String (s, 4); } @@ -31842,7 +31841,7 @@ namespace AudioUnitFormatHelpers return (((OSType) (unsigned char) s[0]) << 24) | (((OSType) (unsigned char) s[1]) << 16) | (((OSType) (unsigned char) s[2]) << 8) - | ((OSType) (unsigned char) s[3]); + | ((OSType) (unsigned char) s[3]); } static const char* auIdentifierPrefix = "AudioUnit:"; @@ -77111,10 +77110,41 @@ OpenGLContext* OpenGLContext::getCurrentContext() return nullptr; } -class OpenGLComponent::OpenGLComponentRenderThread : public Thread +class OpenGLComponent::OpenGLComponentWatcher : public ComponentMovementWatcher { public: + OpenGLComponentWatcher (OpenGLComponent* const owner_) + : ComponentMovementWatcher (owner_), + owner (owner_) + { + } + + void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) + { + owner->updateContextPosition(); + } + + void componentPeerChanged() + { + owner->recreateContextAsync(); + } + + void componentVisibilityChanged() + { + if (! owner->isShowing()) + owner->stopBackgroundThread(); + } + +private: + OpenGLComponent* const owner; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponentWatcher); +}; + +class OpenGLComponent::OpenGLComponentRenderThread : public Thread +{ +public: OpenGLComponentRenderThread (OpenGLComponent& owner_) : Thread ("OpenGL Render"), owner (owner_) @@ -77134,7 +77164,9 @@ public: Thread::sleep (jmax (1, 20 - elapsed)); } - owner.stopRenderThread(); + #if JUCE_LINUX + owner.deleteContext(); + #endif } private: @@ -77143,49 +77175,34 @@ private: JUCE_DECLARE_NON_COPYABLE (OpenGLComponentRenderThread); }; -class OpenGLComponent::OpenGLComponentWatcher : public ComponentMovementWatcher, - public AsyncUpdater +void OpenGLComponent::startRenderThread() { -public: - - OpenGLComponentWatcher (OpenGLComponent* const owner_) - : ComponentMovementWatcher (owner_), - owner (owner_) - { - } + if (renderThread == nullptr) + renderThread = new OpenGLComponentRenderThread (*this); - void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) - { - owner->updateContextPosition(); - } - - void componentPeerChanged() - { - owner->stopRendering(); - } - - void componentVisibilityChanged() - { - if (! owner->isShowing()) - owner->stopRendering(); - } + renderThread->startThread (6); +} - void handleAsyncUpdate() +void OpenGLComponent::stopRenderThread() +{ + if (renderThread != nullptr) { - owner->stopRendering(); + renderThread->stopThread (5000); + renderThread = nullptr; } -private: - OpenGLComponent* const owner; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponentWatcher); -}; + #if ! JUCE_LINUX + deleteContext(); + #endif +} -OpenGLComponent::OpenGLComponent (const OpenGLType type_) +OpenGLComponent::OpenGLComponent (const OpenGLType type_, const bool useBackgroundThread) : type (type_), contextToShareListsWith (nullptr), needToUpdateViewport (true), - useThread (false) + needToDeleteContext (false), + threadStarted (false), + useThread (useBackgroundThread) { setOpaque (true); componentWatcher = new OpenGLComponentWatcher (this); @@ -77193,39 +77210,10 @@ OpenGLComponent::OpenGLComponent (const OpenGLType type_) OpenGLComponent::~OpenGLComponent() { - stopRendering(); - renderThread = nullptr; + stopBackgroundThread(); componentWatcher = nullptr; } -void OpenGLComponent::deleteContext() -{ - const ScopedLock sl (contextLock); - context = nullptr; -} - -void OpenGLComponent::updateContextPosition() -{ - needToUpdateViewport = true; - - if (getWidth() > 0 && getHeight() > 0) - { - Component* const topComp = getTopLevelComponent(); - - if (topComp->getPeer() != nullptr) - { - const ScopedLock sl (contextLock); - - if (context != nullptr) - context->updateWindowPosition (getScreenX() - topComp->getScreenX(), - getScreenY() - topComp->getScreenY(), - getWidth(), - getHeight(), - topComp->getHeight()); - } - } -} - const OpenGLPixelFormat OpenGLComponent::getPixelFormat() const { OpenGLPixelFormat pf; @@ -77242,8 +77230,8 @@ void OpenGLComponent::setPixelFormat (const OpenGLPixelFormat& formatToUse) if (! (preferredPixelFormat == formatToUse)) { const ScopedLock sl (contextLock); - deleteContext(); preferredPixelFormat = formatToUse; + recreateContextAsync(); } } @@ -77252,95 +77240,145 @@ void OpenGLComponent::shareWith (OpenGLContext* c) if (contextToShareListsWith != c) { const ScopedLock sl (contextLock); - deleteContext(); contextToShareListsWith = c; + recreateContextAsync(); } } +void OpenGLComponent::recreateContextAsync() +{ + const ScopedLock sl (contextLock); + needToDeleteContext = true; + repaint(); +} + bool OpenGLComponent::makeCurrentContextActive() { + return context != nullptr && context->makeActive(); +} + +void OpenGLComponent::makeCurrentContextInactive() +{ + if (context != nullptr) + context->makeInactive(); +} + +bool OpenGLComponent::isActiveContext() const noexcept +{ + return context != nullptr && context->isActive(); +} + +void OpenGLComponent::swapBuffers() +{ + if (context != nullptr) + context->swapBuffers(); +} + +void OpenGLComponent::updateContext() +{ + if (needToDeleteContext) + deleteContext(); + if (context == nullptr) { const ScopedLock sl (contextLock); - if (isShowing() && getTopLevelComponent()->getPeer() != nullptr) + if (context == nullptr) { context = createContext(); if (context != nullptr) { + #if JUCE_LINUX if (! useThread) + #endif updateContextPosition(); if (context->makeActive()) + { newOpenGLContextCreated(); + context->makeInactive(); + } } } } - - return context != nullptr && context->makeActive(); } -void OpenGLComponent::makeCurrentContextInactive() +void OpenGLComponent::deleteContext() { + const ScopedLock sl (contextLock); if (context != nullptr) - context->makeInactive(); -} + { + if (context->makeActive()) + { + releaseOpenGLContext(); + context->makeInactive(); + } -bool OpenGLComponent::isActiveContext() const noexcept -{ - return context != nullptr && context->isActive(); + context = nullptr; + } + + needToDeleteContext = false; } -void OpenGLComponent::swapBuffers() +void OpenGLComponent::updateContextPosition() { - if (context != nullptr) - context->swapBuffers(); + needToUpdateViewport = true; + + if (getWidth() > 0 && getHeight() > 0) + { + Component* const topComp = getTopLevelComponent(); + + if (topComp->getPeer() != nullptr) + { + const ScopedLock sl (contextLock); + + if (context != nullptr) + context->updateWindowPosition (getScreenX() - topComp->getScreenX(), + getScreenY() - topComp->getScreenY(), + getWidth(), + getHeight(), + topComp->getHeight()); + } + } } -void OpenGLComponent::setUsingDedicatedThread (bool useDedicatedThread) noexcept +void OpenGLComponent::stopBackgroundThread() { - useThread = useDedicatedThread; + if (threadStarted) + { + stopRenderThread(); + threadStarted = false; + } } void OpenGLComponent::paint (Graphics&) { + ComponentPeer* const peer = getPeer(); + if (useThread) { - if (renderThread == nullptr) - renderThread = new OpenGLComponentRenderThread (*this); - - if (! renderThread->isThreadRunning()) + if (peer != nullptr && isShowing()) { - componentWatcher->handleUpdateNowIfNeeded(); // may still be shutting down as well - #if ! JUCE_LINUX - // Except for Linux, create the context first - const ScopedLock sl (contextLock); - - if (makeCurrentContextActive()) // Make active just to create - makeCurrentContextInactive(); + updateContext(); #endif - startRenderThread(); + if (! threadStarted) + { + threadStarted = true; + startRenderThread(); + } } - - // fall-through and update the masking region } else { - if (renderThread != nullptr) - { - stopRendering(); - renderThread = nullptr; - } + updateContext(); if (! renderAndSwapBuffers()) return; } - ComponentPeer* const peer = getPeer(); - if (peer != nullptr) { const Point topLeft (getScreenPosition() - peer->getScreenPosition()); @@ -77348,64 +77386,32 @@ void OpenGLComponent::paint (Graphics&) } } -void OpenGLComponent::startRenderThread() -{ - // If this is overriden, user will provide a thread. The renderThread object will - // not be used - jassert (renderThread != nullptr); - - renderThread->startThread (6); -} - -void OpenGLComponent::stopRenderThread() +bool OpenGLComponent::renderAndSwapBuffers() { - releaseOpenGLContext(); + const ScopedLock sl (contextLock); #if JUCE_LINUX - deleteContext(); - #else - makeCurrentContextInactive(); + updateContext(); #endif - componentWatcher->triggerAsyncUpdate(); -} - -bool OpenGLComponent::renderAndSwapBuffers() -{ - const ScopedLock sl (contextLock); + if (context != nullptr) + { + if (! makeCurrentContextActive()) + return false; - if (! makeCurrentContextActive()) - return false; + if (needToUpdateViewport) + { + needToUpdateViewport = false; + juce_glViewport (getWidth(), getHeight()); + } - if (needToUpdateViewport) - { - needToUpdateViewport = false; - juce_glViewport (getWidth(), getHeight()); + renderOpenGL(); + swapBuffers(); } - renderOpenGL(); - swapBuffers(); - return true; } -void OpenGLComponent::stopRendering() -{ - componentWatcher->cancelPendingUpdate(); - - if (renderThread != nullptr) - renderThread->stopThread (5000); - - if (context != nullptr && makeCurrentContextActive()) - { - // On Linux, when threaded, context will have already been cleared - const ScopedLock sl (contextLock); - - releaseOpenGLContext(); - deleteContext(); - } -} - void OpenGLComponent::internalRepaint (int x, int y, int w, int h) { Component::internalRepaint (x, y, w, h); @@ -275158,7 +275164,7 @@ private: OpenGLContext* OpenGLComponent::createContext() { ScopedPointer c (new WindowedGLContext (*this, preferredPixelFormat, - contextToShareListsWith != nullptr ? (NSOpenGLContext*) contextToShareListsWith->getRawContext() : 0)); + contextToShareListsWith != nullptr ? (NSOpenGLContext*) contextToShareListsWith->getRawContext() : nil)); return (c->renderContext != nil) ? c.release() : nullptr; } @@ -281055,7 +281061,7 @@ private: OpenGLContext* OpenGLComponent::createContext() { ScopedPointer c (new WindowedGLContext (*this, preferredPixelFormat, - contextToShareListsWith != nullptr ? (NSOpenGLContext*) contextToShareListsWith->getRawContext() : 0)); + contextToShareListsWith != nullptr ? (NSOpenGLContext*) contextToShareListsWith->getRawContext() : nil)); return (c->renderContext != nil) ? c.release() : nullptr; } diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 79e76c405b..774345364d 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -73,7 +73,7 @@ namespace JuceDummyNamespace {} */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 53 -#define JUCE_BUILDNUMBER 82 +#define JUCE_BUILDNUMBER 83 /** Current Juce version number. @@ -64090,8 +64090,13 @@ public: #endif }; - /** Creates an OpenGLComponent. */ - OpenGLComponent (OpenGLType type = openGLDefault); + /** Creates an OpenGLComponent. + If useBackgroundThread is true, the component will launch a background thread + to do the rendering. If false, then renderOpenGL() will be called as part of the + normal paint() method. + */ + OpenGLComponent (OpenGLType type = openGLDefault, + bool useBackgroundThread = false); /** Destructor. */ ~OpenGLComponent(); @@ -64126,14 +64131,9 @@ public: /** Flips the openGL buffers over. */ void swapBuffers(); - /** Indicates whether the component should perform its rendering on a background thread. - By default, this is set to false, and the renderOpenGL() callback happens on the main - UI thread, in response to a repaint. If set to true, then the component will create - a background thread which it uses to repeatedly call renderOpenGL(). + /** Returns true if the component is performing the rendering on a background thread. + This property is specified in the constructor. */ - void setUsingDedicatedThread (bool useDedicatedThread) noexcept; - - /** Returns true if the component is performing the rendering on a background thread. */ bool isUsingDedicatedThread() const noexcept { return useThread; } /** This replaces the normal paint() callback - use it to draw your openGL stuff. @@ -64211,7 +64211,7 @@ public: */ void makeCurrentContextInactive(); - /** Returns true if this component is the active openGL context for the + /** Returns true if this component's context is the active openGL context for the current thread. @see OpenGLContext::isActive @@ -64219,12 +64219,7 @@ public: bool isActiveContext() const noexcept; /** Calls the rendering callback, and swaps the buffers afterwards. - This is called automatically by paint() when the component needs to be rendered. - - It can be overridden if you need to decouple the rendering from the paint callback - and render with a custom thread. - Returns true if the operation succeeded. */ virtual bool renderAndSwapBuffers(); @@ -64238,6 +64233,12 @@ public: */ CriticalSection& getContextLock() noexcept { return contextLock; } + /** Delete the context. + You should only need to call this if you've written a custom thread - if so, make + sure that your thread calls this before it terminates. + */ + void deleteContext(); + /** Returns the native handle of an embedded heavyweight window, if there is one. E.g. On windows, this will return the HWND of the sub-window containing @@ -64245,10 +64246,6 @@ public: */ void* getNativeWindowHandle() const; - /** Delete the context. - This can be called back on the same thread that created the context. */ - void deleteContext(); - protected: /** Kicks off a thread to start rendering. The default implementation creates and manages an internal thread that tries @@ -64282,12 +64279,15 @@ private: CriticalSection contextLock; OpenGLPixelFormat preferredPixelFormat; - bool needToUpdateViewport, useThread; + bool needToUpdateViewport, needToDeleteContext, threadStarted; + const bool useThread; OpenGLContext* createContext(); + void updateContext(); void updateContextPosition(); + void stopBackgroundThread(); + void recreateContextAsync(); void internalRepaint (int x, int y, int w, int h); - void stopRendering(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponent); }; diff --git a/src/audio/plugin_client/VST/juce_VST_Wrapper.cpp b/src/audio/plugin_client/VST/juce_VST_Wrapper.cpp index 10a65b75e0..8b7035f8da 100644 --- a/src/audio/plugin_client/VST/juce_VST_Wrapper.cpp +++ b/src/audio/plugin_client/VST/juce_VST_Wrapper.cpp @@ -210,22 +210,9 @@ namespace LRESULT CALLBACK mouseWheelHookCallback (int nCode, WPARAM wParam, LPARAM lParam) { - #ifndef WM_MOUSEWHEEL - #define WM_MOUSEWHEEL 0x20a - - struct MSLLHOOKSTRUCT - { - POINT pt; - DWORD mouseData; - DWORD flags; - DWORD time; - ULONG_PTR dwExtraInfo; - }; - #endif - if (nCode >= 0 && wParam == WM_MOUSEWHEEL) { - const MSLLHOOKSTRUCT& hs = *(MSLLHOOKSTRUCT*) lParam; + const MOUSEHOOKSTRUCTEX& hs = *(MOUSEHOOKSTRUCTEX*) lParam; Component* const comp = Desktop::getInstance().findComponentAt (Point (hs.pt.x, hs.pt.y)); @@ -240,7 +227,7 @@ namespace void registerMouseWheelHook() { if (mouseHookUsers++ == 0) - mouseWheelHook = SetWindowsHookEx (7 /*WH_MOUSE*/, mouseWheelHookCallback, + mouseWheelHook = SetWindowsHookEx (WH_MOUSE, mouseWheelHookCallback, (HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle(), GetCurrentThreadId()); } diff --git a/src/audio/plugin_host/formats/juce_AudioUnitPluginFormat.mm b/src/audio/plugin_host/formats/juce_AudioUnitPluginFormat.mm index 5ebd93ecac..b810e738b0 100644 --- a/src/audio/plugin_host/formats/juce_AudioUnitPluginFormat.mm +++ b/src/audio/plugin_host/formats/juce_AudioUnitPluginFormat.mm @@ -72,11 +72,10 @@ namespace AudioUnitFormatHelpers const String osTypeToString (OSType type) { - char s[4]; - s[0] = (char) (((uint32) type) >> 24); - s[1] = (char) (((uint32) type) >> 16); - s[2] = (char) (((uint32) type) >> 8); - s[3] = (char) ((uint32) type); + const juce_wchar s[4] = { (juce_wchar) (((uint32) type) >> 24), + (juce_wchar) (((uint32) type) >> 16), + (juce_wchar) (((uint32) type) >> 8), + (juce_wchar) ((uint32) type) }; return String (s, 4); } @@ -87,7 +86,7 @@ namespace AudioUnitFormatHelpers return (((OSType) (unsigned char) s[0]) << 24) | (((OSType) (unsigned char) s[1]) << 16) | (((OSType) (unsigned char) s[2]) << 8) - | ((OSType) (unsigned char) s[3]); + | ((OSType) (unsigned char) s[3]); } static const char* auIdentifierPrefix = "AudioUnit:"; diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h index 5ef1766c33..f3e90695f8 100644 --- a/src/core/juce_StandardHeader.h +++ b/src/core/juce_StandardHeader.h @@ -33,7 +33,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 53 -#define JUCE_BUILDNUMBER 82 +#define JUCE_BUILDNUMBER 83 /** Current Juce version number. diff --git a/src/gui/components/special/juce_OpenGLComponent.cpp b/src/gui/components/special/juce_OpenGLComponent.cpp index 5faa2a8926..02dfa413a3 100644 --- a/src/gui/components/special/juce_OpenGLComponent.cpp +++ b/src/gui/components/special/juce_OpenGLComponent.cpp @@ -131,10 +131,44 @@ OpenGLContext* OpenGLContext::getCurrentContext() } //============================================================================== -class OpenGLComponent::OpenGLComponentRenderThread : public Thread +class OpenGLComponent::OpenGLComponentWatcher : public ComponentMovementWatcher { public: //============================================================================== + OpenGLComponentWatcher (OpenGLComponent* const owner_) + : ComponentMovementWatcher (owner_), + owner (owner_) + { + } + + //============================================================================== + void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) + { + owner->updateContextPosition(); + } + + void componentPeerChanged() + { + owner->recreateContextAsync(); + } + + void componentVisibilityChanged() + { + if (! owner->isShowing()) + owner->stopBackgroundThread(); + } + + //============================================================================== +private: + OpenGLComponent* const owner; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponentWatcher); +}; + +//============================================================================== +class OpenGLComponent::OpenGLComponentRenderThread : public Thread +{ +public: OpenGLComponentRenderThread (OpenGLComponent& owner_) : Thread ("OpenGL Render"), owner (owner_) @@ -154,64 +188,46 @@ public: Thread::sleep (jmax (1, 20 - elapsed)); } - owner.stopRenderThread(); + #if JUCE_LINUX + owner.deleteContext(); + #endif } - //============================================================================== private: OpenGLComponent& owner; JUCE_DECLARE_NON_COPYABLE (OpenGLComponentRenderThread); }; - -//============================================================================== -class OpenGLComponent::OpenGLComponentWatcher : public ComponentMovementWatcher, - public AsyncUpdater +void OpenGLComponent::startRenderThread() { -public: - //============================================================================== - OpenGLComponentWatcher (OpenGLComponent* const owner_) - : ComponentMovementWatcher (owner_), - owner (owner_) - { - } - - //============================================================================== - void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) - { - owner->updateContextPosition(); - } - - void componentPeerChanged() - { - owner->stopRendering(); - } + if (renderThread == nullptr) + renderThread = new OpenGLComponentRenderThread (*this); - void componentVisibilityChanged() - { - if (! owner->isShowing()) - owner->stopRendering(); - } + renderThread->startThread (6); +} - void handleAsyncUpdate() +void OpenGLComponent::stopRenderThread() +{ + if (renderThread != nullptr) { - owner->stopRendering(); + renderThread->stopThread (5000); + renderThread = nullptr; } - //============================================================================== -private: - OpenGLComponent* const owner; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponentWatcher); -}; + #if ! JUCE_LINUX + deleteContext(); + #endif +} //============================================================================== -OpenGLComponent::OpenGLComponent (const OpenGLType type_) +OpenGLComponent::OpenGLComponent (const OpenGLType type_, const bool useBackgroundThread) : type (type_), contextToShareListsWith (nullptr), needToUpdateViewport (true), - useThread (false) + needToDeleteContext (false), + threadStarted (false), + useThread (useBackgroundThread) { setOpaque (true); componentWatcher = new OpenGLComponentWatcher (this); @@ -219,39 +235,10 @@ OpenGLComponent::OpenGLComponent (const OpenGLType type_) OpenGLComponent::~OpenGLComponent() { - stopRendering(); - renderThread = nullptr; + stopBackgroundThread(); componentWatcher = nullptr; } -void OpenGLComponent::deleteContext() -{ - const ScopedLock sl (contextLock); - context = nullptr; -} - -void OpenGLComponent::updateContextPosition() -{ - needToUpdateViewport = true; - - if (getWidth() > 0 && getHeight() > 0) - { - Component* const topComp = getTopLevelComponent(); - - if (topComp->getPeer() != nullptr) - { - const ScopedLock sl (contextLock); - - if (context != nullptr) - context->updateWindowPosition (getScreenX() - topComp->getScreenX(), - getScreenY() - topComp->getScreenY(), - getWidth(), - getHeight(), - topComp->getHeight()); - } - } -} - const OpenGLPixelFormat OpenGLComponent::getPixelFormat() const { OpenGLPixelFormat pf; @@ -268,8 +255,8 @@ void OpenGLComponent::setPixelFormat (const OpenGLPixelFormat& formatToUse) if (! (preferredPixelFormat == formatToUse)) { const ScopedLock sl (contextLock); - deleteContext(); preferredPixelFormat = formatToUse; + recreateContextAsync(); } } @@ -278,95 +265,145 @@ void OpenGLComponent::shareWith (OpenGLContext* c) if (contextToShareListsWith != c) { const ScopedLock sl (contextLock); - deleteContext(); contextToShareListsWith = c; + recreateContextAsync(); } } +void OpenGLComponent::recreateContextAsync() +{ + const ScopedLock sl (contextLock); + needToDeleteContext = true; + repaint(); +} + bool OpenGLComponent::makeCurrentContextActive() { + return context != nullptr && context->makeActive(); +} + +void OpenGLComponent::makeCurrentContextInactive() +{ + if (context != nullptr) + context->makeInactive(); +} + +bool OpenGLComponent::isActiveContext() const noexcept +{ + return context != nullptr && context->isActive(); +} + +void OpenGLComponent::swapBuffers() +{ + if (context != nullptr) + context->swapBuffers(); +} + +void OpenGLComponent::updateContext() +{ + if (needToDeleteContext) + deleteContext(); + if (context == nullptr) { const ScopedLock sl (contextLock); - if (isShowing() && getTopLevelComponent()->getPeer() != nullptr) + if (context == nullptr) { context = createContext(); if (context != nullptr) { + #if JUCE_LINUX if (! useThread) + #endif updateContextPosition(); if (context->makeActive()) + { newOpenGLContextCreated(); + context->makeInactive(); + } } } } - - return context != nullptr && context->makeActive(); } -void OpenGLComponent::makeCurrentContextInactive() +void OpenGLComponent::deleteContext() { + const ScopedLock sl (contextLock); if (context != nullptr) - context->makeInactive(); -} + { + if (context->makeActive()) + { + releaseOpenGLContext(); + context->makeInactive(); + } -bool OpenGLComponent::isActiveContext() const noexcept -{ - return context != nullptr && context->isActive(); + context = nullptr; + } + + needToDeleteContext = false; } -void OpenGLComponent::swapBuffers() +void OpenGLComponent::updateContextPosition() { - if (context != nullptr) - context->swapBuffers(); + needToUpdateViewport = true; + + if (getWidth() > 0 && getHeight() > 0) + { + Component* const topComp = getTopLevelComponent(); + + if (topComp->getPeer() != nullptr) + { + const ScopedLock sl (contextLock); + + if (context != nullptr) + context->updateWindowPosition (getScreenX() - topComp->getScreenX(), + getScreenY() - topComp->getScreenY(), + getWidth(), + getHeight(), + topComp->getHeight()); + } + } } -void OpenGLComponent::setUsingDedicatedThread (bool useDedicatedThread) noexcept +void OpenGLComponent::stopBackgroundThread() { - useThread = useDedicatedThread; + if (threadStarted) + { + stopRenderThread(); + threadStarted = false; + } } void OpenGLComponent::paint (Graphics&) { + ComponentPeer* const peer = getPeer(); + if (useThread) { - if (renderThread == nullptr) - renderThread = new OpenGLComponentRenderThread (*this); - - if (! renderThread->isThreadRunning()) + if (peer != nullptr && isShowing()) { - componentWatcher->handleUpdateNowIfNeeded(); // may still be shutting down as well - #if ! JUCE_LINUX - // Except for Linux, create the context first - const ScopedLock sl (contextLock); - - if (makeCurrentContextActive()) // Make active just to create - makeCurrentContextInactive(); + updateContext(); #endif - startRenderThread(); + if (! threadStarted) + { + threadStarted = true; + startRenderThread(); + } } - - // fall-through and update the masking region } else { - if (renderThread != nullptr) - { - stopRendering(); - renderThread = nullptr; - } + updateContext(); if (! renderAndSwapBuffers()) return; } - ComponentPeer* const peer = getPeer(); - if (peer != nullptr) { const Point topLeft (getScreenPosition() - peer->getScreenPosition()); @@ -374,64 +411,32 @@ void OpenGLComponent::paint (Graphics&) } } -void OpenGLComponent::startRenderThread() -{ - // If this is overriden, user will provide a thread. The renderThread object will - // not be used - jassert (renderThread != nullptr); - - renderThread->startThread (6); -} - -void OpenGLComponent::stopRenderThread() +bool OpenGLComponent::renderAndSwapBuffers() { - releaseOpenGLContext(); + const ScopedLock sl (contextLock); #if JUCE_LINUX - deleteContext(); - #else - makeCurrentContextInactive(); + updateContext(); #endif - componentWatcher->triggerAsyncUpdate(); -} - -bool OpenGLComponent::renderAndSwapBuffers() -{ - const ScopedLock sl (contextLock); + if (context != nullptr) + { + if (! makeCurrentContextActive()) + return false; - if (! makeCurrentContextActive()) - return false; + if (needToUpdateViewport) + { + needToUpdateViewport = false; + juce_glViewport (getWidth(), getHeight()); + } - if (needToUpdateViewport) - { - needToUpdateViewport = false; - juce_glViewport (getWidth(), getHeight()); + renderOpenGL(); + swapBuffers(); } - renderOpenGL(); - swapBuffers(); - return true; } -void OpenGLComponent::stopRendering() -{ - componentWatcher->cancelPendingUpdate(); - - if (renderThread != nullptr) - renderThread->stopThread (5000); - - if (context != nullptr && makeCurrentContextActive()) - { - // On Linux, when threaded, context will have already been cleared - const ScopedLock sl (contextLock); - - releaseOpenGLContext(); - deleteContext(); - } -} - void OpenGLComponent::internalRepaint (int x, int y, int w, int h) { Component::internalRepaint (x, y, w, h); diff --git a/src/gui/components/special/juce_OpenGLComponent.h b/src/gui/components/special/juce_OpenGLComponent.h index 087db07932..c3c051f381 100644 --- a/src/gui/components/special/juce_OpenGLComponent.h +++ b/src/gui/components/special/juce_OpenGLComponent.h @@ -198,8 +198,13 @@ public: #endif }; - /** Creates an OpenGLComponent. */ - OpenGLComponent (OpenGLType type = openGLDefault); + /** Creates an OpenGLComponent. + If useBackgroundThread is true, the component will launch a background thread + to do the rendering. If false, then renderOpenGL() will be called as part of the + normal paint() method. + */ + OpenGLComponent (OpenGLType type = openGLDefault, + bool useBackgroundThread = false); /** Destructor. */ ~OpenGLComponent(); @@ -237,14 +242,9 @@ public: /** Flips the openGL buffers over. */ void swapBuffers(); - /** Indicates whether the component should perform its rendering on a background thread. - By default, this is set to false, and the renderOpenGL() callback happens on the main - UI thread, in response to a repaint. If set to true, then the component will create - a background thread which it uses to repeatedly call renderOpenGL(). + /** Returns true if the component is performing the rendering on a background thread. + This property is specified in the constructor. */ - void setUsingDedicatedThread (bool useDedicatedThread) noexcept; - - /** Returns true if the component is performing the rendering on a background thread. */ bool isUsingDedicatedThread() const noexcept { return useThread; } /** This replaces the normal paint() callback - use it to draw your openGL stuff. @@ -323,7 +323,7 @@ public: */ void makeCurrentContextInactive(); - /** Returns true if this component is the active openGL context for the + /** Returns true if this component's context is the active openGL context for the current thread. @see OpenGLContext::isActive @@ -333,12 +333,7 @@ public: //============================================================================== /** Calls the rendering callback, and swaps the buffers afterwards. - This is called automatically by paint() when the component needs to be rendered. - - It can be overridden if you need to decouple the rendering from the paint callback - and render with a custom thread. - Returns true if the operation succeeded. */ virtual bool renderAndSwapBuffers(); @@ -352,6 +347,12 @@ public: */ CriticalSection& getContextLock() noexcept { return contextLock; } + /** Delete the context. + You should only need to call this if you've written a custom thread - if so, make + sure that your thread calls this before it terminates. + */ + void deleteContext(); + //============================================================================== /** Returns the native handle of an embedded heavyweight window, if there is one. @@ -360,10 +361,6 @@ public: */ void* getNativeWindowHandle() const; - /** Delete the context. - This can be called back on the same thread that created the context. */ - void deleteContext(); - protected: /** Kicks off a thread to start rendering. The default implementation creates and manages an internal thread that tries @@ -398,12 +395,15 @@ private: CriticalSection contextLock; OpenGLPixelFormat preferredPixelFormat; - bool needToUpdateViewport, useThread; + bool needToUpdateViewport, needToDeleteContext, threadStarted; + const bool useThread; OpenGLContext* createContext(); + void updateContext(); void updateContextPosition(); + void stopBackgroundThread(); + void recreateContextAsync(); void internalRepaint (int x, int y, int w, int h); - void stopRendering(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponent); }; diff --git a/src/native/mac/juce_mac_OpenGLComponent.mm b/src/native/mac/juce_mac_OpenGLComponent.mm index e0e8ec8879..afcd096d94 100644 --- a/src/native/mac/juce_mac_OpenGLComponent.mm +++ b/src/native/mac/juce_mac_OpenGLComponent.mm @@ -271,7 +271,7 @@ private: OpenGLContext* OpenGLComponent::createContext() { ScopedPointer c (new WindowedGLContext (*this, preferredPixelFormat, - contextToShareListsWith != nullptr ? (NSOpenGLContext*) contextToShareListsWith->getRawContext() : 0)); + contextToShareListsWith != nullptr ? (NSOpenGLContext*) contextToShareListsWith->getRawContext() : nil)); return (c->renderContext != nil) ? c.release() : nullptr; }