OpenGLComponent::getCurrentContextComponent()


#1

Hi,

I need a way to get the thread’s current openGL context, it would be great to have this added to juce :

in juce_OpenGLComponent.h :

     /** Returns the active OpenGLComponent.

         the returned value is thread dependant, 
         it will be returned only if it was activated in the calling thread
     */
    static OpenGLComponent* getCurrentContextComponent();

in juce_OpenGLComponent.cpp :

extern bool juce_isCurrentOpenGLContext(void* context);

OpenGLComponent* OpenGLComponent::getCurrentContextComponent()
{
    return InternalGLContextHolder::getCurrent();
}

    // ..

class InternalGLContextHolder  : public ComponentMovementWatcher
{

    // ..

    static OpenGLComponent* getCurrent()
    {
        for (int i = activeGLWindows.size(); --i >= 0;)
        {
            OpenGLComponent* component = (OpenGLComponent*) activeGLWindows[i];
            InternalGLContextHolder* context = (InternalGLContextHolder*) component->internalData;
            if (context->initialised() && juce_isCurrentOpenGLContext(context->context))
                return component;
        }
        return NULL;
    }

in juce_win32_Windowing.cpp :

bool juce_isCurrentOpenGLContext(void* context)
{
    OpenGLContextInfo* const oc = (OpenGLContextInfo*) context;
    HGLRC current = wglGetCurrentContext();
    if (current == oc->renderContext)
        return true;
    return false;
}

in juce_mac_Windowing.cpp :

bool juce_isCurrentOpenGLContext(void* context)
{
    OpenGLContextInfo* const oc = (OpenGLContextInfo*) context;

    AGLContext current = aglGetCurrentContext ();
    if (current == oc->renderContext)
        return true;
    return false;
}

in juce_linux_Windowing.cpp

bool juce_isCurrentOpenGLContext(void* context)
{
    OpenGLContextInfo* const oc = (OpenGLContextInfo*) context;

    GLXContext current = glXGetCurrentContext();
    if (current == oc->renderContext)
        return true;
    return false;
}

#2

Seems like a very sensible idea. I’ll do something along those lines. Thanks!


#3

Oops, sorry, I was waiting until I have this sorted, but I’d like to request that the OpenGLComponent takes avoid* instead of another OpenGLComponent as the shared context. It looks like the only place the share is used is to be dereferenced once for the actual context.

The change would make less code, be slightly safer, and will allow Juce openGLComponents to be mixed with other OpenGL contexts - currently the internal class makes this impossible.

Does that conflict with what you’re doing?

Bruce


#4

I’d already done it another way… I guess this’d be better if you wanted to mix non-juce contexts, but I can’t see any other advantages to it?


#5

Well, yes - since the Juce OpenGL Component is very restrictive about setting up the context, and is by nature quite transient, I have to share another context with it. That context will be made in some native format to each platform, and is retained throughout the program run. In my case, it’s per GPU.

But the Juce component is best to draw in a window, and to co-operate with other juce views.

What’s the other way you did it? Can I give the OpenGL component a platform context - that’s all I need.

Bruce


#6

I just did what you suggested above - the code’s checked-in now if you want to try it.


#7

I know it is really a pain to make it generic and nice, but It would be great to add the functions you (Bruce) need to Juce.

I would be happy to share the code I already did to support pixel format selection, but it’s only implemented on win32 for now.

here are the modifications I added for now :

class OpenGLPixelFormat
{
public:
    OpenGLPixelFormat();

    bool operator== (const OpenGLPixelFormat& other) const;
    bool operator!= (const OpenGLPixelFormat& other) const;

    const String toString() const;

    int redSize;
    int greenSize;
    int blueSize;
    int alphaSize;

    int depthSize;

    int stencilSize;

    int accumRedSize;
    int accumGreenSize;
    int accumBlueSize;
    int accumAlphaSize;

    bool isFloatingPoint;

    int FSAASamples;
};

class OpenGLComponent
{
    // ..
    OpenGLComponent (const OpenGLPixelFormat& pixelFormat = OpenGLPixelFormat(),
                     OpenGLComponent* componentToShareContextWith = 0, 
                     bool manualInitialisation = false);


    bool isInitialised() const;
    void initialise();

    bool getPixelFormat (OpenGLPixelFormat& pixelFormat);

    bool getAlternativePixelFormats (OwnedArray<OpenGLPixelFormat>& results);

    static OpenGLComponent* getCurrentContextComponent();

    static bool getAvailablePixelFormatsForComponent (Component* component, 
                                                      OwnedArray<OpenGLPixelFormat>& results);

#8

Good point. I think I can fill in the Mac version.

Bruce


#9

Great ! I’ll post it here as soon as I get enough time to merge it with the tip.
that means in a few hours I hope.

Linux should be similar to the Mac version I guess.


#10

Jules, I looked at the head, and I was looking for something like this, plus the related change to Mac_Windowing that didn’t work in the patch. I can’t tell whether it breaks Thomas’ request.

Either that, or some other way to force a different context. The key is that I don’t need a Juce component to be master context - that will be offscreen.

Bruce

[code]Index: /Juce_Folder/juce/src/juce_appframework/gui/components/special/juce_OpenGLComponent.cpp

— /Juce_Folder/juce/src/juce_appframework/gui/components/special/juce_OpenGLComponent.cpp (revision 166)
+++ /Juce_Folder/juce/src/juce_appframework/gui/components/special/juce_OpenGLComponent.cpp (working copy)
@@ -80,7 +80,7 @@
private:
OpenGLComponent* owner;
void* context;

  • InternalGLContextHolder* sharedContext;
  • void* sharedContext;
    bool wasShowing;

public:
@@ -88,7 +88,7 @@

