Создание ресурсов в определенном контексте

У меня есть приложение Qt OpenGL, которое использует QOpenGLWidget для рендеринга контента. В другом классе (назовем его Resources) я хочу создать для этого виджета ресурсы OpenGL, такие как VBO, VAO, шейдерные программы и т. д. Этот метод создания вызывается не QOpenGLWidget, а внешним вызывающим объектом.

По какой-то причине в моем приложении существует два контекста OpenGL (один, вероятно, используется для графического интерфейса, а другой для QOpenGLWidget). Следовательно, когда вызывается метод создания ресурса, я не могу быть уверен, что правильный контекст активен. Поэтому, когда я звоню

QOpenGLVertexArrayObject vao;
vao.create();

в классе Resources я не могу быть уверен, что этот VAO создан в правильном контексте. Класс Resources не имеет доступа к виджету. Таким образом, context.makeCurrent() назвать нельзя (потому что я не знаю поверхности).

Есть ли прямой способ указать контекст, в котором должны создаваться ресурсы? Хранение поверхности в файле ресурсов (вместе с контекстом) кажется очень неаккуратным.


person Nico Schertler    schedule 11.05.2016    source источник
comment
Разве этот внешний вызывающий объект не может вызвать yourOpenGLWidget->makeCurrent() перед инициализацией ресурсов GL?   -  person peppe    schedule 11.05.2016
comment
@peppe Нет, вызывающий абонент не знает виджет. Он даже не знает о существовании OpenGL. Вызов в основном загружает некоторые данные. И эта самая реализация Resources также создает ресурсы OpenGL. Другие нет.   -  person Nico Schertler    schedule 11.05.2016
comment
Хм, почему бы вам просто не вернуть вектор данных и не позволить какому-нибудь другому объекту с доступом к правильному контексту построить VBO и VAO?   -  person x squared    schedule 12.05.2016
comment
@xsquared Класс Resources имеет доступ к контексту. Но контекст сам по себе здесь не поможет, потому что связанная с ним поверхность отсутствует. Да, я тоже мог бы пройти по поверхности, но я бы этого избегал. У меня есть обходной путь на основе IOC, реализованный прямо сейчас, но я хотел бы посмотреть, есть ли прямой способ использования определенного контекста.   -  person Nico Schertler    schedule 12.05.2016
comment
Ах, извините. Замените «контекст» на «поверхность» в моем предыдущем комментарии. Я не знаю вашей конкретной структуры, но построение объектов openGL позже не кажется мне плохим решением… Тем более, что, насколько я знаю, вызовы OpenGL должны заботиться только о существовании контекста, а не о том, кто им владеет. Так что явное указание его здесь звучит для меня скорее как взлом — независимо от вопроса, возможно ли это вообще.   -  person x squared    schedule 12.05.2016
comment
Или, в качестве альтернативы, ваш внешний вызывающий объект может излучать сигнал перед вызовом класса Resources. Поскольку код после сигнала ожидает возврата всех слотов, поверхность может сделать его контекст актуален до того, как ресурсы начнут работать.   -  person x squared    schedule 12.05.2016


Ответы (1)


Судя по всему, нет возможности создавать ресурсы для конкретного контекста. Я работал над этой проблемой со следующей структурой:

Я создал интерфейс OpenGLContextProvider, который очень прост:

class OpenGLContextProvider
{
public:
    virtual void MakeOpenGLContextCurrent() = 0;
};

Виджет OpenGL реализует этот интерфейс:

class GLView : public QOpenGLWidget, public OpenGLContextProvider
{
    //...
};
void GLView::MakeOpenGLContextCurrent()
{
    makeCurrent();
}

Таким образом, OpenGLContextProvider (то есть виджет OpenGL) внедряется в конструктор объекта Resource. Прежде чем ему понадобится контекст, он вызывает соответствующий метод:

void Resources::LoadSomeData()
{
    //Load data...

    //Create OpenGL resources
    ctx->MakeOpenGLContextCurrent(); //ctx is of type OpenGLContextProvider*
    vao.create(); //is now on the correct context
    //etc.
}
person Nico Schertler    schedule 13.05.2016