Я пытаюсь нарисовать графику, используя 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);
}
У кого-нибудь есть идеи, почему он не хочет работать на виртуальной машине?
Я действительно хотел быть конкретным, описывая мою проблему, но если у вас есть какие-либо дополнительные вопросы, пожалуйста, задавайте.
Вы создаете (новый) экземпляр QOpenGLFramebufferObject, только если _needsErase
когда-либо установлен верно.
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
,
Других решений пока нет …