Browse Source

GL fixes, clean-ups, docs.

tags/2021-05-28
jules 13 years ago
parent
commit
0f8cc04904
10 changed files with 174 additions and 111 deletions
  1. +2
    -1
      extras/JuceDemo/Source/demos/OpenGLDemo.cpp
  2. +0
    -1
      modules/juce_opengl/native/juce_OpenGL_android.h
  3. +0
    -5
      modules/juce_opengl/native/juce_OpenGL_ios.h
  4. +1
    -6
      modules/juce_opengl/native/juce_OpenGL_linux.h
  5. +0
    -13
      modules/juce_opengl/native/juce_OpenGL_osx.h
  6. +1
    -6
      modules/juce_opengl/native/juce_OpenGL_win32.h
  7. +42
    -27
      modules/juce_opengl/opengl/juce_OpenGLContext.cpp
  8. +120
    -49
      modules/juce_opengl/opengl/juce_OpenGLContext.h
  9. +5
    -2
      modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp
  10. +3
    -1
      modules/juce_opengl/opengl/juce_OpenGLTexture.cpp

+ 2
- 1
extras/JuceDemo/Source/demos/OpenGLDemo.cpp View File

@@ -60,7 +60,8 @@ public:
addAndMakeVisible (&sizeSlider); addAndMakeVisible (&sizeSlider);
sizeSlider.setBounds ("parent.width * 0.05, parent.height - 35, parent.width * 0.6, top + 24"); sizeSlider.setBounds ("parent.width * 0.05, parent.height - 35, parent.width * 0.6, top + 24");
openGLContext.setRenderer (this, true);
openGLContext.setRenderer (this);
openGLContext.setComponentPaintingEnabled (true);
openGLContext.attachTo (*this); openGLContext.attachTo (*this);
startTimer (1000 / 30); startTimer (1000 / 30);


+ 0
- 1
modules/juce_opengl/native/juce_OpenGL_android.h View File

@@ -72,7 +72,6 @@ public:
} }
bool makeActive() const noexcept { return isInsideGLCallback; } bool makeActive() const noexcept { return isInsideGLCallback; }
bool makeInactive() const noexcept { return true; }
bool isActive() const noexcept { return isInsideGLCallback; } bool isActive() const noexcept { return isInsideGLCallback; }
void swapBuffers() const noexcept {} void swapBuffers() const noexcept {}


+ 0
- 5
modules/juce_opengl/native/juce_OpenGL_ios.h View File