 //==============================================================================
 InternalGLContextHolder (OpenGLComponent* const owner_,
  •                         InternalGLContextHolder* const sharedContext_)
    
  •                         void* const sharedContext_)
       : ComponentMovementWatcher (owner_),
         owner (owner_),
         context (0),
    

@@ -119,9 +119,7 @@

     if (context == 0)
     {
  •        context = juce_createOpenGLContext (owner,
    
  •                                            sharedContext != 0 ? sharedContext->context
    
  •                                                               : 0);
    
  •        context = juce_createOpenGLContext (owner, sharedContext);
    
           if (context != 0)
           {
    

@@ -195,10 +193,10 @@
};

//==============================================================================
-OpenGLComponent::OpenGLComponent (OpenGLComponent* share)
+OpenGLComponent::OpenGLComponent (void* share)
{
setOpaque (true);

  • internalData = new InternalGLContextHolder (this, (InternalGLContextHolder*) (share != 0 ? share->internalData : 0));
  • internalData = new InternalGLContextHolder (this, share);

    activeGLWindows.add (this);
    }
    Index: /Juce_Folder/juce/src/juce_appframework/gui/components/special/juce_OpenGLComponent.h
    ===================================================================
    — /Juce_Folder/juce/src/juce_appframework/gui/components/special/juce_OpenGLComponent.h (revision 166)
    +++ /Juce_Folder/juce/src/juce_appframework/gui/components/special/juce_OpenGLComponent.h (working copy)
    @@ -52,11 +52,11 @@
    //==============================================================================
    /** Creates an OpenGLComponent.

  •    @param componentToShareContextWith  if this is another OpenGLComponent, then
    
  •    @param contextToShareContextWith	if this is another OpenGLComponent, then
                                           the two contexts will have their OpenGL contexts
                                           shared
    
    */
  • OpenGLComponent (OpenGLComponent* componentToShareContextWith = 0);
  • OpenGLComponent (void* contextToShareContextWith = 0);

    /** Destructor. */
    ~OpenGLComponent();[/code]


#11

Even I support
thomas’s call.
1.Right now there is no way to customize a juce OpenGL context. We are struck with the default opetion for the pixel format.
2. Also there is no way attach the juce opengl context to a separate rendering thread(worker thread).

If Thomas’s suggezstions are followed, both these can be achived…

Yogesh


#12

I did some cleanup of my modifications, here is the result :

juce_OpenGLComponent.cpp
juce_OpenGLComponent.h
juce_win32_Windowing.cpp

And here is a test application to check if it’s working :

Main.cpp

just replace the Main.cpp in the hello world sample to try it.

Also Bruce, I think your request doesn’t break mine, even if I didn’t include it.
I’m just being curious here but, if I understand well, you use a pbuffer as your ‘master’ context to share your resources between different windows ?


#13

Thanks guys, I’m sure I can take all this stuff and turn it into a nice solution. I don’t really use opengl myself, so am relying on your requests to know what kind of functionality it needs.


#14

Great ! thanks !

just a small detail :
In the modifications, I completly removed the OpenGLComponent’s initialisation parameters for construction, and moved them in initialise() to be able to use it in a worker thread.
it’s also possible to let the previous behavior as the default one (initialise on construction) to keep it straight forward for simple usage, but the code was starting to be too messy to understand the rest.


#15

Thomas, I use an AGL context, not attached to any drawable, as a share context. I suppose it could be a PBO or FBO, didn’t think of that.

It’s AGL now, only to share with the Juce component, which uses AGL, and since AGL can be converted (in theory) to CGL.

I’m going to attach some FBOs to the context to save pre-rendered frames, that the other contexts will access.

Bruce


#16

I’m just having a look at all this now - could someone explain what FSAASamples stands for?


#17

FSAA means Full-scene anti-aliasing,
It is now implemented in hardware in most decent opengl compliant graphic cards.
FSAASamples are the number of samples used for calculation,
from 2 to 64 for the most expensive cards

openGL implementations require a special pixel format to create a context that allows hardware multisampling, so you have to specify how many samples you want.
After that you can only switch it on or off using glEnable/glDisable(GL_ARB_MULTISAMPLE);

one last note about the code I posted on this thread:
on win32 implementation it is really a mess to set up this, because of the win32 opengl extensions system :
To create a AA context you need some extensions to choose the right pixel format, but extensions mechanism is per-context
so you need to first create a ‘dummy’ opengl context to find out what extensions are supported, if you find WGL_ARB_pixel_format it means you may have a chance to get an ‘extended’ pixel format.
after that you have to destroy the dummy pixel format and then create a new one with the requested attributes.
The implementation finaly chooses which one is acceptable, and it is not always the one that you asked for.

I hope it’s more clear now


#18

Mac is a tiny bit more flexible than that!

For CGL, the attribute flags are:

kCGLPFASampleBuffers, (CGLPixelFormatAttribute)1, kCGLPFASamples, (CGLPixelFormatAttribute)2, kCGLPFAMultisample,

AGL would be these:

[code]#define AGL_SAMPLE_BUFFERS_ARB 55 /* number of multi sample buffers /
#define AGL_SAMPLES_ARB 56 /
number of samples per multi sample buffer /
#define AGL_MULTISAMPLE 59 /
choose multisample /
#define AGL_SUPERSAMPLE 60 /
choose supersample */

[/code]

That would be Multi-sample or supersample, the two different FSAA modes.

Bruce


#19

Oh, and Jules, please could I have my void* sharedContext, please please? Juce is not an island.

Bruce


#20

Thanks guys, I’m on the case…