c++qtopengl-esqt6

Qt6 OpenGL to OpenGL ES (3.2) code porting


I have a microcomputer with GLES hardware acceleration. It uses risc-V archtechure so no GL drivers.

I'm currently working on adapting a QOpenGLWindow codebase to run on a device with GLES hardware acceleration.

Running this code in GL 3.2 softpipe draws everything perfectly, but because there is no HW acceleration I get less than 1 FPS:

#include <QApplication>
#include <QOpenGLFunctions>
#include <QOpenGLWindow>
#include <QTimer>
#include <QImage>

class OpenGLWindow : public QOpenGLWindow, protected QOpenGLFunctions
{
    Q_OBJECT

public:
    explicit OpenGLWindow(QWidget* parent = nullptr) : QOpenGLWindow() {

        // Animation timer
        QTimer *timer = new QTimer(this);
        connect(timer, &QTimer::timeout, [this]() {
            this->angle += 1.0f;
            this->update();
        });
        timer->start(1); // 60 кадров в секунду
    }

    ~OpenGLWindow(){}

protected:
    void initializeGL() override;
    void paintGL() override;
    void resizeGL(int w, int h) override;

private:
    GLfloat arrow_vertices[9] = {
        1.0f, 0.0f, 0.0f, // Вершина 1
        -1.0f, 0.0f, 0.0f, // Вершина 2
        0.0f, 1.0f, 0.0f  // Вершина 3
    };
    GLfloat arrow_colors[9] = {
        1.0f, 1.0f, 1.0f, // Вершина 1
        1.0f, 1.0f, 1.0f, // Вершина 2
        1.0f, 1.0f, 1.0f  // Вершина 3
    };

    QImage horizontImage;
    GLuint horizontID;
    GLuint HUD_ID;

    // Arrow angle
    float angle = 0.0f;

    // Arrow center
    QPointF center;

    QSurfaceFormat format;
    QOpenGLFunctions *m_functions;
};

void OpenGLWindow::initializeGL()
{
    // Initialize OpenGL ES
    initializeOpenGLFunctions();

    std::string glVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
    std::string glslVer = reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
    qDebug("glVer: %s\nglslVer: %s", glVersion.c_str(), glslVer.c_str());

    // Enable 2D textures
    glEnable(GL_TEXTURE_2D);

    // Enable color blending for transparency
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);

    // Load the horizon image
    horizontImage.load(":/resource/res/horizon.png");
    horizontImage.convertTo(QImage::Format_RGBA8888);

    // Create a texture for the PNG
    glGenTextures(1, &horizontID);
    glBindTexture(GL_TEXTURE_2D, horizontID);

    // Set texture parameters
    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_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    // Load the PNG into the texture
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, horizontImage.width(), horizontImage.height(), 0,
                 GL_RGBA, GL_UNSIGNED_BYTE, horizontImage.bits());

    // Create a texture for the watermark
    glGenTextures(1, &HUD_ID);
    glBindTexture(GL_TEXTURE_2D, HUD_ID);

    // Set texture parameters
    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_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    // Load the watermark into the texture
    QImage watermarkImage(":/resource/res/Desk_PIL.png");
    watermarkImage.convertTo(QImage::Format_RGBA8888);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, watermarkImage.width(), watermarkImage.height(), 0,
                 GL_RGBA, GL_UNSIGNED_BYTE, watermarkImage.bits());
    qDebug() << "First bit:" << watermarkImage.bits()[0] << watermarkImage.bits()[1] << watermarkImage.bits()[2] << watermarkImage.bits()[3];

    glBindTexture(GL_TEXTURE_2D, 0);

    // Set the background color
    glClearColor(0.0f, 1.0f, 0.0f, 1.0f);

    // Define the rotation center
    center = QPointF(width() / 2, height() / 2);
}

void OpenGLWindow::paintGL()
{
    // Clear the buffer
    glClear(GL_COLOR_BUFFER_BIT);

    // Draw the background
    glLoadIdentity();
    glTranslatef(0, sin(angle/60)*20, 0.0f); // Pitch oscillation
    glRotatef(sin(angle/60/60)*0.05f, 0.0f, 0.0f, 1.0f); // Roll oscillation
    glBindTexture(GL_TEXTURE_2D, horizontID); // Set the texture to the horizon

    // Draw the rectangular background tile
    glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 0.0f); glVertex2f(0, height());
    glTexCoord2f(1.0f, 0.0f); glVertex2f(width(), height());
    glTexCoord2f(1.0f, 1.0f); glVertex2f(width(),0);
    glTexCoord2f(0.0f, 1.0f); glVertex2f(0,0);
    glEnd();

    // Set the projection matrix
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0f, width(), 0.0f, height(), -100.0f, 100.0f);

    // Set the modelview matrix
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // Translate to the rotation center
    glTranslatef(center.x(), center.y(), 0.0f);

    // Rotate the arrow
    glRotatef(angle, 0.0f, 0.0f, 1.0f);

    // Scale the arrow
    glScalef(10.0f,20.0f*3,1);

    // Draw a triangle
    glBindTexture(GL_TEXTURE_2D, 0);
    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(3, GL_FLOAT, 0, arrow_vertices);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glDisableClientState(GL_VERTEX_ARRAY);

    // Draw a watermark
    glLoadIdentity();
    glBindTexture(GL_TEXTURE_2D, HUD_ID);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 0.0f); glVertex2f(0, height());
    glTexCoord2f(1.0f, 0.0f); glVertex2f(width(), height());
    glTexCoord2f(1.0f, 1.0f); glVertex2f(width(),0);
    glTexCoord2f(0.0f, 1.0f); glVertex2f(0,0);
    glEnd();
}

void OpenGLWindow::resizeGL(int w, int h)
{
    center = QPointF(w / 2, h / 2);
    glViewport(0, 0, w, h);
}

static QSurfaceFormat createFormat(){
    QSurfaceFormat format;

    // OpenGL ES init
    format.setRenderableType(QSurfaceFormat::OpenGLES);
    format.setProfile(QSurfaceFormat::CoreProfile);
    format.setVersion(3,0);
    format.setDepthBufferSize(24);
    format.setStencilBufferSize(8);
    format.setSamples(4);
    return format;
}

int main(int argc, char *argv[])
{
    //// COMMENT FOR GL, UNCOMMENT FOR GLES
    // QSurfaceFormat format = createFormat(); 
    // QSurfaceFormat::setDefaultFormat(format);
    // QCoreApplication::setAttribute(Qt::AA_UseOpenGLES, true);
    // QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL, true);
    // QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL, false);
    QApplication app(argc, argv);
    OpenGLWindow w;
    w.show();

    w.showFullScreen();

    return app.exec();
}

However, when I run the code under GLES, I only see a green background. The vertices and textures are not being rendered.

Why might this be happening?


Solution

  • Why might this be happening?

    You can't use fixed-function pipeline functionality like glBegin() & friends on OpenGL ES 2.0+ contexts.

    You'll need to port your logic over to the programmable pipeline: shaders, VAOs, client-side matrix stack, etc.