Share GLX pixmap with another process

Hello,

I am desperately trying to share a GLX pixmap with another process running its own context to display it in another window.

Here is my setup:

At the server side:


unsigned long xid = glXGetCurrentDrawable();

glXMakeCurrent(glXGetCurrentDisplay(), None, None);

// Send xid to clients via a socket
send_xid(xid);

{
// Wait for response from clients
std::unique_lock<std::mutex> lock(this->mtx);
this->cv.wait(lock, [&]{ return this->count == 0; });
}

glXMakeCurrent(glXGetCurrentDisplay(), xid, glXGetCurrentContext());

At the client side:


glXMakeContextCurrent(glXGetCurrentDisplay(), this->windowId, _xid, glXGetCurrentContext());

glDrawBuffer(GL_BACK);
glReadBuffer(GL_FRONT);

glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);

glRasterPos2i(0, 0);
glPixelTransferi(GL_MAP_COLOR, GL_TRUE);
glCopyPixels(0, 0, _width, _height, GL_COLOR);
glXSwapBuffers(glXGetCurrentDisplay(), this->windowId);

// Send response to server
send_ok();

glXMakeContextCurrent(glXGetCurrentDisplay(), None, None, None);

The problem is that, when I read the pixmap, for instance with glReadPixels, its content is zero at the client side only, and its window only contains a black image. Can you see what is wrong with my code? Thanks.

Does someone have the answer? Is there something I am missing?

If they’re both using GL, why do you want to use a GLXpixmap as the interchange mechanism. Consider using a GL object such as a texture. Plus you’ll likely get more folks trying to help you because few have messed with rendering to GLXpixmaps. I worked on high-performance flight sim rendering on Linux/UNIX for 12 years and never touched GLXpixmaps. So I suspect that even among the folks developing GL apps on Linux/UNIX, you’re not going to get much help there.

Also, what are you using to ensure that the GL work issued by one context is complete in the other context?

Thanks for your help. I plan to use GLXpixmap because it seems to be the only way to share a drawable between processes without having to perform any copy. The idea is that if you release the context with glXMakeCurrent(glXGetCurrentDisplay(), None, None), the other process should be able to work on the same pixmap. Is that also possible with a texture?

I am not sure I understand your last question. What do you mean by “complete”? The two contexts are created in the same manner if that is what you mean.

You can share textures between separate contexts, yes.

Re complete. Just because you finish issuing the commands to draw a render target doesn’t mean that any/all of those commands have executed yet. When using multiple contexts, you have to use pipeline synchronization to ensure that when context #1 renders something, context #2’s queue doesn’t operate with that something until the GPU has finished rendering.

The OP is trying to share textures between processes. And you can’t use a context in a process other than the one which created it. Server-side resources (e.g. Pixmaps) can be used by any client which can get hold of the XID. But an OpenGL context is a mixture of server-side and client-side state. A GLXContext is a pointer, so you can’t pass references to context between clients (which may not even be running on the same host). A GLXPixmap is just an XID (i.e. a 32-bit integer); so there’s no inherent problem with passing it between clients.

However, it’s possible that either the client-side portion of the implementation maintains private data using the XID as a key, or the server limits access to a GLXPixmap to the client which created it.

Is the context using direct or indirect rendering? I’d expect direct rendering to have additional issues, as much of the rendering process bypasses the X server.

[QUOTE=GClements;1279054]The OP is trying to share textures between processes. And you can’t use a context in a process other than the one which created it. Server-side resources (e.g. Pixmaps) can be used by any client which can get hold of the XID. But an OpenGL context is a mixture of server-side and client-side state. A GLXContext is a pointer, so you can’t pass references to context between clients (which may not even be running on the same host). A GLXPixmap is just an XID (i.e. a 32-bit integer); so there’s no inherent problem with passing it between clients.

However, it’s possible that either the client-side portion of the implementation maintains private data using the XID as a key, or the server limits access to a GLXPixmap to the client which created it.

Is the context using direct or indirect rendering? I’d expect direct rendering to have additional issues, as much of the rendering process bypasses the X server.[/QUOTE]
I use direct rendering on both sides. I will tell you tomorrow if the problem also appears with indirect rendering. Thank you very much.

Unfortunately, I have no choice but to use direct rendering on both sides.

For a start, the glXCreateGLXPixmap manual page says:

Some implementations may not support GLX pixmaps with direct rendering contexts.

Assuming that GLXPixmaps are supported with direct rendering contexts:

  1. Are you synchronising correctly? The rendering side should call glFinish() and wait for it to return before notifying the reader.
  2. Ensure that the GLXPixmap isn’t current in multiple contexts simultaneously.
  3. If you can’t share a GLXPixmap, maybe you can have each client create its own GLXPixmap but sharing the underlying Pixmap?
  4. If this is with a proprietary driver, have you tested with the Mesa software driver?

Sorry for the late reply GClements.

[QUOTE=GClements;1279094]For a start, the glXCreateGLXPixmap manual page says:

  1. Are you synchronising correctly? The rendering side should call glFinish() and wait for it to return before notifying the reader.
    [/quote]
    Yes, I am sure that the rendering side calls glFinish(). Before sending the xid to a client, I also call:
    glXMakeContextCurrent(display, None, None, NULL);
    to release the xid. And then I wait for a response from a client before performing any new operation.
  1. Ensure that the GLXPixmap isn’t current in multiple contexts simultaneously.

Actually, I don’t use a GLXPixmap, but a GLXPbuffer. And, yes, as said before, the GLXPbuffer is released before sending it to a single client. The client successfully calls glXMakeContextCurrent(display, window, xid, context); and then I try to copy the pixels from the GLXPbuffer identified by its xid to the window buffer:
glRasterPos2i(0, 0);
glPixelTransferi(GL_MAP_COLOR, GL_TRUE);
glCopyPixels(0, 0, _width, _height, GL_COLOR);
But it fails (black pixels).

  1. If you can’t share a GLXPixmap, maybe you can have each client create its own GLXPixmap but sharing the underlying Pixmap?

OK, I may try that.

  1. If this is with a proprietary driver, have you tested with the Mesa software driver?

I only use open source drivers (radeon). Thank you very much for your help.

OK, it actually works with Pixmap/GLXPixmap, but not with GLXPbuffer. No idea why, I will investigate further.