diff --git a/build/linux/platform_specific_code/juce_linux_Windowing.cpp b/build/linux/platform_specific_code/juce_linux_Windowing.cpp index 4bacc3eb48..c8e2a155b7 100644 --- a/build/linux/platform_specific_code/juce_linux_Windowing.cpp +++ b/build/linux/platform_specific_code/juce_linux_Windowing.cpp @@ -2948,6 +2948,18 @@ public: glXSwapBuffers (display, embeddedWindow); } + bool setSwapInterval (const int numFramesPerSwap) + { + // xxx needs doing.. + return false; + } + + int getSwapInterval() const + { + // xxx needs doing.. + return 0; + } + void repaint() { } diff --git a/build/macosx/platform_specific_code/juce_mac_Windowing.cpp b/build/macosx/platform_specific_code/juce_mac_Windowing.cpp index a52b52af7c..9eb7a7000f 100644 --- a/build/macosx/platform_specific_code/juce_mac_Windowing.cpp +++ b/build/macosx/platform_specific_code/juce_mac_Windowing.cpp @@ -3401,6 +3401,18 @@ public: aglSwapBuffers (renderContext); } + bool setSwapInterval (const int numFramesPerSwap) + { + return aglSetInteger (renderContext, AGL_SWAP_INTERVAL, &numFramesPerSwap); + } + + int getSwapInterval() const + { + GLint numFrames = 0; + aglGetInteger (renderContext, AGL_SWAP_INTERVAL, &numFrames); + return numFrames; + } + void repaint() { } diff --git a/build/win32/platform_specific_code/juce_win32_Windowing.cpp b/build/win32/platform_specific_code/juce_win32_Windowing.cpp index 54c924ab8c..53bfc939c0 100644 --- a/build/win32/platform_specific_code/juce_win32_Windowing.cpp +++ b/build/win32/platform_specific_code/juce_win32_Windowing.cpp @@ -3037,6 +3037,8 @@ bool DragAndDropContainer::performExternalDragDropOfText (const String& text) typedef const char* (WINAPI* PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int* piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval); +typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void); #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 #define WGL_DRAW_TO_WINDOW_ARB 0x2001 @@ -3299,6 +3301,32 @@ public: SwapBuffers (dc); } + bool setSwapInterval (const int numFramesPerSwap) + { + StringArray availableExtensions; + getWglExtensions (dc, availableExtensions); + + PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = 0; + + return availableExtensions.contains ("WGL_EXT_swap_control") + && WGL_EXT_FUNCTION_INIT (PFNWGLSWAPINTERVALEXTPROC, wglSwapIntervalEXT) + && wglSwapIntervalEXT (numFramesPerSwap) != FALSE; + } + + int getSwapInterval() const + { + StringArray availableExtensions; + getWglExtensions (dc, availableExtensions); + + PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = 0; + + if (availableExtensions.contains ("WGL_EXT_swap_control") + && WGL_EXT_FUNCTION_INIT (PFNWGLGETSWAPINTERVALEXTPROC, wglGetSwapIntervalEXT)) + return wglGetSwapIntervalEXT(); + + return 0; + } + void findAlternativeOpenGLPixelFormats (OwnedArray & results) { jassert (isActive()); diff --git a/src/juce_appframework/gui/components/special/juce_OpenGLComponent.cpp b/src/juce_appframework/gui/components/special/juce_OpenGLComponent.cpp index 20239010ea..90eede3adb 100644 --- a/src/juce_appframework/gui/components/special/juce_OpenGLComponent.cpp +++ b/src/juce_appframework/gui/components/special/juce_OpenGLComponent.cpp @@ -93,7 +93,6 @@ public: { const ScopedLock sl (owner->getContextLock()); owner->deleteContext(); - owner->createContext(); } void componentVisibilityChanged (Component&) @@ -131,30 +130,6 @@ OpenGLComponent::~OpenGLComponent() delete componentWatcher; } -void OpenGLComponent::createContext() -{ - const ScopedLock sl (contextLock); - - jassert (context == 0); - - if (context == 0 && isShowing() && getTopLevelComponent()->getPeer() != 0) - { - context = OpenGLContext::createContextForWindow (this, - preferredPixelFormat, - componentToShareListsWith != 0 - ? componentToShareListsWith->context - : 0); - - if (context != 0) - { - updateContextPosition(); - - if (makeCurrentContextActive()) - newOpenGLContextCreated(); - } - } -} - void OpenGLComponent::deleteContext() { const ScopedLock sl (contextLock); @@ -173,9 +148,6 @@ void OpenGLComponent::updateContextPosition() { const ScopedLock sl (contextLock); - if (context == 0) - createContext(); - if (context != 0) context->updateWindowPosition (getScreenX() - topComp->getScreenX(), getScreenY() - topComp->getScreenY(), @@ -197,17 +169,14 @@ const OpenGLPixelFormat OpenGLComponent::getPixelFormat() const return pf; } -bool OpenGLComponent::setPixelFormat (const OpenGLPixelFormat& formatToUse) +void OpenGLComponent::setPixelFormat (const OpenGLPixelFormat& formatToUse) { - if (preferredPixelFormat == formatToUse) - return true; - - const ScopedLock sl (contextLock); - deleteContext(); - preferredPixelFormat = formatToUse; - createContext(); - - return context != 0; + if (! (preferredPixelFormat == formatToUse)) + { + const ScopedLock sl (contextLock); + deleteContext(); + preferredPixelFormat = formatToUse; + } } void OpenGLComponent::shareWith (OpenGLComponent* const comp) @@ -217,12 +186,33 @@ void OpenGLComponent::shareWith (OpenGLComponent* const comp) const ScopedLock sl (contextLock); deleteContext(); componentToShareListsWith = comp; - createContext(); } } bool OpenGLComponent::makeCurrentContextActive() { + if (context == 0) + { + const ScopedLock sl (contextLock); + + if (isShowing() && getTopLevelComponent()->getPeer() != 0) + { + context = OpenGLContext::createContextForWindow (this, + preferredPixelFormat, + componentToShareListsWith != 0 + ? componentToShareListsWith->context + : 0); + + if (context != 0) + { + updateContextPosition(); + + if (context->makeActive()) + newOpenGLContextCreated(); + } + } + } + return context != 0 && context->makeActive(); } diff --git a/src/juce_appframework/gui/components/special/juce_OpenGLComponent.h b/src/juce_appframework/gui/components/special/juce_OpenGLComponent.h index 91a4ec5bdb..54e4d8a754 100644 --- a/src/juce_appframework/gui/components/special/juce_OpenGLComponent.h +++ b/src/juce_appframework/gui/components/special/juce_OpenGLComponent.h @@ -110,6 +110,21 @@ public: /** Swaps the buffers (if the context can do this). */ virtual void swapBuffers() = 0; + /** Sets whether the context checks the vertical sync before swapping. + + The value is the number of frames to allow between buffer-swapping. This is + fairly system-dependent, but 0 turns off syncing, 1 makes it swap on frame-boundaries, + and greater numbers indicate that it should swap less often. + + Returns true if it sets the value successfully. + */ + virtual bool setSwapInterval (const int numFramesPerSwap) = 0; + + /** Returns the current swap-sync interval. + See setSwapInterval() for info about the value returned. + */ + virtual int getSwapInterval() const = 0; + //============================================================================== /** Returns the pixel format being used by this context. */ virtual const OpenGLPixelFormat getPixelFormat() const = 0; @@ -175,7 +190,7 @@ public: @see OpenGLPixelFormat::getAvailablePixelFormats() */ - bool setPixelFormat (const OpenGLPixelFormat& formatToUse); + void setPixelFormat (const OpenGLPixelFormat& formatToUse); /** Returns the pixel format that this component is currently using. */ const OpenGLPixelFormat getPixelFormat() const; @@ -207,6 +222,13 @@ public: You can use this callback as an opportunity to set up things like textures that your context needs. + New contexts are created on-demand by the makeCurrentContextActive() method - so + if the context is deleted, e.g. by changing the pixel format or window, no context + will be created until the next call to makeCurrentContextActive(), which will + synchronously create one and call this method. This means that if you're using + a non-GUI thread for rendering, you can make sure this method is be called by + your renderer thread. + When this callback happens, the context will already have been made current using the makeCurrentContextActive() method, so there's no need to call it again in your code. @@ -217,9 +239,11 @@ public: //============================================================================== /** Returns the context that will draw into this component. - This may return 0 if it failed to initialise properly, or if the component - is currently invisible. The context object may be deleted and a new one created - during the life of this component - see newOpenGLContextCreated(). + This may return 0 if the component is currently invisible or hasn't currently + got a context. The context object can be deleted and a new one created during + the lifetime of this component, and there may be times when it doesn't have one. + + @see newOpenGLContextCreated() */ OpenGLContext* getCurrentContext() const throw(); @@ -231,6 +255,10 @@ public: If this returns false, then the context isn't active, so you should avoid making any calls. + This call may actually create a context if one isn't currently initialised. If + it does this, it will also synchronously call the newOpenGLContextCreated() + method to let you initialise it as necessary. + @see OpenGLContext::makeActive */ bool makeCurrentContextActive(); @@ -289,7 +317,6 @@ private: OpenGLPixelFormat preferredPixelFormat; bool needToUpdateViewport; - void createContext(); void deleteContext(); void updateContextPosition(); void internalRepaint (int x, int y, int w, int h);