*rest of the owl*
authorMateusz Majewski <m.majewski2@samsung.com>
Tue, 25 Mar 2025 13:39:30 +0000 (14:39 +0100)
committerMateusz Majewski <m.majewski2@samsung.com>
Tue, 25 Mar 2025 14:15:39 +0000 (15:15 +0100)
Change-Id: I825083e7e8a83b35877894a1809bccc0bcc09f8f

package/build.linux
tizen/emulator_configure.sh
tizen/src/hw/pci/maru_brightness.c
tizen/src/ui/displayglwidget.cpp
tizen/src/ui/displayglwidget.h
tizen/src/ui/mainwindow.cpp
tizen/src/ui/qt5.c
tizen/src/ui/qt5_supplement.cpp
tizen/src/ui/qt5_supplement.h
vl.c

index 095c992ab5d2d0a3393d73d54a5345e3b11d0ad4..2f9303c4a2934a2ab5dad30f2365f50b9eac377c 100755 (executable)
@@ -22,6 +22,10 @@ prepare()
                        export CROSS_PREFIX=x86_64-w64-mingw32
                fi
 
+               cp $SRCDIR/deps/lib/* $ROOTDIR/lib/
+               cp $SRCDIR/deps/pc/* $ROOTDIR/lib/pkgconfig
+               cp -r $SRCDIR/deps/include/* $ROOTDIR/include
+
                # correct pc's prefix since windows install script is not run
                # on linux
                cd ${ROOTDIR}/lib/pkgconfig
@@ -36,7 +40,8 @@ prepare()
 
                REQUIRED_PKG="ant python3 zlib1g-dev libglib2.0-dev libsdl1.2-dev \
                        libasound2-dev libx11-dev libv4l-dev libxcomposite-dev \
-                       libpixman-1-dev libcurl4-gnutls-dev     libcap-dev libattr1-dev"
+                       libpixman-1-dev libcurl4-gnutls-dev     libcap-dev libattr1-dev \
+                       libvirglrenderer-dev libepoxy-dev libgbm-dev libdrm-dev"
 
                echo "Checking required packages before compling!!"
                for pkg in ${REQUIRED_PKG}
index aebfa088447d5d62152764049208aee3b646c3d1..89dbfb5842e819ceac99991dbe06024f63c6dd1f 100755 (executable)
@@ -148,6 +148,8 @@ CONFIGURE_APPEND="
  --disable-spice
  --disable-curses
  --disable-xen
+ --enable-virglrenderer
+ --enable-opengl
  $CONFIGURE_APPEND"
 
 CONFIGURE_APPEND_WIN="
index 225fa77d89f52201e990ee501d0dcfcf3173b68b..9e4c7b6d13e348b212b23643c96b886610947fea 100644 (file)
@@ -38,6 +38,7 @@
 #include "hw/maru_device_ids.h"
 #include "maru_brightness.h"
 #include "debug_ch.h"
+#include "qt5_supplement.h"
 
 MULTI_DEBUG_CHANNEL(tizen, brightness);
 
@@ -137,7 +138,12 @@ static void maru_pixman_image_set_alpha(uint8_t value)
     level_color.alpha = value << 8;
     brightness_image = pixman_image_create_solid_fill(&level_color);
 
-    graphic_hw_invalidate(NULL);
+#ifdef CONFIG_OPENGL
+    if (display_opengl)
+        qt5_gl_display_force_redraw();
+    else
+#endif
+        graphic_hw_invalidate(NULL);
 }
 
 static void brightness_reg_write(void *opaque,
index 9f9dc890678d3f310cd17ff6436abaacd723e375..4b55d25745156984d20e53fd20b4d374f114d734 100644 (file)
@@ -225,6 +225,10 @@ DisplayGLWidget::DisplayGLWidget(QWidget *parent,
     mFuncs = NULL;
     mVAO = NULL;
     mVBO = NULL;
+
+#ifdef CONFIG_OPENGL
+    offscreen = NULL;
+#endif
 }
 
 void DisplayGLWidget::changedTexture(struct dpy_item *item)
@@ -242,6 +246,57 @@ void DisplayGLWidget::changedTexture(struct dpy_item *item)
     this->update();
 }
 
+#ifdef CONFIG_OPENGL
+QOpenGLContext *DisplayGLWidget::createSharedContext(int major, int minor)
+{
+    auto glob = context();
+    if (!glob)
+        return nullptr;
+
+    QSurfaceFormat fmt;
+#ifdef CONFIG_DARWIN
+    fmt.setVersion(4, 1);
+    fmt.setProfile(QSurfaceFormat::CoreProfile);
+#else
+    fmt.setVersion(major, minor);
+    fmt.setProfile(QSurfaceFormat::CompatibilityProfile);
+    fmt.setOption(QSurfaceFormat::DeprecatedFunctions);
+#endif
+
+    if (!offscreen) {
+        offscreen = new(std::nothrow) QOffscreenSurface;
+        if (!offscreen)
+            return nullptr;
+
+        offscreen->create();
+
+        if (!offscreen->isValid()) {
+            offscreen->destroy();
+            offscreen = nullptr;
+            return nullptr;
+        }
+    }
+
+    auto ctx = new(std::nothrow) QOpenGLContext;
+    if (!ctx)
+        return nullptr;
+
+    ctx->setFormat(fmt);
+    ctx->setShareContext(glob);
+
+    if (!ctx->create())
+        return nullptr;
+
+    return ctx;
+}
+
+bool DisplayGLWidget::activateSharedContext(QOpenGLContext *ctx)
+{
+    // TODO: Context loss???
+    return ctx->makeCurrent(offscreen);
+}
+#endif
+
 float DisplayGLWidget::getBrightness()
 {
     if (display_off) {
@@ -576,6 +631,12 @@ DisplayGLWidget::~DisplayGLWidget()
     if (maskTexture) {
         mFuncs->glDeleteTextures(1, &maskTexture);
     }
+#ifdef CONFIG_OPENGL
+    if (offscreen) {
+        offscreen->destroy();
+        delete offscreen;
+    }
+#endif
     mVAO->destroy();
     mVBO->destroy();
     texProgram->removeAllShaders();
index 26cf7cf96a779b96dfa2e55647b6447d37b1ef87..6042b88ee2dac13c56cd991ee5c61a02bf0cccf4 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "displaybase.h"
 #include <QMutex>
+#include <QOffscreenSurface>
 #include <QOpenGLWidget>
 #include <QMatrix4x4>
 
@@ -53,6 +54,8 @@ struct dpy_item {
 };
 }
 
+// TODO: This probably should not be included directly.
+#include "config-host.h"
 
 class QOpenGLFunctions;
 class QOpenGLShaderProgram;
@@ -72,6 +75,11 @@ public:
 
     void changedTexture(struct dpy_item *tex);
 
+#ifdef CONFIG_OPENGL
+    QOpenGLContext *createSharedContext(int major, int minor);
+    bool activateSharedContext(QOpenGLContext *ctx);
+#endif
+
 protected:
     void initializeGL();
     void paintGL();
@@ -113,6 +121,9 @@ private:
     QOpenGLShaderProgram *texProgram;
     QOpenGLShaderProgram *scaleProgram;
 
+#ifdef CONFIG_OPENGL
+    QOffscreenSurface *offscreen;
+#endif
 };
 
 #endif // DISPLAYGLWIDGET_H
index ce3e35b365bba4bbcff07a8c700e7f747a8b203f..cafadff8e58104179946284eddb2a84d9220d87a 100644 (file)
@@ -125,6 +125,9 @@ void MainWindow::createDisplay(maru_display_type display_type)
 
     switch (display_type) {
     case MARU_DISPLAY_TYPE_ONSCREEN:
+#ifdef CONFIG_OPENGL
+    case MARU_DISPLAY_TYPE_GL:
+#endif
         this->display = new DisplayGLWidget(this,
             uiInfo->getMainFormDpyType(), uiInfo->getResolution(), getUiState()->getScaleFactor());
         break;
index 6007112785bfb6e7ccb39f3334f1d5ce6c2d5a41..e7e5d4f24fda22f646bf30843a328c2604bbb273 100644 (file)
@@ -54,6 +54,17 @@ static struct qt5_state {
     DisplaySurface *surface;
 
     int idx;
+
+#ifdef CONFIG_OPENGL
+    uint64_t gen;
+    bool updated;
+    ConsoleGLState *gls;
+    QEMUGLContext ctx;
+    bool is_scanout;
+    uint32_t scanout_fbs[2];
+    bool backing_y_0_top;
+    uint32_t backing_width, backing_height;
+#endif
 } *qt5_console;
 
 void qt5_graphic_hw_invalidate(void)
@@ -129,6 +140,176 @@ static const DisplayChangeListenerOps dcl_ops = {
     .dpy_cursor_define = qt5_mouse_define,
 };
 
+#ifdef CONFIG_OPENGL
+static void qt5_gl_update(DisplayChangeListener *dcl,
+                       int x, int y, int w, int h)
+{
+    struct qt5_state *con = container_of(dcl, struct qt5_state, dcl);
+
+    if (con->is_scanout)
+        return;
+
+    if (con->ctx)
+        qt5_gl_make_context_current_internal(con->ctx);
+    surface_gl_update_texture(con->gls, con->surface, x, y, w, h);
+    con->updated = true;
+
+    /* Note that, unlike non-GL, we do not call composite_brightness_image.
+     * In this case, brightness rendering is the responsibility of the display. */
+}
+
+static void qt5_gl_switch(DisplayChangeListener *dcl,
+                       DisplaySurface *new_surface)
+{
+    struct qt5_state *con = container_of(dcl, struct qt5_state, dcl);
+
+    if (con->ctx)
+        qt5_gl_make_context_current_internal(con->ctx);
+
+    surface_gl_destroy_texture(NULL, con->surface);
+
+    if (new_surface && !con->gls) {
+        con->gls = console_gl_init_context();
+    } else if (!new_surface && con->gls) {
+        console_gl_fini_context(con->gls);
+        con->gls = NULL;
+        return;
+    } else if (con->surface &&
+            (surface_width(con->surface) != surface_width(new_surface) ||
+             surface_height(con->surface) != surface_height(new_surface))) {
+        // TODO: we should adjust display size.
+        // We should warn to user since we can not adjust display size now.
+        LOG_WARNING("display size is changed.\n");
+    }
+
+    con->surface = new_surface;
+    con->gen += 1;
+    // TODO: con->is_scanout?
+    surface_gl_create_texture(con->gls, con->surface);
+}
+
+static void qt5_gl_refresh(DisplayChangeListener *dcl)
+{
+    struct qt5_state *con = container_of(dcl, struct qt5_state, dcl);
+
+    if (con->ctx)
+        qt5_gl_make_context_current_internal(con->ctx);
+
+    graphic_hw_update(dcl->con);
+    qt5_refresh_internal();
+    if (con->surface && !con->is_scanout && con->updated) {
+        bool should_free;
+        con->surface->texture = qt5_gl_refresh_internal(con->surface->texture, surface_width(con->surface), surface_height(con->surface), con->gen, &should_free);
+        if (should_free) {
+            surface_gl_destroy_texture(con->gls, con->surface);
+        }
+        if (con->surface->texture == 0) {
+            surface_gl_create_texture(con->gls, con->surface);
+        }
+        con->updated = false;
+    }
+}
+
+static QEMUGLContext qt5_gl_create_context(DisplayChangeListener *dcl,
+                                     QEMUGLParams *params)
+{
+    return qt5_gl_create_context_internal(params->major_ver, params->minor_ver);
+}
+
+static void qt5_gl_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx)
+{
+    qt5_gl_destroy_context_internal(ctx);
+}
+
+static int qt5_gl_make_context_current(DisplayChangeListener *dcl,
+                                 QEMUGLContext ctx)
+{
+    return qt5_gl_make_context_current_internal(ctx);
+}
+
+static QEMUGLContext qt5_gl_get_current_context(DisplayChangeListener *dcl)
+{
+    return qt5_gl_get_current_context_internal();
+}
+
+static void qt5_gl_scanout(DisplayChangeListener *dcl,
+                     uint32_t backing_id, bool backing_y_0_top,
+                     uint32_t backing_width, uint32_t backing_height,
+                     uint32_t x, uint32_t y,
+                     uint32_t w, uint32_t h)
+{
+    struct qt5_state *con = container_of(dcl, struct qt5_state, dcl);
+
+    if (backing_id == 0) {
+        con->is_scanout = false;
+        return;
+    }
+    con->is_scanout = true;
+
+    if (con->ctx)
+        qt5_gl_make_context_current_internal(con->ctx);
+
+    con->backing_y_0_top = backing_y_0_top;
+    con->backing_width = backing_width;
+    con->backing_height = backing_height;
+
+    if (con->scanout_fbs[0] == 0) {
+        // TODO: these leak?
+        glGenFramebuffers(2, con->scanout_fbs);
+    }
+
+    glBindFramebuffer(GL_READ_FRAMEBUFFER, con->scanout_fbs[0]);
+    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, con->scanout_fbs[1]);
+    glFramebufferTexture2DEXT(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT,
+                              GL_TEXTURE_2D, backing_id, 0);
+
+}
+
+static void qt5_gl_scanout_flush(DisplayChangeListener *dcl,
+                           uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+{
+    struct qt5_state *con = container_of(dcl, struct qt5_state, dcl);
+
+    if (con->ctx)
+        qt5_gl_make_context_current_internal(con->ctx);
+
+    glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT,
+                              GL_TEXTURE_2D, con->surface->texture, 0);
+
+    uint32_t y1 = con->backing_y_0_top ? con->backing_height : 0;
+    uint32_t y2 = con->backing_y_0_top ? 0 : con->backing_height;
+    glBlitFramebuffer(0, y1, con->backing_width, y2,
+                      0, 0, surface_width(con->surface), surface_height(con->surface),
+                      GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+    bool should_free;
+    con->surface->texture = qt5_gl_refresh_internal(con->surface->texture, surface_width(con->surface), surface_height(con->surface), con->gen, &should_free);
+    if (should_free) {
+        surface_gl_destroy_texture(con->gls, con->surface);
+    }
+    if (con->surface->texture == 0) {
+        surface_gl_create_texture(con->gls, con->surface);
+    }
+}
+
+static const DisplayChangeListenerOps dcl_gl_ops = {
+    .dpy_name             = "qt5-gl",
+    .dpy_gfx_update       = qt5_gl_update,
+    .dpy_gfx_switch       = qt5_gl_switch,
+    .dpy_gfx_check_format = console_gl_check_format,
+    .dpy_refresh          = qt5_gl_refresh,
+    .dpy_mouse_set        = qt5_mouse_warp,
+    .dpy_cursor_define    = qt5_mouse_define,
+
+    .dpy_gl_ctx_create       = qt5_gl_create_context,
+    .dpy_gl_ctx_destroy      = qt5_gl_destroy_context,
+    .dpy_gl_ctx_make_current = qt5_gl_make_context_current,
+    .dpy_gl_ctx_get_current  = qt5_gl_get_current_context,
+    .dpy_gl_scanout          = qt5_gl_scanout,
+    .dpy_gl_update           = qt5_gl_scanout_flush,
+};
+#endif
+
 void maru_early_qt5_display_init(enum maru_display_type display_type)
 {
 #ifdef CONFIG_DARWIN
@@ -156,6 +337,11 @@ void maru_early_qt5_display_init(enum maru_display_type display_type)
     case MARU_DISPLAY_TYPE_OFFSCREEN:
         LOG_INFO("Display Type: QT5 Offscreen\n");
         break;
+#ifdef CONFIG_OPENGL
+    case MARU_DISPLAY_TYPE_GL:
+        LOG_INFO("Display Type: QT5 GL\n");
+        break;
+#endif
     }
 }
 
