From: Mateusz Majewski Date: Tue, 25 Mar 2025 13:39:30 +0000 (+0100) Subject: *rest of the owl* X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=15a7d4a19db8a14fce0e1fc1b9bc089d783dccc8;p=sdk%2Femulator%2Fqemu.git *rest of the owl* Change-Id: I825083e7e8a83b35877894a1809bccc0bcc09f8f --- diff --git a/package/build.linux b/package/build.linux index 095c992ab5..2f9303c4a2 100755 --- a/package/build.linux +++ b/package/build.linux @@ -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} diff --git a/tizen/emulator_configure.sh b/tizen/emulator_configure.sh index aebfa08844..89dbfb5842 100755 --- a/tizen/emulator_configure.sh +++ b/tizen/emulator_configure.sh @@ -148,6 +148,8 @@ CONFIGURE_APPEND=" --disable-spice --disable-curses --disable-xen + --enable-virglrenderer + --enable-opengl $CONFIGURE_APPEND" CONFIGURE_APPEND_WIN=" diff --git a/tizen/src/hw/pci/maru_brightness.c b/tizen/src/hw/pci/maru_brightness.c index 225fa77d89..9e4c7b6d13 100644 --- a/tizen/src/hw/pci/maru_brightness.c +++ b/tizen/src/hw/pci/maru_brightness.c @@ -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, diff --git a/tizen/src/ui/displayglwidget.cpp b/tizen/src/ui/displayglwidget.cpp index 9f9dc89067..4b55d25745 100644 --- a/tizen/src/ui/displayglwidget.cpp +++ b/tizen/src/ui/displayglwidget.cpp @@ -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(); diff --git a/tizen/src/ui/displayglwidget.h b/tizen/src/ui/displayglwidget.h index 26cf7cf96a..6042b88ee2 100644 --- a/tizen/src/ui/displayglwidget.h +++ b/tizen/src/ui/displayglwidget.h @@ -35,6 +35,7 @@ #include "displaybase.h" #include +#include #include #include @@ -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 diff --git a/tizen/src/ui/mainwindow.cpp b/tizen/src/ui/mainwindow.cpp index ce3e35b365..cafadff8e5 100644 --- a/tizen/src/ui/mainwindow.cpp +++ b/tizen/src/ui/mainwindow.cpp @@ -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; diff --git a/tizen/src/ui/qt5.c b/tizen/src/ui/qt5.c index 6007112785..e7e5d4f24f 100644 --- a/tizen/src/ui/qt5.c +++ b/tizen/src/ui/qt5.c @@ -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; diff --git a/tizen/src/ui/qt5_supplement.cpp b/tizen/src/ui/qt5_supplement.cpp index 113ac3dd07..571457efac 100644 --- a/tizen/src/ui/qt5_supplement.cpp +++ b/tizen/src/ui/qt5_supplement.cpp @@ -28,10 +28,13 @@ * */ +#include + #include #include #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 diff --git a/tizen/src/ui/qt5_supplement.h b/tizen/src/ui/qt5_supplement.h index 73b82e0360..80a66f5740 100644 --- a/tizen/src/ui/qt5_supplement.h +++ b/tizen/src/ui/qt5_supplement.h @@ -31,6 +31,11 @@ #ifndef __QT5_INTERNAL_H__ #define __QT5_INTERNAL_H__ +#include + +// 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 3317a1424b..04eaea037d 100644 --- 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: