New OpenGL Scheme prevents sharing


#1

We need some tweaks to OpenGL. Should be still in time, since the OpenGL stuff is ‘new’.

Everytime an OpenGLContext is being passed around, we should actually be able to pass an OpenGLContext::NativeContext.

All the user classes just seem to dereference it anyway,

Then: NativeContext needs to be tweaked a hair to be used as an offscreen context - essentially very close to the existing CachedImage class that uses an FBO.

To be honest the cachedImage stuff should probably all use a centralized Context anyway. Currently, a lot of cached images means a lot of contexts, as I read it. That’s not good OpenGL practice - the number of contexts and the times they are switched should be minimized, and also, the current design may not permit the same image to be used in different contexts without some sort of anchoring window.

Best would be to have an anchoring context to share, and cached images should draw in the context that is currently active, so there’s no context switch, then linked to the anchoring context.

Bruce


#2

Thanks Bruce - yes, this does need some tweaking. Will look into it when I get chance, but feel free to pester/suggest things to get me moving on it.


#3

Unless you’ve thought of something better:

CachedImage (OpenGLContext& context_, Component& component_, const OpenGLPixelFormat& pixelFormat, const OpenGLContext::NativeContext* contextToShareWith) : Thread ("OpenGL Rendering"), context (context_), component (component_), #if JUCE_OPENGL_ES shadersAvailable (true), #else shadersAvailable (false), #endif needsUpdate (true) { nativeContext = new NativeContext (component, pixelFormat, contextToShareWith);

Move up the NativeContext forward declaration, then:

[code] void setContextToShareWith (const NativeContext* contextToShareWith) noexcept;

/** Returns the NativeContext used by this context. Use this context to pass to
    another context for them to share OpenGL resources.
 */
inline NativeContext* getNativeContext () const noexcept     { return nativeContext; }[/code]

OpenGLPixelFormat pixelFormat; const NativeContext* contextToShareWith; int width, height;


#4

Then:

NativeContext needs to be moved around so it works as a BaseClass and is inheritable (more declarations),

OR

If no Component is passed to a NativeContext, we can have it set up as an offscreen context.

Preference, Jules?

Bruce

EDIT - if you want to make it a base class, I’ll end up making Mac & windows offscreen NC’s. If you change to a Component pointer, I will flesh out the Mac and Linux code to make an offscreen context.

Huh. Or - can a CachedImage be created and never shown? That would be close enough to an offscreen. Then we just need a getNativeContext from a CachedImage. That has the advantage of the user being able to place the Component on the correct screen (i.e. GPU), so that the OpenGL sharing will work properly for the items on that same screen/GPU.


#5

Well, the NativeContext class is a Pimpl, so I certainly don’t want to expose it in any way… it’s really just there for handling native OS stuff behind the scenes.


#6

Well, next one down is a void* to the actual platform context. Do the subclasses need to know anything other than that?

Bruce


#7

I’ll need to have a think about this one…


#8

How about this -

NativeContext takes a raw context pointer to share with instead of a NativeContext*, and getRawContext() in OpenGLContext is virtual.

That way, there’s no exposure.

I wonder if over-protecting NativeContext is worthwhile, btw. Any other context that is intended to be shared with it would have involved complex OpenGL and platform work.

Bruce


#9

Hang on, I’m confused here… What’s wrong with OpenGLContext::setContextToShareWith? Does it not work?


#10

setContextToShareWith takes an OpenGLContext. The problems then are:

  • There isn’t an offscreen OpenGLContext in Juce, and OpenGLContext won’t make an actual context unless assigned a component.

  • OpenGLContext is not set up to be a base class, so can’t be replaced by a custom, offscreen capable version.
    Amongst other problems, it actually looks for a NativeContext when sharing, and that’s even harder to subclass.

  • A share from another non-Juce OpenGLContext can’t be wrapped and used - it can’t provide the hidden NativeContext.

So, it’s impossible to have a consistent share context, that survives the comings and goings of Juce contexts, and/or to share something that doesn’t rely on juce.

Being able to get the raw context from an OpenGLContext is helpful, but the other way around would be better - a GUI element would tend to be more transient than a global share context that ‘holds’ resources in shareable way for a certain GPU (on Mac, should be able to share between all GPUs these days).

Bruce


#11