@@ -205,9 +391,22 @@ void maru_qt5_display_init(DisplayState *ds, int full_screen)
     }
     qt5_num_outputs = i;
     qt5_console = g_new0(struct qt5_state, qt5_num_outputs);
+#ifdef CONFIG_OPENGL
+    qt5_gl_init_items();
+#endif
     for (i = 0; i < qt5_num_outputs; i++) {
         QemuConsole *con = qemu_console_lookup_by_index(i);
+#ifdef CONFIG_OPENGL
+        qt5_console[i].dcl.ops = display_opengl ? &dcl_gl_ops : &dcl_ops;
+        qt5_console[i].gen = 0;
+        qt5_console[i].updated = false;
+        qt5_console[i].gls = NULL;
+        qt5_console[i].ctx = display_opengl ? qt5_gl_create_context_internal(3, 3) : NULL;
+        qt5_console[i].is_scanout = false;
+        qt5_console[i].scanout_fbs[0] = 0;
+#else
         qt5_console[i].dcl.ops = &dcl_ops;
+#endif
         qt5_console[i].dcl.con = con;
         register_displaychangelistener(&qt5_console[i].dcl);
         qt5_console[i].idx = i;
index 113ac3dd07b9d93f691cbaba09d11c89c839e93b..571457efacfd2b4f6adc01eff26ddbaa7b9d64f9 100644 (file)
  *
  */
 
+#include <memory>
+
 #include <QApplication>
 #include <QOpenGLContext>
 
 #include "qt5_supplement.h"
+#include "displayglwidget.h"
 #include "propertykeyword.h"
 #include "mainwindow.h"
 #include "layout/hardwarekey.h"
@@ -40,6 +43,9 @@
 #include "resource/ui_strings.h"
 #include "displaybase.h"
 
+// TODO: Figure out the compilation
+extern int display_opengl;
+
 #include "util/new_debug_ch.h"
 // XXX: all modules in ui/* are controlled by channel name "qt5_ui"
 DECLARE_DEBUG_CHANNEL(qt5_ui);
@@ -443,10 +449,13 @@ void qt5_set_force_legacy(bool isLegacy)
 void qt5_early_prepare(enum maru_display_type _display_type)
 {
     display_type = _display_type;
+#ifdef CONFIG_OPENGL
+    display_opengl = display_type == MARU_DISPLAY_TYPE_GL;
+#endif
 
     Q_INIT_RESOURCE(resource);
 
-    if (display_type == MARU_DISPLAY_TYPE_ONSCREEN) {
+    if (display_type == MARU_DISPLAY_TYPE_ONSCREEN || display_type == MARU_DISPLAY_TYPE_GL) {
         QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
         QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
 
@@ -600,3 +609,103 @@ void qt5_update_texture(void *dpy_item)
         mainwindow->updateTexture(dpy_item);
     }
 }
+
+#ifdef CONFIG_OPENGL
+#define DPY_ITEM_NO 5
+static dpy_item dpy_item_pool[DPY_ITEM_NO];
+static uint64_t dpy_item_gen[DPY_ITEM_NO];
+
+void qt5_gl_init_items()
+{
+    for (int i = 0; i < DPY_ITEM_NO; ++i) {
+        qemu_mutex_init(&dpy_item_pool[i].mutex);
+        dpy_item_pool[i].available = true;
+    }
+}
+// TODO: Is there a good place to put this?
+/* void qt5_gl_destroy_items()
+{
+    for (int i = 0; i < DPY_ITEM_NO; ++i) {
+        qemu_mutex_destroy(&dpy_item_pool[i].mutex);
+    }
+} */
+
+uint32_t qt5_gl_refresh_internal(uint32_t tex, uint32_t width, uint32_t height, uint64_t gen, bool *should_free)
+{
+    uint32_t ret = tex;
+    *should_free = false;
+
+    if (mainwindow) {
+        int item_id = 0;
+        while (true)
+        {
+            auto item = &dpy_item_pool[item_id];
+            qemu_mutex_lock(&item->mutex);
+            bool ok = item->available;
+            if (ok) {
+                ret = item->tex;
+                if (dpy_item_gen[item_id] != gen || /* HACK HACK HACK */ item->tex < 25) {
+                    /* This tells the caller that the texture should not be used anymore.
+                     * Preferably we could handle this right here, but the caller can do it
+                     * conveniently and I couldn't get compilation to work. */
+                    dpy_item_gen[item_id] = gen;
+                    *should_free = true;
+                }
+                item->tex = tex;
+                item->width = width;
+                item->height = height;
+                item->available = false;
+            }
+            qemu_mutex_unlock(&item->mutex);
+            if (ok) {
+                mainwindow->updateTexture(item);
+                break;
+            }
+            item_id++;
+            if (item_id == DPY_ITEM_NO) {
+                break;
+            }
+        }
+
+    }
+
+    return ret;
+}
+
+void *qt5_gl_create_context_internal(int major, int minor)
+{
+    if (mainwindow) {
+        return ((DisplayGLWidget *)mainwindow->getDisplay())->createSharedContext(major, minor);
+    } else {
+        return nullptr;
+    }
+}
+
+void qt5_gl_destroy_context_internal(void *_ctx)
+{
+    auto ctx = (QOpenGLContext *)_ctx;
+    delete ctx;
+}
+
+int qt5_gl_make_context_current_internal(void *_ctx)
+{
+    auto ctx = (QOpenGLContext *)_ctx;
+    if (mainwindow) {
+        return ((DisplayGLWidget *)mainwindow->getDisplay())->activateSharedContext(ctx) ? 0 : -1;
+    } else {
+        return -1;
+    }
+}
+
+void *qt5_gl_get_current_context_internal()
+{
+    return QOpenGLContext::currentContext();
+}
+
+void qt5_gl_display_force_redraw()
+{
+    if (mainwindow) {
+        ((DisplayGLWidget *)mainwindow->getDisplay())->update();
+    }
+}
+#endif
index 73b82e0360cda8164c50773fe5bbfa7a04970aac..80a66f57403d0dfa12d0bfef6747df6ff180cd60 100644 (file)
 #ifndef __QT5_INTERNAL_H__
 #define __QT5_INTERNAL_H__
 
+#include <stdint.h>
+
+// TODO: This probably should not be included directly.
+#include "config-host.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -38,6 +43,9 @@ extern "C" {
 enum maru_display_type {
     MARU_DISPLAY_TYPE_ONSCREEN,
     MARU_DISPLAY_TYPE_OFFSCREEN,
+#ifdef CONFIG_OPENGL
+    MARU_DISPLAY_TYPE_GL,
+#endif
 };
 
 void qt5_graphic_hw_invalidate(void);
@@ -54,6 +62,18 @@ void qt5_refresh_internal(void);
 const char* qt5_get_version(void);
 
 void qt5_set_force_legacy(bool isLegacy);
+
+#ifdef CONFIG_OPENGL
+void qt5_gl_init_items(void);
+// void qt5_gl_destroy_items(void);
+uint32_t qt5_gl_refresh_internal(uint32_t tex, uint32_t width, uint32_t height, uint64_t gen, bool *should_free);
+void *qt5_gl_create_context_internal(int major, int minor);
+void qt5_gl_destroy_context_internal(void *);
+int qt5_gl_make_context_current_internal(void *_ctx);
+void *qt5_gl_get_current_context_internal(void);
+void qt5_gl_display_force_redraw(void);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/vl.c b/vl.c
index 3317a1424bc7697a4baab1c134454fce86d957b1..04eaea037d51db8a0adebbcd74a5176ded071360 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -2157,6 +2157,9 @@ typedef enum DisplayType {
 # ifdef CONFIG_QT
     DT_MARU_QT_ONSCREEN,
     DT_MARU_QT_OFFSCREEN,
+#  ifdef CONFIG_OPENGL
+    DT_MARU_QT_GL,
+#  endif
 # endif
 #endif
     DT_NONE,
@@ -2297,6 +2300,10 @@ static DisplayType select_display(const char *p)
                     display = DT_MARU_QT_ONSCREEN;
                 } else if (strstart(opts, "offscreen", &nextopt)) {
                     display = DT_MARU_QT_OFFSCREEN;
+#  ifdef CONFIG_OPENGL
+                } else if (strstart(opts, "gl", &nextopt)) {
+                    display = DT_MARU_QT_GL;
+#  endif
                 } else {
                     goto invalid_maru_qt_args;
                 }
@@ -4492,6 +4499,10 @@ int main(int argc, char **argv, char **envp)
         maru_early_qt5_display_init(MARU_DISPLAY_TYPE_ONSCREEN);
     } else if (display_type == DT_MARU_QT_OFFSCREEN) {
         maru_early_qt5_display_init(MARU_DISPLAY_TYPE_OFFSCREEN);
+#  ifdef CONFIG_OPENGL
+    } else if (display_type == DT_MARU_QT_GL) {
+        maru_early_qt5_display_init(MARU_DISPLAY_TYPE_GL);
+#  endif
     }
 # endif
 #endif
@@ -4841,6 +4852,9 @@ int main(int argc, char **argv, char **envp)
  #if defined(CONFIG_QT)
     case DT_MARU_QT_ONSCREEN:
     case DT_MARU_QT_OFFSCREEN:
+  #if defined(CONFIG_OPENGL)
+    case DT_MARU_QT_GL:
+  #endif
         if (!is_maru_machine(machine_class)) {
             error_report("maru_qt can not work"
                     " without maru machine");
@@ -4938,6 +4952,9 @@ int main(int argc, char **argv, char **envp)
     switch (display_type) {
     case DT_MARU_QT_ONSCREEN:
     case DT_MARU_QT_OFFSCREEN:
+# ifdef CONFIG_OPENGL
+    case DT_MARU_QT_GL:
+# endif
         maru_qt5_display_fini();
         break;
     default: