Странное поведение OpenGL в QT при наследовании от QQuickItem против QQuickPaintedItem (рендеринг видео) - PullRequest
1 голос
/ 19 июня 2019

Этот вопрос является перезаписью Красного видео поверх обычного видео в Qt / OpenGL с использованием QQuickItem , но с кодом, разбитым до минимально проверяемого примера.Тем не менее, вы должны увидеть фотографии старого вопроса, потому что они показывают, что происходит, когда настоящее видео отображается на экране

У меня есть класс класса с именем OpenGlVideoQtQuick2, который я тестирую двумя возможными наследованиями.: от QQuickItem против QQuickPaintedItem.Я получаю ожидаемое поведение (гигантский красный экран), когда OpenGlVideoQtQuick2 наследует от QQuickItem, но не когда он наследует от QQuickPaintedItem, то есть когда я получаю черный экран размером 640x480, который является размером OpenGlVideoQtQuick2 элемент в main.qml.

Вот что происходит, когда class OpenGlVideoQtQuick2 : public QQuickPaintedItem enter image description here

Вот что происходит, когда class OpenGlVideoQtQuick2 : public QQuickItem enter image description here

Вот код:

OpenGlVideoQtQuick2.h:

#ifndef OpenGlVideoQtQuick2_H
#define OpenGlVideoQtQuick2_H

#include <QtQuick/QQuickItem>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLFunctions>
#include <QtQuick/qquickwindow.h>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLContext>
#include <QString>
#include <iostream>
#include <QTimer>
#include <QMatrix4x4>
#include <QQmlListProperty>
#include <QQuickPaintedItem>


class OpenGlVideoQtQuick2Renderer2 : public QObject, protected QOpenGLFunctions
{
    Q_OBJECT
public:
    OpenGlVideoQtQuick2Renderer2() {        
    }
    ~OpenGlVideoQtQuick2Renderer2();
    void setViewportSize(const QSize &size) { m_viewportSize = size; }
    void setWindow(QQuickWindow *window) { m_window = window; }

    QMatrix4x4 qQuickVideoMatrix;

public slots:
    void render();

private:
    QSize m_viewportSize;
    QOpenGLShaderProgram* program;
    QQuickWindow *m_window;
    GLuint unis[3] = {0};
    GLuint texs[3] = { 0 };
    unsigned char *datas[3] = { 0 };
    bool firstRender = true;
    int width = 0;
    int height = 0;
    int x = 0;
    int y = 0;
};

//class OpenGlVideoQtQuick2 : public QQuickItem
class OpenGlVideoQtQuick2 : public QQuickPaintedItem
{
    Q_OBJECT
protected:
    void paint(QPainter* painter){std::cout << "PAINT BEING USED" << std::endl;};

public:
    OpenGlVideoQtQuick2();
    QMatrix4x4 getModelMatrix();

signals:
    void tChanged();

public slots:
    void sync();
    void cleanup();
    void update();//Updates the window


private slots:
    void handleWindowChanged(QQuickWindow *win);

private:
    OpenGlVideoQtQuick2Renderer2 *openGlVideoQtQuick2Renderer2;

};

#endif // OpenGlVideoQtQuick2_H

OpenGlVideoQtQuick.cpp:

#include "OpenGlVideoQtQuick2.h"

#define GET_STR(x) #x
#define A_VER 3
#define T_VER 4

//Simple shader. Outpus the same location as input, I guess
const char *vString4 = GET_STR(
    attribute vec4 vertexIn;
    attribute vec2 textureIn;
    varying vec2 textureOut;
    uniform mat4 u_transform;   
    void main(void)
    {
        gl_Position = u_transform * vertexIn;
        textureOut = textureIn;
    }
);


const char *tString4 = GET_STR(
    varying vec2 textureOut;
    void main(void)
    {
        gl_FragColor = vec4(1.0,0,0, 1.0);
    }

);


void OpenGlVideoQtQuick2::update()
{
    if (window())
        window()->update();
}

OpenGlVideoQtQuick2::OpenGlVideoQtQuick2()
    : openGlVideoQtQuick2Renderer2(nullptr)
{
    connect(this, &QQuickItem::windowChanged, this, &OpenGlVideoQtQuick2::handleWindowChanged);
}


void OpenGlVideoQtQuick2::handleWindowChanged(QQuickWindow *win)
{
    if (win) {
        connect(win, &QQuickWindow::beforeSynchronizing, this, &OpenGlVideoQtQuick2::sync, Qt::DirectConnection);
        win->setClearBeforeRendering(false);
    }
}

void OpenGlVideoQtQuick2::cleanup()
{
   if (openGlVideoQtQuick2Renderer2) {
        delete openGlVideoQtQuick2Renderer2;
        openGlVideoQtQuick2Renderer2 = nullptr;
    }
}

OpenGlVideoQtQuick2Renderer2::~OpenGlVideoQtQuick2Renderer2()
{
    delete program;
}

void OpenGlVideoQtQuick2::sync()
{
    //std::cout << "sync called" << std::endl;
    if (!openGlVideoQtQuick2Renderer2) {
        openGlVideoQtQuick2Renderer2 = new OpenGlVideoQtQuick2Renderer2();
        connect(window(), &QQuickWindow::beforeRendering, openGlVideoQtQuick2Renderer2, &OpenGlVideoQtQuick2Renderer2::render, Qt::DirectConnection);
        connect(window(), &QQuickWindow::afterRendering, this, &OpenGlVideoQtQuick2::update, Qt::DirectConnection);
    }
}


