1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

GL fixes, clean-ups, docs.

This commit is contained in:
jules 2012-03-30 15:28:26 +01:00
parent 87d3acf19f
commit 0f8cc04904
10 changed files with 188 additions and 125 deletions

View file

@ -60,7 +60,8 @@ public:
addAndMakeVisible (&sizeSlider);
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);
startTimer (1000 / 30);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -350,11 +350,8 @@ void OpenGLContext::NativeContext::renderCallback()
class OpenGLContext::Attachment : public ComponentMovementWatcher
{
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))
attach();
@ -418,8 +415,6 @@ public:
private:
OpenGLContext& context;
OpenGLPixelFormat pixelFormat;
const OpenGLContext* contextToShareWith;
static bool canBeAttached (const Component& comp) noexcept
{
@ -435,7 +430,8 @@ private:
{
Component* const comp = getComponent();
comp->setCachedComponentImage (new CachedImage (context, *comp,
pixelFormat, contextToShareWith));
context.pixelFormat,
context.contextToShareWith));
}
void detach()
@ -446,7 +442,7 @@ private:
//==============================================================================
OpenGLContext::OpenGLContext()
: nativeContext (nullptr), renderer (nullptr),
: nativeContext (nullptr), renderer (nullptr), contextToShareWith (nullptr),
width (0), height (0), renderComponents (true)
{
}
@ -456,37 +452,55 @@ OpenGLContext::~OpenGLContext()
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!
// Call it before attaching your context, or use detach() first, before calling this!
jassert (nativeContext == nullptr);
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)
{
component.repaint();
attachTo (component, OpenGLPixelFormat(), nullptr);
if (getTargetComponent() != &component)
{
detach();
width = component.getWidth();
height = component.getHeight();
attachment = new Attachment (*this, component);
}
}
void OpenGLContext::detach()
@ -522,7 +536,6 @@ OpenGLContext* OpenGLContext::getCurrentContext()
}
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(); }
void OpenGLContext::triggerRepaint()
@ -575,7 +588,7 @@ bool OpenGLContext::areShadersAvailable() const
return c != nullptr && c->shadersAvailable;
}
ReferenceCountedObjectPtr<ReferenceCountedObject> OpenGLContext::getAssociatedObject (const char* name) const
ReferenceCountedObject* OpenGLContext::getAssociatedObject (const char* name) const
{
jassert (name != nullptr);
@ -635,7 +648,7 @@ void OpenGLContext::copyTexture (const Rectangle<int>& targetClipArea,
static const OverlayShaderProgram& select (OpenGLContext& context)
{
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)
{
@ -716,7 +729,9 @@ void OpenGLContext::copyTexture (const Rectangle<int>& targetClipArea,
JUCE_CHECK_OPENGL_ERROR
glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
extensions.glUseProgram (0);
extensions.glDisableVertexAttribArray (program.params.positionAttribute.attributeID);
}
#if JUCE_USE_OPENGL_FIXED_FUNCTION
else

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
{
@ -38,24 +42,42 @@ public:
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;
/**
/** 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;
/**
/** 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;
};
//==============================================================================
/**
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
{
@ -66,30 +88,66 @@ public:
~OpenGLContext();
//==============================================================================
/** */
void setRenderer (OpenGLRenderer* rendererToUse,
bool shouldAlsoPaintComponent) noexcept;
/** 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);
/** 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).
/** */
void attachTo (Component& component,
const OpenGLPixelFormat& preferredPixelFormat,
const OpenGLContext* contextToShareWith);
/** */
void detach();
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.
/** */
bool isAttached() const noexcept;
Note: This must be called BEFORE attaching your context to a target component!
*/
void setComponentPaintingEnabled (bool shouldPaintComponent) 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;
/** 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!
*/
void setContextToShareWith (const OpenGLContext* contextToShareWith) noexcept;
//==============================================================================
/** 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;
/** Attaches the context to a target component.
If the component is not fully visible, this call will wait until the component
is shown before actually creating a native context for it.
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);
/** 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.
*/
void detach();
/** 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.
*/
bool isAttached() const noexcept;
/** Returns the component to which this context is currently attached, or nullptr. */
Component* getTargetComponent() const noexcept;
@ -99,6 +157,56 @@ public:
*/
static OpenGLContext* getCurrentContext();
/** Asynchronously causes a repaint to be made. */
void triggerRepaint();
//==============================================================================
/** Returns the width of this context */
inline int getWidth() const noexcept { return width; }
/** Returns the height of this context */
inline int getHeight() const noexcept { return height; }
/** If this context is backed by a frame buffer, this returns its ID number,
or 0 if the context does not use a framebuffer.
*/
unsigned int getFrameBufferID() const noexcept;
/** Returns true if shaders can be used in this context. */
bool areShadersAvailable() const;
/** This structure holds a set of dynamically loaded GL functions for use on this context. */
OpenGLExtensionFunctions extensions;
//==============================================================================
/** This retrieves an object that was previously stored with setAssociatedObject().
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.
@see setAssociatedObject
*/
ReferenceCountedObject* getAssociatedObject (const char* name) const;
/** Attaches a named object to the context, which will be deleted when the context is
destroyed.
This allows you to store an object which will be released before the context is
deleted. The main purpose is for caching GL objects such as shader programs, which
will become invalid when the context is deleted.
This method must only be called from within the GL rendering methods.
*/
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
@ -122,45 +230,6 @@ public:
*/
int getSwapInterval() const;
/** */
void triggerRepaint();
//==============================================================================
/** Returns the width of this context */
inline int getWidth() const noexcept { return width; }
/** Returns the height of this context */
inline int getHeight() const noexcept { return height; }
/** If this context is backed by a frame buffer, this returns its ID number,
or 0 if the context has no accessible framebuffer.
*/
unsigned int getFrameBufferID() const noexcept;
/** Returns true if shaders can be used in this context. */
bool areShadersAvailable() const;
/** This structure holds a set of dynamically loaded GL functions for use on this context. */
OpenGLExtensionFunctions extensions;
/** This retrieves an object that was previously stored with setAssociatedObject().
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.
@see setAssociatedObject
*/
ReferenceCountedObjectPtr<ReferenceCountedObject> getAssociatedObject (const char* name) const;
/** Attaches a named object to the context, which will be deleted when the context is
destroyed.
This allows you to store an object which will be released before the context is
deleted. The main purpose is for caching GL objects such as shader programs, which
will become invalid when the context is deleted.
This method must only be called from within the GL rendering methods.
*/
void setAssociatedObject (const char* name, ReferenceCountedObject* newObject);
//==============================================================================
/** Returns an OS-dependent handle to some kind of underlting OS-provided GL context.
@ -197,6 +266,8 @@ private:
NativeContext* nativeContext;
OpenGLRenderer* renderer;
ScopedPointer<Attachment> attachment;
OpenGLPixelFormat pixelFormat;
const OpenGLContext* contextToShareWith;
int width, height;
bool renderComponents;

View file

@ -1021,7 +1021,7 @@ struct StateHelpers
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)
#else
enum { numQuads = 8192 };
@ -1051,7 +1051,7 @@ struct StateHelpers
activeShader (nullptr)
{
const char programValueID[] = "GraphicsContextPrograms";
programs = static_cast <ShaderPrograms*> (context.getAssociatedObject (programValueID).getObject());
programs = static_cast <ShaderPrograms*> (context.getAssociatedObject (programValueID));
if (programs == nullptr)
{
@ -1154,6 +1154,9 @@ public:
#if defined (GL_INDEX_ARRAY)
glDisableClientState (GL_INDEX_ARRAY);
#endif
target.context.extensions.glBindBuffer (GL_ARRAY_BUFFER, 0);
target.context.extensions.glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
}
void flush()

View file

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