mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
OpenGL tweaks, including fix for flickering GL windows when resizing in OSX.
This commit is contained in:
parent
4d4cc13a46
commit
cf781ecb75
3 changed files with 86 additions and 116 deletions
|
|
@ -23,87 +23,6 @@
|
|||
==============================================================================
|
||||
*/
|
||||
|
||||
struct ThreadSafeNSOpenGLViewClass : public ObjCClass <NSOpenGLView>
|
||||
{
|
||||
ThreadSafeNSOpenGLViewClass() : ObjCClass <NSOpenGLView> ("JUCEGLView_")
|
||||
{
|
||||
addIvar <CriticalSection*> ("lock");
|
||||
addIvar <BOOL> ("needsUpdate");
|
||||
|
||||
addMethod (@selector (update), update, "v@:");
|
||||
addMethod (@selector (reshape), reshape, "v@:");
|
||||
addMethod (@selector (_surfaceNeedsUpdate:), surfaceNeedsUpdate, "v@:@");
|
||||
addMethod (@selector (rightMouseDown:), rightMouseDown, "v@:@");
|
||||
addMethod (@selector (rightMouseUp:), rightMouseUp, "v@:@");
|
||||
addMethod (@selector (acceptsFirstMouse:), acceptsFirstMouse, "v@:@");
|
||||
|
||||
registerClass();
|
||||
}
|
||||
|
||||
static void init (id self)
|
||||
{
|
||||
object_setInstanceVariable (self, "lock", new CriticalSection());
|
||||
|
||||
#if defined (MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7)
|
||||
if ([self respondsToSelector: @selector (setWantsBestResolutionOpenGLSurface:)])
|
||||
[self setWantsBestResolutionOpenGLSurface: YES];
|
||||
#endif
|
||||
|
||||
setNeedsUpdate (self, YES);
|
||||
}
|
||||
|
||||
static bool makeActive (id self)
|
||||
{
|
||||
const ScopedLock sl (*getLock (self));
|
||||
|
||||
if ([(NSOpenGLView*) self openGLContext] == nil)
|
||||
return false;
|
||||
|
||||
[[(NSOpenGLView*) self openGLContext] makeCurrentContext];
|
||||
|
||||
if (getIvar<void*> (self, "needsUpdate"))
|
||||
{
|
||||
sendSuperclassMessage (self, @selector (update));
|
||||
setNeedsUpdate (self, NO);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
static CriticalSection* getLock (id self)
|
||||
{
|
||||
return getIvar<CriticalSection*> (self, "lock");
|
||||
}
|
||||
|
||||
static void setNeedsUpdate (id self, BOOL b)
|
||||
{
|
||||
object_setInstanceVariable (self, "needsUpdate", (void*) b);
|
||||
}
|
||||
|
||||
static void setNeedsUpdateLocked (id self, BOOL b)
|
||||
{
|
||||
const ScopedLock sl (*getLock (self));
|
||||
setNeedsUpdate (self, b);
|
||||
}
|
||||
|
||||
static void dealloc (id self, SEL)
|
||||
{
|
||||
delete getLock (self);
|
||||
sendSuperclassMessage (self, @selector (dealloc));
|
||||
}
|
||||
|
||||
static BOOL acceptsFirstMouse (id, SEL, NSEvent*) { return YES; }
|
||||
static void surfaceNeedsUpdate (id self, SEL, NSNotification*) { setNeedsUpdateLocked (self, YES); }
|
||||
static void update (id self, SEL) { setNeedsUpdateLocked (self, YES); }
|
||||
static void reshape (id self, SEL) { setNeedsUpdateLocked (self, YES); }
|
||||
|
||||
static void rightMouseDown (id self, SEL, NSEvent* ev) { [[(NSOpenGLView*) self superview] rightMouseDown: ev]; }
|
||||
static void rightMouseUp (id self, SEL, NSEvent* ev) { [[(NSOpenGLView*) self superview] rightMouseUp: ev]; }
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class OpenGLContext::NativeContext
|
||||
{
|
||||
public:
|
||||
|
|
@ -130,10 +49,14 @@ public:
|
|||
|
||||
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes: attribs];
|
||||
|
||||
static ThreadSafeNSOpenGLViewClass cls;
|
||||
static MouseForwardingNSOpenGLViewClass cls;
|
||||
view = [cls.createInstance() initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)
|
||||
pixelFormat: format];
|
||||
ThreadSafeNSOpenGLViewClass::init (view);
|
||||
|
||||
#if defined (MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7)
|
||||
if ([view respondsToSelector: @selector (setWantsBestResolutionOpenGLSurface:)])
|
||||
[view setWantsBestResolutionOpenGLSurface: YES];
|
||||
#endif
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver: view
|
||||
selector: @selector (_surfaceNeedsUpdate:)
|
||||
|
|
@ -172,8 +95,13 @@ public:
|
|||
if ([renderContext view] != view)
|
||||
[renderContext setView: view];
|
||||
|
||||
ThreadSafeNSOpenGLViewClass::makeActive (view);
|
||||
return true;
|
||||
if (NSOpenGLContext* context = [view openGLContext])
|
||||
{
|
||||
[context makeCurrentContext];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isActive() const noexcept
|
||||
|
|
@ -225,11 +153,29 @@ public:
|
|||
return numFrames;
|
||||
}
|
||||
|
||||
private:
|
||||
NSOpenGLContext* renderContext;
|
||||
NSOpenGLView* view;
|
||||
ReferenceCountedObjectPtr<ReferenceCountedObject> viewAttachment;
|
||||
|
||||
//==============================================================================
|
||||
struct MouseForwardingNSOpenGLViewClass : public ObjCClass <NSOpenGLView>
|
||||
{
|
||||
MouseForwardingNSOpenGLViewClass() : ObjCClass <NSOpenGLView> ("JUCEGLView_")
|
||||
{
|
||||
addMethod (@selector (rightMouseDown:), rightMouseDown, "v@:@");
|
||||
addMethod (@selector (rightMouseUp:), rightMouseUp, "v@:@");
|
||||
addMethod (@selector (acceptsFirstMouse:), acceptsFirstMouse, "v@:@");
|
||||
|
||||
registerClass();
|
||||
}
|
||||
|
||||
private:
|
||||
static void rightMouseDown (id self, SEL, NSEvent* ev) { [[(NSOpenGLView*) self superview] rightMouseDown: ev]; }
|
||||
static void rightMouseUp (id self, SEL, NSEvent* ev) { [[(NSOpenGLView*) self superview] rightMouseUp: ev]; }
|
||||
static BOOL acceptsFirstMouse (id, SEL, NSEvent*) { return YES; }
|
||||
};
|
||||
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ public:
|
|||
#else
|
||||
shadersAvailable (false),
|
||||
#endif
|
||||
hasInitialised (false),
|
||||
needsUpdate (1)
|
||||
{
|
||||
nativeContext = new NativeContext (component, pixFormat, contextToShare);
|
||||
|
|
@ -65,6 +66,7 @@ public:
|
|||
#if ! JUCE_ANDROID
|
||||
stopThread (10000);
|
||||
#endif
|
||||
hasInitialised = false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -276,6 +278,19 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
void handleResize()
|
||||
{
|
||||
updateViewportSize (true);
|
||||
|
||||
#if JUCE_MAC
|
||||
if (hasInitialised)
|
||||
{
|
||||
[nativeContext->view update];
|
||||
renderFrame();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void run()
|
||||
{
|
||||
|
|
@ -286,15 +301,14 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
nativeContext->makeActive();
|
||||
nativeContext->setSwapInterval (1);
|
||||
|
||||
initialiseOnThread();
|
||||
|
||||
#if JUCE_USE_OPENGL_SHADERS && ! JUCE_OPENGL_ES
|
||||
shadersAvailable = OpenGLShaderProgram::getLanguageVersion() > 0;
|
||||
#endif
|
||||
|
||||
hasInitialised = true;
|
||||
|
||||
while (! threadShouldExit())
|
||||
{
|
||||
if (! renderFrame())
|
||||
|
|
@ -306,15 +320,15 @@ public:
|
|||
|
||||
void initialiseOnThread()
|
||||
{
|
||||
associatedObjectNames.clear();
|
||||
associatedObjects.clear();
|
||||
|
||||
cachedImageFrameBuffer.release();
|
||||
jassert (associatedObjectNames.size() == 0);
|
||||
jassert (! cachedImageFrameBuffer.isValid());
|
||||
|
||||
context.makeActive();
|
||||
nativeContext->initialiseOnRenderThread();
|
||||
glViewport (0, 0, component.getWidth(), component.getHeight());
|
||||
|
||||
context.extensions.initialise();
|
||||
nativeContext->setSwapInterval (1);
|
||||
|
||||
if (context.renderer != nullptr)
|
||||
context.renderer->newOpenGLContextCreated();
|
||||
|
|
@ -353,7 +367,7 @@ public:
|
|||
ReferenceCountedArray<ReferenceCountedObject> associatedObjects;
|
||||
|
||||
WaitableEvent canPaintNowFlag, finishedPaintingFlag;
|
||||
bool shadersAvailable;
|
||||
bool shadersAvailable, hasInitialised;
|
||||
Atomic<int> needsUpdate;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CachedImage)
|
||||
|
|
@ -411,7 +425,7 @@ public:
|
|||
&& context.nativeContext != nullptr)
|
||||
{
|
||||
if (CachedImage* const c = CachedImage::get (comp))
|
||||
c->updateViewportSize (true);
|
||||
c->handleResize();
|
||||
|
||||
context.nativeContext->updateWindowPosition (comp.getTopLevelComponent()
|
||||
->getLocalArea (&comp, comp.getLocalBounds()));
|
||||
|
|
@ -562,22 +576,37 @@ Component* OpenGLContext::getTargetComponent() const noexcept
|
|||
return attachment != nullptr ? attachment->getComponent() : nullptr;
|
||||
}
|
||||
|
||||
static ThreadLocalValue<OpenGLContext*> currentThreadActiveContext;
|
||||
|
||||
OpenGLContext* OpenGLContext::getCurrentContext()
|
||||
{
|
||||
#if JUCE_ANDROID
|
||||
if (NativeContext* const nc = NativeContext::getActiveContext())
|
||||
if (CachedImage* currentContext = CachedImage::get (nc->component))
|
||||
#else
|
||||
if (CachedImage* currentContext = dynamic_cast <CachedImage*> (Thread::getCurrentThread()))
|
||||
#endif
|
||||
return ¤tContext->context;
|
||||
|
||||
return nullptr;
|
||||
return currentThreadActiveContext.get();
|
||||
}
|
||||
|
||||
bool OpenGLContext::makeActive() const noexcept { return nativeContext != nullptr && nativeContext->makeActive(); }
|
||||
bool OpenGLContext::isActive() const noexcept { return nativeContext != nullptr && nativeContext->isActive(); }
|
||||
void OpenGLContext::deactivateCurrentContext() { NativeContext::deactivateCurrentContext(); }
|
||||
bool OpenGLContext::makeActive() const noexcept
|
||||
{
|
||||
OpenGLContext*& current = currentThreadActiveContext.get();
|
||||
|
||||
if (nativeContext != nullptr && nativeContext->makeActive())
|
||||
{
|
||||
current = const_cast <OpenGLContext*> (this);
|
||||
return true;
|
||||
}
|
||||
|
||||
current = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OpenGLContext::isActive() const noexcept
|
||||
{
|
||||
return nativeContext != nullptr && nativeContext->isActive();
|
||||
}
|
||||
|
||||
void OpenGLContext::deactivateCurrentContext()
|
||||
{
|
||||
NativeContext::deactivateCurrentContext();
|
||||
currentThreadActiveContext.get() = nullptr;
|
||||
}
|
||||
|
||||
void OpenGLContext::triggerRepaint()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,16 +26,11 @@
|
|||
class OpenGLFrameBuffer::Pimpl
|
||||
{
|
||||
public:
|
||||
Pimpl (OpenGLContext& context_, const int width_, const int height_,
|
||||
Pimpl (OpenGLContext& c, const int w, const int h,
|
||||
const bool wantsDepthBuffer, const bool wantsStencilBuffer)
|
||||
: context (context_),
|
||||
width (width_),
|
||||
height (height_),
|
||||
textureID (0),
|
||||
frameBufferID (0),
|
||||
depthOrStencilBuffer (0),
|
||||
hasDepthBuffer (false),
|
||||
hasStencilBuffer (false)
|
||||
: context (c), width (w), height (h),
|
||||
textureID (0), frameBufferID (0), depthOrStencilBuffer (0),
|
||||
hasDepthBuffer (false), hasStencilBuffer (false)
|
||||
{
|
||||
// Framebuffer objects can only be created when the current thread has an active OpenGL
|
||||
// context. You'll need to create this object in one of the OpenGLContext's callbacks.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue