PBuffer & Texture Sharing

Is there a way to share Textures loaded in GL memory between Standard Rendering Context and the PBuffer Context ?

I currently load texture once for the Standard Context and a second one for the PBuffer Context, to avoid this problem.

Thanks.

wglShareLists does exactly that, although it’s name won’t suggest it :wink:

Arff!

It seems not working correctly.

I use Vertex & Fragment with textures.
Using wglShareLists display textures but randomly…
GL_Id of texture doesn’t match…
It’s also the same problem with V/F programs…
Sometimes it works with randomly sorted program.

So I spot the fact that I load now, only once the textures and the programs when the main Context is Active.

It’s Strange…
I must be wrong somewhere.

I would like just select when rendering Objects between ColorBuffer and PBuffer destination.

I’m lost. :slight_smile:

Thanks

Try to check the return value of wglShareLists it should be TRUE if things went right.

How are you using it ? personally I do something like that :

	m_hPBuffer = wglCreatePbufferARB (m_hGLDC, pixelFormat, width, height, pBufferAttributes);

m_hDC = wglGetPbufferDCARB (m_hPBuffer);
m_hRC = wglCreateContext (m_hDC);
wglShareLists(m_hGLRC, m_hRC);  

Nothing extraordinary, PBuffer isn’t really difficult to setup (even if it’s a pain to do that if what you want is just rendering to a texture, but soon things will change). In this code m_hGLDC is the window device context and m_hGLRC is the window rendering context. I load shaders and texture only once and things are perfectly right. Moreover I think (need to check thoug) that if the pixel format of your PBuffer and your FrameBuffer match you don’t need to create a new one for your PBuffer, you can share it.

Hope that helps

wglShareLists() works just fine, assuming you haven’t already allocated other things in the context. Thus, you should call it right after creation. The texture Ids you should use are the same as you had in the original context.

Edit: remember also that the two contexts have different state. Thus, if you bind a texture in one context, it does not mean that it’s bound in the other. The same for every other non-shared state (matrices, enables, texenv, etc).

It’s Exacly what I’ve done.

Jwatte:
You’re right it works fine.

I’ve noticed that everything works till I don’t use Fragment or Vertex Program on PBuffer…

I may be wrong somewhere in my implementation.

I’m little confused between pbuffer and V/F programs…

Thanks

Deeper Inside…

I’ve noticed something strange:
Using wslShareLists allows vertex/fragment program ID to be shared between main rendering context and pbuffer rendering context.
BUT programs are not accessible from pbuffer if not loaded from it.

So I’ve tried to load the programs on both rendering context (with each “Made Current Before” of course) and now it works nice with the program Id of one of them (both Id aim it’s own copy program)…

So I gone further,I tried to load an EMPTY fragment program in pBuffer while loading the good fragment program in the main context (EMPTY means : “!!ARBfp1.0 END”)
And everything is stil rendered by using the Fragment Program ID of the main context (wich seems to be shared correctly).

But if I don’t load (with glProgramStringARB) something in the pBuffer context, programs are not reachable from pBuffer…

Any Idea?

Thanks.

I’ve finaly found the problem.
But I don’t know if it’s normal:

Using wglsharelists with multiple pBuffer (in my case 10) and one Main rendering Context, leads to a program binding problem.
When using several v/f programs, rendering contexts shared lose the Programs IDs generated in the main context if you generate & delete programs several times.

I must bind an empty or default program ID “0” in all pBuffers before deleting the program.
In that case, the program deleted is deleted in all shared context, with all Program ID matches.

I don’t know if it’s an obvious problem or if I don’t understand the behaviour of wglShareLists with v/f programs.
But I put here what I’ve Noticed.

If someone can tell me if it’s part of wglShareLists or VERTEX/FRAGMENT_PROGRAM_ARB specs…

I used several Driver (53.03 to 56.72 on my GForceFX5200) to be sure that’s not a bug driver.

Thanks.

No one truly knows what’s the correct behavior. Only MSDN documents it but it isn’t well explained.

It is my understanding that if you have a shareable bound in one of the contexts, and you attempt to delete it, it won’t be deleted but it will become inaccessible in the context in which you deleted it.

I think there is something like a reference count similar to COM objects.

When the final context unbinds the shareable and calls delete on it, the shareable gets deallocated.

This bevavior would respect the glDeleteXXXXXXX function and at the same time would respect wglShareLists.

By shareable, I mean display lists, textures, programs, shaders, buffer objects.

When you create an OpenGL rendering context, it has its own display-list space. The wglShareLists function enables a rendering context to share the display-list space of another rendering context; any number of rendering contexts can share a single display-list space. Once a rendering context shares a display-list space, the rendering context always uses the display-list space until the rendering context is deleted. When the last rendering context of a shared display-list space is deleted, the shared display-list space is deleted. All the indexes and definitions of display lists in a shared display-list space are shared.

