Как поделиться контекстом или данными OpenGL?

Мне нужны общие данные (текстуры, буферы вершин и т. Д.) Для всех виджетов OpenGL в приложении.

Следующий код не работает:

Я нашел несколько решений, в которых один главный QGLWidget, а другие созданы с использованием этого основного виджета. К сожалению, я не могу использовать этот подход, потому что все мои QGLWidget равны и почти наверняка первый (основной) созданный QGLWidget будет уничтожен раньше других.

Возможный подход:

  • единый общий контекст OpenGL между всеми QGLWidgets
  • не работает: только один виджет QGLWidget отображается правильно, другие ведут себя так, как если бы они не отображались, поврежденные / случайные данные
  • ошибка для каждой QGLWidget конструкции, кроме первой:

    QGLWidget::setContext: Context must refer to this widget
    

Другой подход:

  • основной контекст OpenGL и создать подконтекст для каждого QGLWidget
  • не работает: context->isSharing() возвращает false
  • код, который я использую для создания контекста, context1 и context2 позже передаются конструкторам QGLWidgets:

    QGLContext *mainContext = new QGLContext(format), *context1, *context2;
    mainContext->create();
    context1 = new QGLContext(format);
    context1->create(mainContext);
    context2 = new QGLContext(format);
    context2->create(mainContext);
    cout << mainContext->isSharing() << " " <<  context1->isSharing() << endl;
    

person kravemir    schedule 06.01.2014    source источник
comment
... в вашем описании совместного использования ресурсов меня беспокоит. Не все объекты OpenGL являются общими, особенно весь класс объектов, называемых контейнерами. Объекты-контейнеры в OpenGL включают такие вещи, как объекты массива вершин и объекты буфера кадра. С этой целью общий конечный автомат хранится для каждого контекста, и это может объяснить, почему вещи ведут себя так, как если бы они были повреждены или случайны.   -  person Andon M. Coleman    schedule 06.01.2014
comment
Если я использую единый контекст, второй виджет QGLWidget действует так, как будто он даже не был отрисован, как если бы glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) не был выполнен   -  person kravemir    schedule 06.01.2014
comment
Это не то же самое, что совместное использование контекста. Это повторное использование того же контекста. Обычно контексты визуализации связаны с некоторой прямоугольной областью вашего окна на самом низком уровне (не путать с отображением области просмотра); Qt скрывает от вас реализацию оконной системы, но если вы хотите переключаться между виджетами, вам, вероятно, придется как-то переопределить эту область. Это, конечно, предполагает, что вы не рисуете каждый виджет в отдельном потоке, потому что это открывает совершенно другую банку с червями. У виджетов есть makeCurrent метод, который должен решить эту проблему.   -  person Andon M. Coleman    schedule 06.01.2014


Ответы (3)


Что касается первого подхода, вы не настраиваете совместное использование, а пытаетесь принудительно использовать один и тот же контекст с разными QGLWidgets. Как указывалось выше, это неправильно и работать не будет.

Вместо этого создайте QGLWidgets обычным образом и передайте первый QGLWidget в параметре shareWidget при создании остальных. Таким образом, вы получите отдельный контекст для каждого QGLWidget, но все они будут совместно использовать контекст первого (и, следовательно, друг с другом). См. http://qt-project.org/doc/qt-4.8/qglwidget.html#QGLWidget

Уничтожение первого виджета раньше других не должно быть проблемой, поскольку общие объекты будут присутствовать до тех пор, пока не будет активен какой-либо из контекстов совместного использования.

person Laszlo Agocs    schedule 07.01.2014
comment
Это объясняет, почему первый подход не работает, но почему второй тоже не работает? Все ли контексты равны, и каждый ли контекст может получить доступ к данным любого другого? - person kravemir; 09.01.2014
comment
Скорее всего, create () завершится неудачно (проверьте возвращаемое значение), поскольку QGLContext не может использоваться без устройства рисования (растрового изображения или QGLWidget). Соответствующие общедоступные API в QGLContext (например, конструктор, который также принимает QPaintDevice) давно устарели. По сути, вам следует избегать прямого использования QGLContext. Просто используйте QGLWidget и позвольте ему создавать и управлять контекстами за вас. - person Laszlo Agocs; 12.01.2014

Я понимаю, что прошел почти год с тех пор, как был задан этот вопрос, но я считаю, что приведенный выше комментарий может быть неточным.

Чтобы быть более точным, хотя использование одного QGLContext с несколькими QGLWidgets действительно может быть недопустимым, это было бы ограничением реализации OpenGL Qt, а не ограничением OpenGL или оконной системы. Конечно, кажется правильным использовать один и тот же контекст для визуализации в нескольких окнах. Например, функции wglMakeCurrent и SwapBuffers принимают в качестве параметров дескрипторы устройства наряду с дескрипторами контекста OpenGL. Процитируем документацию wglMakeCurrent:

Параметр hdc должен относиться к поверхности рисования, поддерживаемой OpenGL. Это не обязательно должен быть тот же самый hdc, который был передан в wglCreateContext при создании hglrc, но он должен быть на том же устройстве и иметь тот же формат пикселей.

Я даже не хочу вдаваться в проблемы со SwapBuffers, поскольку в Интернете есть несколько отчетов об ошибках, касающихся Qt5, которые, кажется, заставляют без необходимости делать контекст OpenGL текущим до вызова SwapBuffers.

person tabaci    schedule 24.11.2015

Это было обновлено, начиная с QT 5.4, и теперь вы должны использовать QOpenGLWidget вместо QGLWidget. Теперь в QOpenGLWidget было записано глобальное совместное использование контекстов, поэтому вам не нужно его кодировать самостоятельно. Вам просто нужно включить флаг совместного использования Qt :: AA_ShareOpenGLContexts перед созданием QGuiApplication.

person steventaitinger    schedule 13.01.2016