@@ -116,11 +116,6 @@ public:
return true; return true;
} }
bool makeInactive() const noexcept
{
return (! isActive()) || [EAGLContext setCurrentContext: nil];
}
bool isActive() const noexcept bool isActive() const noexcept
{ {
return [EAGLContext currentContext] == context; return [EAGLContext currentContext] == context;


+ 1
- 6
modules/juce_opengl/native/juce_OpenGL_linux.h View File

@@ -114,7 +114,7 @@ public:
void shutdownOnRenderThread() void shutdownOnRenderThread()
{ {
makeInactive();
glXMakeCurrent (display, None, 0);
glXDestroyContext (display, renderContext); glXDestroyContext (display, renderContext);
renderContext = nullptr; renderContext = nullptr;
} }
@@ -125,11 +125,6 @@ public:
&& glXMakeCurrent (display, embeddedWindow, renderContext); && glXMakeCurrent (display, embeddedWindow, renderContext);
} }
bool makeInactive() const noexcept
{
return (! isActive()) || glXMakeCurrent (display, None, 0);
}
bool isActive() const noexcept bool isActive() const noexcept
{ {
return glXGetCurrentContext() == renderContext && renderContext != 0; return glXGetCurrentContext() == renderContext && renderContext != 0;


+ 0
- 13
modules/juce_opengl/native/juce_OpenGL_osx.h View File

@@ -36,7 +36,6 @@
- (id) initWithFrame: (NSRect) frameRect pixelFormat: (NSOpenGLPixelFormat*) format; - (id) initWithFrame: (NSRect) frameRect pixelFormat: (NSOpenGLPixelFormat*) format;
- (bool) makeActive; - (bool) makeActive;
- (void) makeInactive;
- (void) reshape; - (void) reshape;
- (void) rightMouseDown: (NSEvent*) ev; - (void) rightMouseDown: (NSEvent*) ev;
- (void) rightMouseUp: (NSEvent*) ev; - (void) rightMouseUp: (NSEvent*) ev;
@@ -84,12 +83,6 @@
return true; return true;
} }
- (void) makeInactive
{
const juce::ScopedLock sl (*contextLock);
[NSOpenGLContext clearCurrentContext];
}
- (void) _surfaceNeedsUpdate: (NSNotification*) notification - (void) _surfaceNeedsUpdate: (NSNotification*) notification
{ {
(void) notification; (void) notification;
@@ -187,12 +180,6 @@ public:
return true; return true;
} }
bool makeInactive() const noexcept
{
[view makeInactive];
return true;
}
bool isActive() const noexcept bool isActive() const noexcept
{ {
return [NSOpenGLContext currentContext] == renderContext; return [NSOpenGLContext currentContext] == renderContext;


+ 1
- 6
modules/juce_opengl/native/juce_OpenGL_win32.h View File

@@ -50,7 +50,7 @@ public:
initialiseGLExtensions(); initialiseGLExtensions();
const int wglFormat = wglChoosePixelFormatExtension (pixelFormat); const int wglFormat = wglChoosePixelFormatExtension (pixelFormat);
makeInactive();
wglMakeCurrent (0, 0);
if (wglFormat != pixFormat && wglFormat != 0) if (wglFormat != pixFormat && wglFormat != 0)
{ {
@@ -94,11 +94,6 @@ public:
return wglMakeCurrent (dc, renderContext) != FALSE; return wglMakeCurrent (dc, renderContext) != FALSE;
} }
bool makeInactive() const noexcept
{
return (! isActive()) || (wglMakeCurrent (0, 0) != FALSE);
}
bool isActive() const noexcept bool isActive() const noexcept
{ {
return wglGetCurrentContext() == renderContext; return wglGetCurrentContext() == renderContext;


+ 42
- 27
modules/juce_opengl/opengl/juce_OpenGLContext.cpp View File

@@ -350,11 +350,8 @@ void OpenGLContext::NativeContext::renderCallback()
class OpenGLContext::Attachment : public ComponentMovementWatcher class OpenGLContext::Attachment : public ComponentMovementWatcher
{ {
public: public:
Attachment (OpenGLContext& context_, Component& comp,
const OpenGLPixelFormat& pixelFormat_,
const OpenGLContext* contextToShareWith_)
: ComponentMovementWatcher (&comp), context (context_),
pixelFormat (pixelFormat_), contextToShareWith (contextToShareWith_)
Attachment (OpenGLContext& context_, Component& comp)
: ComponentMovementWatcher (&comp), context (context_)
{ {
if (canBeAttached (comp)) if (canBeAttached (comp))
attach(); attach();
@@ -418,8 +415,6 @@ public:
private: private:
OpenGLContext& context; OpenGLContext& context;
OpenGLPixelFormat pixelFormat;
const OpenGLContext* contextToShareWith;
static bool canBeAttached (const Component& comp) noexcept static bool canBeAttached (const Component& comp) noexcept
{ {
@@ -435,7 +430,8 @@ private:
{ {
Component* const comp = getComponent(); Component* const comp = getComponent();
comp->setCachedComponentImage (new CachedImage (context, *comp, comp->setCachedComponentImage (new CachedImage (context, *comp,
pixelFormat, contextToShareWith));
context.pixelFormat,
context.contextToShareWith));
} }
void detach() void detach()
@@ -446,7 +442,7 @@ private:
//============================================================================== //==============================================================================
OpenGLContext::OpenGLContext() OpenGLContext::OpenGLContext()
: nativeContext (nullptr), renderer (nullptr),
: nativeContext (nullptr), renderer (nullptr), contextToShareWith (nullptr),
width (0), height (0), renderComponents (true) width (0), height (0), renderComponents (true)
{ {
} }
@@ -456,37 +452,55 @@ OpenGLContext::~OpenGLContext()
detach(); detach();
} }
void OpenGLContext::setRenderer (OpenGLRenderer* rendererToUse,
bool shouldAlsoPaintComponent) noexcept
void OpenGLContext::setRenderer (OpenGLRenderer* rendererToUse) noexcept
{ {
// This method must not be called when the context has already been attached! // This method must not be called when the context has already been attached!
// Call it before attaching your context, or use detach() first, before calling this! // Call it before attaching your context, or use detach() first, before calling this!
jassert (nativeContext == nullptr); jassert (nativeContext == nullptr);
renderer = rendererToUse; renderer = rendererToUse;
renderComponents = shouldAlsoPaintComponent;
} }
void OpenGLContext::attachTo (Component& component,
const OpenGLPixelFormat& pixelFormat,
const OpenGLContext* contextToShareWith)
void OpenGLContext::setComponentPaintingEnabled (bool shouldPaintComponent) noexcept
{ {
if (getTargetComponent() != &component)
{
detach();
// This method must not be called when the context has already been attached!
// Call it before attaching your context, or use detach() first, before calling this!
jassert (nativeContext == nullptr);
width = component.getWidth();
height = component.getHeight();
renderComponents = shouldPaintComponent;
}
attachment = new Attachment (*this, component,
pixelFormat, contextToShareWith);
}
void OpenGLContext::setPixelFormat (const OpenGLPixelFormat& preferredPixelFormat) noexcept
{
// This method must not be called when the context has already been attached!
// Call it before attaching your context, or use detach() first, before calling this!
jassert (nativeContext == nullptr);
pixelFormat = preferredPixelFormat;
}
void OpenGLContext::setContextToShareWith (const OpenGLContext* context) noexcept
{
// This method must not be called when the context has already been attached!
// Call it before attaching your context, or use detach() first, before calling this!
jassert (nativeContext == nullptr);
contextToShareWith = context;
} }
void OpenGLContext::attachTo (Component& component) void OpenGLContext::attachTo (Component& component)
{ {
component.repaint(); component.repaint();
attachTo (component, OpenGLPixelFormat(), nullptr);
if (getTargetComponent() != &component)
{
detach();
width = component.getWidth();
height = component.getHeight();
attachment = new Attachment (*this, component);
}
} }
void OpenGLContext::detach() void OpenGLContext::detach()
@@ -522,7 +536,6 @@ OpenGLContext* OpenGLContext::getCurrentContext()
} }
bool OpenGLContext::makeActive() const noexcept { return nativeContext != nullptr && nativeContext->makeActive(); } bool OpenGLContext::makeActive() const noexcept { return nativeContext != nullptr && nativeContext->makeActive(); }
bool OpenGLContext::makeInactive() const noexcept { return nativeContext != nullptr && nativeContext->makeInactive(); }
bool OpenGLContext::isActive() const noexcept { return nativeContext != nullptr && nativeContext->isActive(); } bool OpenGLContext::isActive() const noexcept { return nativeContext != nullptr && nativeContext->isActive(); }
void OpenGLContext::triggerRepaint() void OpenGLContext::triggerRepaint()
@@ -575,7 +588,7 @@ bool OpenGLContext::areShadersAvailable() const
return c != nullptr && c->shadersAvailable; return c != nullptr && c->shadersAvailable;
} }
ReferenceCountedObjectPtr<ReferenceCountedObject> OpenGLContext::getAssociatedObject (const char* name) const
ReferenceCountedObject* OpenGLContext::getAssociatedObject (const char* name) const
{ {
jassert (name != nullptr); jassert (name != nullptr);
@@ -635,7 +648,7 @@ void OpenGLContext::copyTexture (const Rectangle<int>& targetClipArea,
static const OverlayShaderProgram& select (OpenGLContext& context) static const OverlayShaderProgram& select (OpenGLContext& context)
{ {
static const char programValueID[] = "juceGLComponentOverlayShader"; static const char programValueID[] = "juceGLComponentOverlayShader";
OverlayShaderProgram* program = static_cast <OverlayShaderProgram*> (context.getAssociatedObject (programValueID).getObject());
OverlayShaderProgram* program = static_cast <OverlayShaderProgram*> (context.getAssociatedObject (programValueID));
if (program == nullptr) if (program == nullptr)
{ {
@@ -716,7 +729,9 @@ void OpenGLContext::copyTexture (const Rectangle<int>& targetClipArea,
JUCE_CHECK_OPENGL_ERROR JUCE_CHECK_OPENGL_ERROR
glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
extensions.glUseProgram (0); extensions.glUseProgram (0);
extensions.glDisableVertexAttribArray (program.params.positionAttribute.attributeID);
} }
#if JUCE_USE_OPENGL_FIXED_FUNCTION #if JUCE_USE_OPENGL_FIXED_FUNCTION
else else


+ 120
- 49
modules/juce_opengl/opengl/juce_OpenGLContext.h View File

@@ -31,6 +31,10 @@
//============================================================================== //==============================================================================
/** /**
A base class that should be implemented by classes which want to render openGL
on a background thread.
@see OpenGLContext
*/ */
class JUCE_API OpenGLRenderer class JUCE_API OpenGLRenderer
{ {
@@ -38,24 +42,42 @@ public:
OpenGLRenderer() {} OpenGLRenderer() {}
virtual ~OpenGLRenderer() {} virtual ~OpenGLRenderer() {}
/**
/** Called when a new GL context has been created.
You can use this as an opportunity to create your textures, shaders, etc.
When the method is invoked, the new GL context will be active.
Note that this callback will be made on a background thread, so make sure
that your implementation is thread-safe.
*/ */
virtual void newOpenGLContextCreated() = 0; virtual void newOpenGLContextCreated() = 0;
/**
/** Called when you should render the next openGL frame.
Note that this callback will be made on a background thread, so make sure
that your implementation is thread-safe.
*/ */
virtual void renderOpenGL() = 0; virtual void renderOpenGL() = 0;
/**
/** Called when the current openGL context is about to close.
You can use this opportunity to release any GL resources that you may have
created.
Note that this callback will be made on a background thread, so make sure
that your implementation is thread-safe.
(Also note that on Android, this callback won't happen, because there's currently
no way to implement it..)
*/ */
virtual void openGLContextClosing() = 0; virtual void openGLContextClosing() = 0;
}; };
//============================================================================== //==============================================================================
/** /**
A base class for types of OpenGL context.
Creates an OpenGL context, which can be attached to a component.
An OpenGLComponent will supply its own context for drawing in its window.
To render some OpenGL in a component, you should create an instance of an OpenGLContext,
and call attachTo() to make it use your component as its render target.
To free the context, either call detach(), or delete the OpenGLContext.
@see OpenGLRenderer
*/ */
class JUCE_API OpenGLContext class JUCE_API OpenGLContext
{ {
@@ -66,63 +88,76 @@ public:
~OpenGLContext(); ~OpenGLContext();
//============================================================================== //==============================================================================
/** */
void setRenderer (OpenGLRenderer* rendererToUse,
bool shouldAlsoPaintComponent) noexcept;
/** */
void attachTo (Component& component);
/** Gives the context an OpenGLRenderer to use to do the drawing.
The object that you give it will not be owned by the context, so it's the caller's
responsibility to manage its lifetime and make sure that it doesn't get deleted
while the context may be using it. To stop the context using a renderer, just call
this method with a null pointer.
Note: This must be called BEFORE attaching your context to a target component!
*/
void setRenderer (OpenGLRenderer* rendererToUse) noexcept;
/** */
void attachTo (Component& component,
const OpenGLPixelFormat& preferredPixelFormat,
const OpenGLContext* contextToShareWith);
/** */
void detach();
/** Enables or disables the use of the GL context to perform 2D rendering
of the component to which it is attached.
If this is false, then only your OpenGLRenderer will be used to perform
any rendering. If true, then each time your target's paint() method needs
to be called, an OpenGLGraphicsContext will be used to render it, (after
calling your OpenGLRenderer if there is one).
/** */
bool isAttached() const noexcept;
By default this is set to true. If you're not using any paint() method functionality
and are doing all your rendering in an OpenGLRenderer, you should disable it
to improve performance.
//==============================================================================
/** Makes this context the currently active one. */
bool makeActive() const noexcept;
/** If this context is currently active, it is disactivated. */
bool makeInactive() const noexcept;
/** Returns true if this context is currently active. */
bool isActive() const noexcept;
Note: This must be called BEFORE attaching your context to a target component!
*/
void setComponentPaintingEnabled (bool shouldPaintComponent) noexcept;
/** Returns the component to which this context is currently attached, or nullptr. */
Component* getTargetComponent() const noexcept;
/** Sets the pixel format which you'd like to use for the target GL surface.
Note: This must be called BEFORE attaching your context to a target component!
*/
void setPixelFormat (const OpenGLPixelFormat& preferredPixelFormat) noexcept;
/** Returns the context that's currently in active use by the calling thread, or
nullptr if no context is active.
/** Provides a context with which you'd like this context's resources to be shared.
The object passed-in here must not be deleted while the context may still be
using it! To turn off sharing, you can call this method with a null pointer.
Note: This must be called BEFORE attaching your context to a target component!
*/ */
static OpenGLContext* getCurrentContext();
void setContextToShareWith (const OpenGLContext* contextToShareWith) noexcept;
//============================================================================== //==============================================================================
/** Swaps the buffers (if the context can do this).
There's normally no need to call this directly - the buffers will be swapped
automatically after your OpenGLRenderer::renderOpenGL() method has been called.
*/
void swapBuffers();
/** Attaches the context to a target component.
/** Sets whether the context checks the vertical sync before swapping.
If the component is not fully visible, this call will wait until the component
is shown before actually creating a native context for it.
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.
When a native context is created, a thread is started, and will be used to call
the OpenGLRenderer methods. The context will be floated above the target component,
and when the target moves, it will track it. If the component is hidden/shown, the
context may be deleted and re-created.
*/
void attachTo (Component& component);
Returns true if it sets the value successfully - some platforms won't support
this setting.
/** Detaches the context from its target component and deletes any native resources.
If the context has not been attached, this will do nothing. Otherwise, it will block
until the context and its thread have been cleaned up.
*/ */
bool setSwapInterval (int numFramesPerSwap);
void detach();
/** Returns the current swap-sync interval.
See setSwapInterval() for info about the value returned.
/** Returns true if the context is attached to a component and is on-screen.
Note that if you call attachTo() for a non-visible component, this method will
return false until the component is made visible.
*/ */
int getSwapInterval() const;
bool isAttached() const noexcept;
/** */
/** Returns the component to which this context is currently attached, or nullptr. */
Component* getTargetComponent() const noexcept;
/** Returns the context that's currently in active use by the calling thread, or
nullptr if no context is active.
*/
static OpenGLContext* getCurrentContext();
/** Asynchronously causes a repaint to be made. */
void triggerRepaint(); void triggerRepaint();
//============================================================================== //==============================================================================
@@ -133,7 +168,7 @@ public:
inline int getHeight() const noexcept { return height; } inline int getHeight() const noexcept { return height; }
/** If this context is backed by a frame buffer, this returns its ID number, /** If this context is backed by a frame buffer, this returns its ID number,
or 0 if the context has no accessible framebuffer.
or 0 if the context does not use a framebuffer.
*/ */
unsigned int getFrameBufferID() const noexcept; unsigned int getFrameBufferID() const noexcept;
@@ -143,12 +178,13 @@ public:
/** This structure holds a set of dynamically loaded GL functions for use on this context. */ /** This structure holds a set of dynamically loaded GL functions for use on this context. */
OpenGLExtensionFunctions extensions; OpenGLExtensionFunctions extensions;
//==============================================================================
/** This retrieves an object that was previously stored with setAssociatedObject(). /** This retrieves an object that was previously stored with setAssociatedObject().
If no object is found with the given name, this will return nullptr. If no object is found with the given name, this will return nullptr.
This method must only be called from within the GL rendering methods. This method must only be called from within the GL rendering methods.
@see setAssociatedObject @see setAssociatedObject
*/ */
ReferenceCountedObjectPtr<ReferenceCountedObject> getAssociatedObject (const char* name) const;
ReferenceCountedObject* getAssociatedObject (const char* name) const;
/** Attaches a named object to the context, which will be deleted when the context is /** Attaches a named object to the context, which will be deleted when the context is
destroyed. destroyed.
@@ -161,6 +197,39 @@ public:
*/ */
void setAssociatedObject (const char* name, ReferenceCountedObject* newObject); void setAssociatedObject (const char* name, ReferenceCountedObject* newObject);
//==============================================================================
/** Makes this context the currently active one.
You should never need to call this in normal use - the context will already be
active when OpenGLRenderer::renderOpenGL() is invoked.
*/
bool makeActive() const noexcept;
/** Returns true if this context is currently active for the calling thread. */
bool isActive() const noexcept;
//==============================================================================
/** Swaps the buffers (if the context can do this).
There's normally no need to call this directly - the buffers will be swapped
automatically after your OpenGLRenderer::renderOpenGL() method has been called.
*/
void swapBuffers();
/** 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 - some platforms won't support
this setting.
*/
bool setSwapInterval (int numFramesPerSwap);
/** Returns the current swap-sync interval.
See setSwapInterval() for info about the value returned.
*/
int getSwapInterval() const;
//============================================================================== //==============================================================================
/** Returns an OS-dependent handle to some kind of underlting OS-provided GL context. /** Returns an OS-dependent handle to some kind of underlting OS-provided GL context.
@@ -197,6 +266,8 @@ private:
NativeContext* nativeContext; NativeContext* nativeContext;
OpenGLRenderer* renderer; OpenGLRenderer* renderer;
ScopedPointer<Attachment> attachment; ScopedPointer<Attachment> attachment;
OpenGLPixelFormat pixelFormat;
const OpenGLContext* contextToShareWith;
int width, height; int width, height;
bool renderComponents; bool renderComponents;


+ 5
- 2
modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp View File

@@ -1021,7 +1021,7 @@ struct StateHelpers
GLuint colour; GLuint colour;
}; };
#if ! JUCE_MAC
#if ! (JUCE_MAC || JUCE_ANDROID || JUCE_IOS)
enum { numQuads = 64 }; // (had problems with my drivers segfaulting when these buffers are any larger) enum { numQuads = 64 }; // (had problems with my drivers segfaulting when these buffers are any larger)
#else #else
enum { numQuads = 8192 }; enum { numQuads = 8192 };
@@ -1051,7 +1051,7 @@ struct StateHelpers
activeShader (nullptr) activeShader (nullptr)
{ {
const char programValueID[] = "GraphicsContextPrograms"; const char programValueID[] = "GraphicsContextPrograms";
programs = static_cast <ShaderPrograms*> (context.getAssociatedObject (programValueID).getObject());
programs = static_cast <ShaderPrograms*> (context.getAssociatedObject (programValueID));
if (programs == nullptr) if (programs == nullptr)
{ {
@@ -1154,6 +1154,9 @@ public:
#if defined (GL_INDEX_ARRAY) #if defined (GL_INDEX_ARRAY)
glDisableClientState (GL_INDEX_ARRAY); glDisableClientState (GL_INDEX_ARRAY);
#endif #endif
target.context.extensions.glBindBuffer (GL_ARRAY_BUFFER, 0);
target.context.extensions.glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
} }
void flush() void flush()


+ 3
- 1
modules/juce_opengl/opengl/juce_OpenGLTexture.cpp View File

@@ -142,7 +142,9 @@ void OpenGLTexture::release()
{ {
if (textureID != 0) if (textureID != 0)
{ {
glDeleteTextures (1, &textureID);
if (OpenGLHelpers::isContextActive())
glDeleteTextures (1, &textureID);
textureID = 0; textureID = 0;
width = 0; width = 0;
height = 0; height = 0;


Loading…
Cancel
Save