2
votes

I am writing an application that:

  • Continuously renders stuff offscreen in a pipeline that has private OpenGL context & private thread
  • Draws some of the previously rendered textures in widgets

In order to do that I need to share those textures across both the pipeline and the widgets contexts:

Approach 1 : share all contexts

int main (int argc, char *argv[])
{
     QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
     QApplication a(argc, argv);

     // [...] Create and initialize the pipeline (private context)
     // [...] Create a window with a widget that can display a texture (Qt creates a private context itself)
     // [...] Set the texture to display in the widget with one created and rendered in the pipeline
}

By the time i want to draw my texture (in the paintGL() callback), glBindTexture yields a GL_INVALID_OPERATION.
Graphics debugger shows a weird texture instead of mine : context sharing does not seem to work.

Approach 2 : widget have a self created context that shares both the pipeline and the Qt one

// [...] Create and initialize the pipeline (private context)
// [...] Create a window with a widget that can display a texture (Qt creates a private context itself)
// widget's initializeGL() callback gets called
void initializeGL()
{
     initializeOpenGLFunctions();
     m_secondContext.setShareContext(QOpenGLContext::currentContext());
     m_secondContext.setShareContext(pipelineContext);
     m_secondContext.create();
}
// use the second context during paintEvents
void paintGL()
{
     auto contextBackup(QOpenGLContext::currentContext());
     auto surfaceBackup(contextBackup->surface());
     assert(m_secondContext->makeCurrent(surfaceBackup));

     // [...] draw texture

     contextBackup->makeCurrent(surfaceBackup);
}

Does not work either, yields same error as approach 1 + some more that i have not located.

Approach 3 : Pipeline share the widgets context

// [...] Create a window with a widget that can display a texture (Qt creates a private context itself)
// [...] Create and initialize the pipeline with the widgets context set as shared 
//       before calling create on the new pipeline context
void initializePipeline()
{
     m_pipelineContext.setShareContext(widgetContext);
     m_pipelineContext.create();
}

This does work, BUT it is an unwanted solution as it does not allow the creation of such widgets AFTER the pipeline initialization

Questions i am asking:

  • All theses three scenarios should give the same result, what is happening, what did i miss ?
  • Does one need to add specific instructions to allocate shared resource on a context that is shared?
  • Is context sharing thread safe ? E.g can i use shared resources without caring about mutual exclusion ? (edit: using one does not solve any issue)
1
Since it's working if using CodeXL: After rendering to the texture, do you run glFlush or glFinish to "commit" the context command queue? Because you should. - Andreas
I was mistaken, it does not work on CodeXL (it executed another version of the program). glFlush does not solve the problem though - Adrien Grosjean

1 Answers

1
votes

Answering you questions:

Does one need to add specific instructions to allocate shared resource on a context that is shared?

No.

Is context sharing thread safe ? E.g can i use shared resources without caring about mutual exclusion?

Context sharing is not thread safe. Sharing is a consolidation of OpenGL object namespace.

But I suspect those answers do not help you at all. I'll keep going with an observation. Your error is strange because GL_INVALID_OPERATION is only generated in one scenario for glBindTexture:

GL_INVALID_OPERATION is generated if texture was previously created with a target that doesn't match that of target.

Which indicates there is a texture with the name textureHandle, just not with target GL_TEXTURE_2D. Perhaps the texture target is actually GL_TEXTURE_2D_MULTISAMPLE?

Of course there is the possibility that the sharing does not work for whatever reason. This should be easily found using just about any graphics debugger to list objects in each context; create in one, see if it pops up in the other.