I’m agree with Bruce, setContextToShareWith is not enough to share from raw native GL contexts (HGLRC…) created without Juce.
For this, I had to made ugly Juce code modifications. (http://www.rawmaterialsoftware.com/viewtopic.php?f=2&t=9108)
Bruce’s modifications seem to be the cleanest way to do this.


#12

I have a feeling Jules will object to OpenGLContext being subclassed. It does so much, using it as a base class to get one feature seems wrong.

So I have a proposal that better fits the way I want to use sharing, hopefully it fits with o=your cases?

class OpenGLShareGroup

Each new OpenGLContext can share with it or not. Resources can be registered with it, much like with an OpenGLContext, but they will now be shut down when the last context in the group shuts down, or the group itself shuts down.

At some point we could add a ‘persistent’ flag that would allow an offscreen context to be created.

A key advantage would be that no other contexts are needed. Currently, AFAICT, CachedComponentImages use their own context - Jules, context switching in the middle of a rendering pass is a big non-no. Now any work that needs to be done on a context can be done on any context in the group. So, for instance, if I want to make an Image available as a texture, I add it to the share group. Now, the first context that wants to render with it will create the texture (will involve some locking, but no context switching). It’s then available to any members of the group, and it’s still available even if one or all classes disappear.

class OpenGLShareGroupMember

a fairly lightweight ABC class that links to and from the share group. It should be lightweight enough that external, non-juce contexts can be wrapped and join the group, or the group can start with a non-juce context.

Any comments? I’d love to be able to not roll my own offscreen contexts, and it should improve the current Juce GL system.

It should also be relatively simple to implement with a minimum feature set: just the OpenGLShareGroupMember class as an ABC for sharing, thereby no misuse of the heavyweight OpenGLContext class.

setContextToShareWith (OpenGLShareGroupMember* share)

or

setContextShareGroup (OpenGLShareGroup::Ptr shareGroup)

Bruce


#13

Nice interface Bruce!

Also, sharing is caring!!!


#14

My initial thoughts on this were that I could just change the setContextToShareWith method to make it take a raw context handle instead of an OpenGLContext pointer, so you could either create that native context object yourself, or just get it from an existing OpenGLContext… What would be the advantages of using your OpenGLShareGroup idea instead?


#15

That solution is fine too, but:

It addresses what people are trying to do, adding it as a juce capability.

In terms of stuff you may be concentrating on, it would allow resources (display lists, textures etc.) to be resident on the GPU even if a context is created and has to be recreated. That obviously has a positive effect on frame rates and responsiveness.

It also makes a stable well defined place for non-juce or juce OpenGL stuff to share with, without lifecycle issues.

Meanwhile, I had noticed that the CachedComponentImage creates a context. That may well be fine, but I do see some potential issues - the whole thing would probably have to be recreated if the main context has to be, and it doesn’t seem to have hooks to move, so the whole thing would have to be retransferred to GL (that’s the sort of thing you end up obsessing about when working on frame rates - times that GPU and CPU have to work together), but mostly importantly - if you’re actually using that context, switching to it has a big cost. It’s far better to have a context around to share with, but actually do the drawing on the thread and context that is making your visible results.

It also keeps some void pointers (more) out of the mix, so could avoid some pointer/deleted object related crashes.

Bruce

Edit/PS - it’s really whether you believe sharing is a useful feature for the majority. I was hoping some other OpenGL focussed users would jump in… it moves it from an ‘as well/not impossible’ to a feature. If did decide to do it, and has to go on the list for down the road, please do make the void* changes so it’s usable as is.


#16

Ok, I’m probably being a bit thick, but I’m struggling a bit to see exactly what you mean with this… I’m going to do the void* change for now, because that’s a 5-minute job, and maybe you could sketch out your thoughts about this other idea - perhaps if I saw some code I’d understand the point!


#17

The latest version doesn’t build on Windows.


#18

Damn, could have sworn that I checked that… Thanks, it’s fixed now!


#19

I have it in my head, but I’m a bit jammed. Will do.

Bruce


#20

So actually, C++ is now your mother tongue, as English doesn’t fit anymore ?

I’d tend to follow Bruce idea, as I’ve hard time optimizing my code to reach the 60fps target, and context switching was an issue. I had to change the visibility of the method “isContextActive()” and perform a “if (!isContextActive()) makeCurrentContextActive()” because calling makeCurrentContextActive() unconditionnaly took milliseconds! (even if already active).