You can only share display lists with rendering contexts within the same process. However, not all rendering contexts in a process can share display lists. Rendering contexts can share display lists only if they use the same implementation of OpenGL functions. All client rendering contexts of a given pixel format can always share display lists.

All rendering contexts of a shared display list must use an identical pixel format. Otherwise the results depend on the implementation of OpenGL used.

This is fresh from MSDN. The last paragraph is interesting.

Originally posted by V-man:
No one truly knows what’s the correct behavior.

Someone could take offence at that :wink: .

This is from the GLX spec:

If one context deletes a list that is being executed by another context, the second context will continue executing the old contents of the list until it reaches the end.
[…]
OpenGL makes no attempt to synchronize access to texture objects. If a texture object is bound to more than one context, then it is up to the programmer to ensure that the contents of the object are not being changed via one context while another context is using the texture object for rendering. The results of changing a texture object while another context is using it are undefined.

Yeah, I know it’s GLX and not WGL, but the concept is the same and, as you say, WGL specs are not the deepest thought-of in the world.

Originally posted by V-man:
It is my understanding that if you have a shareable bound in one of the contexts, and you attempt to delete it, it won’t be deleted but it will become inaccessible in the context in which you deleted it.

Close, but not quite. When the textures are shared, the array of texture names becomes common to both contexts. This array is the one that gets refcounted (NOT every individual texture).

When a texture/list/shared resource is deleted (or renamed) in one context, it also gets deleted (or renamed) in the rest.

When a context gets destroyed, the array of names gets refcounted down and the array will finally be destroyed when all the contexts sharing the array have been destroyed.

The only tricky point is when the resource is currently in use in some other context, so the other context will still see the ghost resource until it has finished using it.
Think context A deletes display list 1, but display list 1 is currently being replayed (rendered) on context B, in that case, the display list will actually be deleted when B finishes using it. The display list name is no longer visible to the contexts, but the display list itself (the physical list of OpenGL commands) is still taking memory because it’s in use.

Originally posted by V-man:
When the final context unbinds the shareable and calls delete on it, the shareable gets deallocated.

A shared texture gets deleted when it’s deleted from one context and no longer bound to any context, you don’t need to call glDeleteTextures for each context. Same as with the display list example, the name of the texture is no longer visible to other contexts as soon as you call glDeleteTextures on it.

All modifications to shared context state as a result of executing glBindTexture are atomic. Also, a texture object will not be deleted until it is no longer bound to any rendering context.

(again, from the GLX spec).

OK, I wasn’t perfectly correct :slight_smile:

but there is more …

like jwatte said, “assuming you haven’t already allocated other things in the context”.

MSDN doesn’t say this. I discovered it myself accidently as I learned GL.

MSDN is old. It seems to be GL 1.0 specific. It doesn’t mention texture objects even.

You can only share display lists with rendering contexts within the same process.
What about threads? What about two or more visuals in a single thread each with their own RC? What about two or more visuals each their own RC, each running in their own thread?
There is much that isn’t defined.

MSDN doesn’t even talk about deleting a display list. It’s talking about deleting an RC.

All modifications to shared context state as a result of executing glBindTexture are atomic. Also, a texture object will not be deleted until it is no longer bound to any rendering context.
I’m not sure if I understand the first sentence. What does glBindTexture modify?

Shared context state? That can’t be right.

The current texture bind is a per-context state, so if you bind a texture in a pbuffer/rtt context, that doesn’t mean it will be bound in the viewable context, and vice versa. This can get you in trouble if you’re not carefull when switching contexts.

I’ve never had any problems with ShareLists though, it has always worked perfectly for me, even with several cube and 2D rtts.

Originally posted by V-man:
[b]

[quote]You can only share display lists with rendering contexts within the same process.
What about threads? What about two or more visuals in a single thread each with their own RC? What about two or more visuals each their own RC, each running in their own thread?
There is much that isn’t defined.
[/b]
[/QUOTE]Don’t know about visuals, but you can assume that if the spec doesn’t impose any limitation on those, it should “just work”.

[b]

[quote]All modifications to shared context state as a result of executing glBindTexture are atomic. Also, a texture object will not be deleted until it is no longer bound to any rendering context.
I’m not sure if I understand the first sentence. What does glBindTexture modify?
Shared context state? That can’t be right.
[/b]
[/QUOTE]When glBindTexture is used to create a new texture name, it modifies the array of existing texture names. That modification has to be atomic to all the contexts sharing the array. That name and the rest of texture state bound to the texture object(data modifiable via glTexParamXXXX and the texture image itself) is the shared state it refers to.

Thanks to all for replies :slight_smile:

It was a great help!

Like evanGLizr said, wglShareLists seems to act as told in GLX specs…
Microsoft MSDN is not acurate enough.

But now my program works perfectly:
When deleting vertex/fragment programs, the program must be “unbind” from all context to allow correct Id sharing.

Thanks again.