static const GLfloat ver[] = {
    -1.0f,-1.0f,
     1.0f,-1.0f,
    -1.0f, 1.0f,
     1.0f, 1.0f
};

static const GLfloat tex[] = {
    0.0f, 1.0f,
    1.0f, 1.0f,
    0.0f, 0.0f,
    1.0f, 0.0f
};

//TODO: FIX THIS https://stackoverflow.com/a/54773889/6655884
void OpenGlVideoQtQuick2Renderer2::render()
{
    int frameWidth = 1280;
    int frameHeight = 720;
    if (this->firstRender) {
        std::cout << "Creating QOpenGLShaderProgram " << std::endl;
        program = new QOpenGLShaderProgram();
        initializeOpenGLFunctions();
        //this->m_F  = QOpenGLContext::currentContext()->functions();
        std::cout << "frameWidth: " << frameWidth << + " frameHeight: " << frameHeight << std::endl;
        datas[0] = new unsigned char[frameWidth*frameHeight];   //Y
        datas[1] = new unsigned char[frameWidth*frameHeight/4]; //U
        datas[2] = new unsigned char[frameWidth*frameHeight/4]; //V

        std::cout << "Fragment Shader compilation: " << program->addShaderFromSourceCode(QOpenGLShader::Fragment, tString4) << std::endl;
        std::cout << "Vertex Shader compilation: " << program->addShaderFromSourceCode(QOpenGLShader::Vertex, vString4) << std::endl;

        program->bindAttributeLocation("vertexIn",A_VER);
        program->bindAttributeLocation("textureIn",T_VER);
        std::cout << "program->link() = " << program->link() << std::endl;

        glGenTextures(3, texs);//TODO: ERASE THIS WITH glDeleteTextures
        this->firstRender = false;

    }
    program->bind();

    QMatrix4x4 transform;
    transform.setToIdentity();
    program->setUniformValue("u_transform", this->qQuickVideoMatrix);

    glVertexAttribPointer(A_VER, 2, GL_FLOAT, 0, 0, ver);
    glEnableVertexAttribArray(A_VER);

    glVertexAttribPointer(T_VER, 2, GL_FLOAT, 0, 0, tex);
    glEnableVertexAttribArray(T_VER);

    unis[0] = program->uniformLocation("tex_y");
    unis[1] = program->uniformLocation("tex_u");
    unis[2] = program->uniformLocation("tex_v");

    //Y
    glBindTexture(GL_TEXTURE_2D, texs[0]);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, frameWidth, frameHeight, 0, GL_RED, GL_UNSIGNED_BYTE, 0);

    //U
    glBindTexture(GL_TEXTURE_2D, texs[1]);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, frameWidth/2, frameHeight / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);

    //V
    glBindTexture(GL_TEXTURE_2D, texs[2]);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, frameWidth / 2, frameHeight / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texs[0]);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frameWidth, frameHeight, GL_RED, GL_UNSIGNED_BYTE, datas[0]);
    glUniform1i(unis[0], 0);


    glActiveTexture(GL_TEXTURE0+1);
    glBindTexture(GL_TEXTURE_2D, texs[1]); 
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frameWidth/2, frameHeight / 2, GL_RED, GL_UNSIGNED_BYTE, datas[1]);
    glUniform1i(unis[1],1);


    glActiveTexture(GL_TEXTURE0+2);
    glBindTexture(GL_TEXTURE_2D, texs[2]);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frameWidth / 2, frameHeight / 2, GL_RED, GL_UNSIGNED_BYTE, datas[2]);
    glUniform1i(unis[2], 2);

    glDrawArrays(GL_TRIANGLE_STRIP,0,4);

    program->disableAttributeArray(A_VER);
    program->disableAttributeArray(T_VER);
    program->release();
}

main.qml:

import QtQuick 2.0

import OpenGlVideoQtQuick2 1.0


Grid {
    columns: 2
    spacing: 2    
    width: 1280
    height: 720
    OpenGlVideoQtQuick2 {
        width: 640
        height: 360
    }

}

Итак, мне нужно, чтобы мой класс был производным от QQuickPaintedItem, а не QQuickItem, и мне нужен этот черный экранчтобы не отображаться поверх моего красного экрана, где будет загружено реальное видео.

Весь проект можно найти здесь: https://github.com/lucaszanella/QQuickPaintedItemBug/tree/c9c2b23d891689a63fbaf2f014142be1f3c5ff0d,, где вы можете скомпилировать и протестировать.Я рекомендую компилировать с использованием локально установленных папок cmake и qt, как описано в файле Readme.md в github

1 Ответ

2 голосов
/ 23 июня 2019

Я бы не ожидал, что результат использования QQuickItem и QQuickPaintedItem будет одинаковым.

Когда вы используете QQuickPaintedItem, вы должны визуализировать элемент, используя функцию paint().Поскольку вы вызываете свою render() функцию на beforeRendering(), то сразу после того, как вы сделаете свой собственный рендеринг, QQuickPaintedItem отобразит поверх него то, что вы должны были нарисовать в функции paint().

Вы можете предотвратить отображение QQuickPaintedItem черного прямоугольника, переопределив updatePaintNode() как пустую функцию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...