1
0
Fork 0
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:
jules 2013-03-09 18:04:58 +00:00
parent 4d4cc13a46
commit cf781ecb75
3 changed files with 86 additions and 116 deletions

View file

@ -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)
};

View file

@ -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 &currentContext->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()
{

View file

@ -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.