5

I met a problem using shared contexts:

I have two threads and each has one context, say Thr1(thread1) with Ctx1(Context1) and Thr2 and Ctx2. Ctx2 was created sharing with Ctx1.

Then, in Thr2, I create some textures with Ctx2 as current context, and do some rendering. After that, I destroy the Ctx2 and finish Thr2.

Now the problem arised: after I destroy the Ctx2, the textures created under the Ctx2 not released(Some of then, not all). I use gDebugger to profile my program, and see that, these textures are not released, and listed under Ctx1.

As I repeat create Thr2/Ctx2 and create textures and destroy Thr2/Ctx2, the textures are getting more and more, as well as the memory.

What I have tried:

Delete the textures in Thr2 before destroy Ctx2;

In Thr2 make Ctx1 as current and try to delete the textures, before Ctx2 is destroy;

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
CurtisGuo
  • 339
  • 1
  • 3
  • 10

1 Answers1

5

This sounds like expected behavior.

To explain the lifetime of objects with multiple contexts, I'm going to use the word "pool" to describe a collection of textures. I don't think there's universal terminology for the concept, so this is as good as anything.

While you may normally picture textures being owned by a context, they are in fact owned by a pool. As long as you just have a single context, that's an academic difference. The context owns the pool, the pool owns all the textures that were created in the context. When the context is destroyed, the pool goes away with it, which in turn destroys all textures in the pool.

Now, with two sharing contexts, things get more interesting. You still have one pool, which both contexts have shared ownership for. When you create a texture in any one of the two contexts, the texture is owned by the shared pool. When a context is deleted, it gives up its shared ownership of the pool. The pool (including all textures in the pool) stays around as long as at least one of the contexts is alive.

In your scenario, context 2 creates a texture. This texture is added to the pool shared by context 1 and context 2. Then you delete context 2. The created texture remains in the pool. The pool itself remains alive because context 1 (which still exists) has shared ownership of the pool. This means that the texture also remains alive. It is irrelevant that context 2 created the texture, since the texture is owned by the pool, not by context 2.

Therefore, if you really want to delete the texture, you'll have to make a glDeleteTexture() call. It does not matter if you make this call in context 1 or context 2.

There are some subtle aspects when shared textures are deleted, related for example to textures being FBO attachments, or textures being deleted in one context while being bound in another context. But since this is not at the core of this question, and it's somewhat complicated, I'll refer to the spec for the details (see for example section D.1.2 on page 337 of the OpenGL 3.3 spec).

Reto Koradi
  • 53,228
  • 8
  • 93
  • 133
  • Thanks a lot. Sorry that I'm new to openGL. What will happen in my scenario that if Thr2 call the glDeleteTextures after MakeCurrent(0, 0, 0) is called? According to what you said, it seems nothing will happen. Am I right? – CurtisGuo Apr 23 '15 at 06:18
  • Yes, you need to make all OpenGL calls while you have a current context. Otherwise they won't have any effect. – Reto Koradi Apr 23 '15 at 06:25
  • If (in GLX extension) glXMakeCurrent(dpy, 0, 0) is called, and the GLXDrawable is destroyed. Is it the only way to delete the textures that I create a new GLXDrawable and call the glXMakeCurrent(dpy, Ctx2, drawable) and delete the textures? – CurtisGuo Apr 23 '15 at 06:52
  • In your scenario, after you delete context 2, you can still delete the textures with `glDeleteTextures()` calls from context 1. – Reto Koradi Apr 23 '15 at 07:12
  • Is glDeleteTextures must called in thread 1 if using context 1? – CurtisGuo Apr 23 '15 at 07:18
  • Yes. The current context is per thread. And every context can only be current to one thread. – Reto Koradi Apr 23 '15 at 07:21
  • What if I call makeCurrent(dpy, ctx1, dra) in thread 2, and then call glDeleteTextures in thread 2? It‘s better for me to do this cleanup in thread 2. – CurtisGuo Apr 23 '15 at 07:25
  • @CurtisGuo: OpenGL contexts are not tied to drawables. You can bind a given OpenGL context to any drawable that has a compatible format. In hindsight the context creation and drawable management APIs are quite arcane. A much better API design choice would have been to create a format descriptor handle use that to set a drawable's format and also use the format handle for context creation. Anyway, what I'm trying to get at is, that as long as you've got one drawable around to work with, you can use that. You can even make the same drawable current with different contexts in different threads. – datenwolf Apr 23 '15 at 07:45
  • @RetoKoradi What if Ctx1 shared with Ctx2 and Ctx2 shared with Ctx3? Are the 3 contexts sharing the same texture pool? – CurtisGuo Apr 24 '15 at 01:56
  • Yes, they would share the textures between all 3 contexts. Or in the terminology I made up for this answer, they would all share the same texture pool. – Reto Koradi Apr 24 '15 at 02:28