OpenGL падает на виртуальной машине (Ubuntu 16.04), настроенной на VMWare Fusion Version 10.1.3. - PullRequest
0 голосов
/ 05 октября 2018

Я пытаюсь нарисовать графику, используя OpenGL.Я использую VMWare Fusion Version 10.1.3 с Ubuntu 16.04 и QtCreator 4.6.2.

Моя задача - воспроизвести запись с некоторым рисунком в OpenGL.В этом случае мне нужно FBO, чтобы увеличить содержимое моего рисунка и создать изображение в конце записи, а также мне нужно, чтобы текстура отображалась на экране во время воспроизведения записи.

Моя проблема в том, что у меня происходит постоянный сбой при уничтожении объекта, в котором я использую OpenGL.

Вот мой код:

void DrawingView::paint(QPainter *painter) {

    painter->beginNativePainting();
    if(_needsErase) {

        QOpenGLContext  *context = QOpenGLContext::currentContext();

        _frameBuffer = new QOpenGLFramebufferObject(QSize(_rect.width(), _rect.height()), _format);

        glBindTexture(GL_TEXTURE_2D, _frameBuffer->texture());
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

        glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _rect.width(), _rect.height(), 0,  GL_RGBA , GL_UNSIGNED_BYTE, 0);

        glBindTexture(GL_TEXTURE_2D, 0);

        _frameBuffer->bind();
        {
            glClearColor(0.0, 0.0, 0.0, 0.0);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        }
        _frameBuffer->release();

        _needsErase = false;
    }

    glEnable(GL_BLEND);

    _frameBuffer->bind();
    { // here I'm drawing to my fbo, this part is irrelevant. }
    _frameBuffer->release();

    _shaderProgram->release();

    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

    glUniform1i(_tex0Uniform, 0);
    _copyBuffer->bind();

    glActiveTexture(GL_TEXTURE0);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, _frameBuffer->texture());

    glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
    glEnableVertexAttribArray(ATTRIB_VERTEX);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture( GL_TEXTURE_2D, 0);
    glDisable(GL_TEXTURE_2D);

    _copyBuffer->release();

    glDisable(GL_BLEND);

    painter->endNativePainting();
}

Приложение вылетает при уничтожении моего DrawingView объекта после строки delete _frameBuffer; с журналом:

context mismatch in svga_surface_destroy
VMware: vmw_ioctl_command error Invalid argument.

Вот как яосвобождаю мой DrawingView объект.

void DrawingView::cleanupGL() {
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    _shaderProgram->release();
    _frameBuffer->release();
    _copyBuffer->release();

    delete _shaderProgram;
    delete _copyBuffer;
    delete _frameBuffer;

    glDeleteBuffers(1, &_ebo);
    glDeleteBuffers(1, &_vbo);
}

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

Я использовал этот код также на macOS, и там все работало ОТЛИЧНО, но, к сожалению, мне нужно использовать этот код на виртуальной машине с Ubuntu.

Вот также код моей вершины и фрагменташейдеры:

вершинный шейдер:

uniform vec2 screenSize;
attribute vec2 position;
varying vec2 coord;

void main(void)
{
    coord = position;
    vec2 halfScreenSize = screenSize * 0.5f;
    vec2 pos = halfScreenSize * position + halfScreenSize;
    gl_Position = gl_ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0);
}

фрагментный шейдер:

uniform sampler2D tex0;
varying vec2 coord;

void main(void)
{
    vec2 coords = coord * 0.5 + 0.5;
    gl_FragColor = texture2D(tex0, coords.xy);
}

У кого-нибудь есть идеи, почему он не хочет работать на виртуальной машине?

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

1 Ответ

0 голосов
/ 06 октября 2018

Вы создаете (новый) экземпляр QOpenGLFramebufferObject, только если _needsErase когда-либо установлен в значение true.

if(_needsErase) {
        QOpenGLContext  *context = QOpenGLContext::currentContext();
        _frameBuffer = new QOpenGLFramebufferObject(…

Если этого не произойдет, это будет неинициализированный указатель, и вызов функций-членов на нем вызовет неопределенное поведение.Этот конкретный код неверен в любом случае, потому что он никогда не удаляет тот экземпляр, на который мог указывать _frameBuffer перед перезаписью указателя.

Вместо ручного управления памятью я настоятельно советую использовать автоматические конструкции.Я ценю необходимость динамического создания экземпляра в этом конкретном случае.Это можно сделать либо через std::shared_ptr, либо через std::unique_ptr.Я настоятельно рекомендую начать с std::unique_ptr и изменить его на общий указатель, только если это абсолютно необходимо.

В вашем DrawingView class

#include <memory>
class DrawingView : public ... {
    ...
protected:
    std::unique_ptr<QOpenGLFramebufferObject> _frameBuffer;
    ...
};

в методе DrawingView::paint:

 if(_needsErase) {
         QOpenGLContext  *context = QOpenGLContext::currentContext();
         _frameBuffer = std::make_unique<QOpenGLFramebufferObject>(…

Не использовать new или delete.

...