Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

#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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading