{"id":1571490,"url":"http://patchwork.ozlabs.org/api/patches/1571490/?format=json","web_url":"http://patchwork.ozlabs.org/project/qemu-devel/patch/20211221065855.142578-17-marcandre.lureau@redhat.com/","project":{"id":14,"url":"http://patchwork.ozlabs.org/api/projects/14/?format=json","name":"QEMU Development","link_name":"qemu-devel","list_id":"qemu-devel.nongnu.org","list_email":"qemu-devel@nongnu.org","web_url":"","scm_url":"","webscm_url":"","list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<20211221065855.142578-17-marcandre.lureau@redhat.com>","list_archive_url":null,"date":"2021-12-21T06:58:35","name":"[PULL,v2,16/36] ui: split the GL context in a different object","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"633554103403ae325c721b8a0c5e9c719db0a115","submitter":{"id":66774,"url":"http://patchwork.ozlabs.org/api/people/66774/?format=json","name":"Marc-André Lureau","email":"marcandre.lureau@redhat.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/qemu-devel/patch/20211221065855.142578-17-marcandre.lureau@redhat.com/mbox/","series":[{"id":277865,"url":"http://patchwork.ozlabs.org/api/series/277865/?format=json","web_url":"http://patchwork.ozlabs.org/project/qemu-devel/list/?series=277865","date":"2021-12-21T06:58:19","name":"[PULL,v2,01/36] ui/vdagent: add CHECK_SPICE_PROTOCOL_VERSION","version":2,"mbox":"http://patchwork.ozlabs.org/series/277865/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/1571490/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/1571490/checks/","tags":{},"related":[],"headers":{"Return-Path":"<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@bilbo.ozlabs.org","Authentication-Results":["bilbo.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=C1fz0ydq;\n\tdkim-atps=neutral","ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=<UNKNOWN>)","relay.mimecast.com;\n auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=marcandre.lureau@redhat.com"],"Received":["from lists.gnu.org (lists.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby bilbo.ozlabs.org (Postfix) with ESMTPS id 4JJ7fZ0kYWz9s3q\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 21 Dec 2021 18:40:36 +1100 (AEDT)","from localhost ([::1]:48134 helo=lists1p.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>)\n\tid 1mzZlA-0004gT-U1\n\tfor incoming@patchwork.ozlabs.org; Tue, 21 Dec 2021 02:40:32 -0500","from eggs.gnu.org ([209.51.188.92]:58658)\n by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <marcandre.lureau@redhat.com>)\n id 1mzZAy-0005uh-0t\n for qemu-devel@nongnu.org; Tue, 21 Dec 2021 02:03:08 -0500","from us-smtp-delivery-124.mimecast.com ([170.10.133.124]:47517)\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <marcandre.lureau@redhat.com>)\n id 1mzZAv-00025l-4H\n for qemu-devel@nongnu.org; Tue, 21 Dec 2021 02:03:07 -0500","from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com\n [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS\n (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id\n us-mta-50-XIHM-629MDCEy-zj2PXnxA-1; Tue, 21 Dec 2021 02:03:01 -0500","from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com\n [10.5.11.11])\n (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n (No client certificate requested)\n by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 0AA31801B31;\n Tue, 21 Dec 2021 07:03:00 +0000 (UTC)","from localhost (unknown [10.39.208.37])\n by smtp.corp.redhat.com (Postfix) with ESMTP id A0A857EA36;\n Tue, 21 Dec 2021 07:02:57 +0000 (UTC)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1640070184;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding:\n in-reply-to:in-reply-to:references:references;\n bh=0XmaWU22xZifElMEq63eAPJ22WB/aAoJVypSzIxJk10=;\n b=C1fz0ydqxoHYodzrDtwZDz+t5hf0f5+kq8L5JEy9DzUZkFJ0xNQNHU1+7c0mXXtk87FDSt\n odnXDFERFRJqeAv0at397a+DTDdaYg2pgCWaIe/exfuRC1TsrjJkNKrXSFDWIvIprNqmPm\n QgUTY4vLWjSPbiWo66q6PJPw3sHYT/w=","X-MC-Unique":"XIHM-629MDCEy-zj2PXnxA-1","From":"marcandre.lureau@redhat.com","To":"qemu-devel@nongnu.org","Subject":"[PULL v2 16/36] ui: split the GL context in a different object","Date":"Tue, 21 Dec 2021 10:58:35 +0400","Message-Id":"<20211221065855.142578-17-marcandre.lureau@redhat.com>","In-Reply-To":"<20211221065855.142578-1-marcandre.lureau@redhat.com>","References":"<20211221065855.142578-1-marcandre.lureau@redhat.com>","MIME-Version":"1.0","X-Scanned-By":"MIMEDefang 2.79 on 10.5.11.11","X-Mimecast-Spam-Score":"0","X-Mimecast-Originator":"redhat.com","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"8bit","Received-SPF":"pass client-ip=170.10.133.124;\n envelope-from=marcandre.lureau@redhat.com;\n helo=us-smtp-delivery-124.mimecast.com","X-Spam_score_int":"-29","X-Spam_score":"-3.0","X-Spam_bar":"---","X-Spam_report":"(-3.0 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.203,\n DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001,\n SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no","X-Spam_action":"no action","X-BeenThere":"qemu-devel@nongnu.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<qemu-devel.nongnu.org>","List-Unsubscribe":"<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>","List-Archive":"<https://lists.nongnu.org/archive/html/qemu-devel>","List-Post":"<mailto:qemu-devel@nongnu.org>","List-Help":"<mailto:qemu-devel-request@nongnu.org?subject=help>","List-Subscribe":"<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>","Cc":"peter.maydell@linaro.org, richard.henderson@linaro.org, =?utf-8?q?Marc-A?=\n\t=?utf-8?q?ndr=C3=A9_Lureau?= <marcandre.lureau@redhat.com>","Errors-To":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org","Sender":"\"Qemu-devel\"\n <qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>"},"content":"From: Marc-André Lureau <marcandre.lureau@redhat.com>\n\nThis will allow to have one GL context but a variable number of\nlisteners.\n\nSigned-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>\nAcked-by: Gerd Hoffmann <kraxel@redhat.com>\n---\n include/ui/console.h       | 34 ++++++++++++++++++++++------------\n include/ui/egl-context.h   |  6 +++---\n include/ui/gtk.h           | 11 ++++++-----\n include/ui/sdl2.h          |  7 ++++---\n include/ui/spice-display.h |  1 +\n ui/console.c               | 26 ++++++++++++++++----------\n ui/egl-context.c           |  6 +++---\n ui/egl-headless.c          | 21 ++++++++++++++-------\n ui/gtk-egl.c               | 10 +++++-----\n ui/gtk-gl-area.c           |  8 ++++----\n ui/gtk.c                   | 24 ++++++++++++++++--------\n ui/sdl2-gl.c               | 10 +++++-----\n ui/sdl2.c                  | 13 +++++++++----\n ui/spice-display.c         | 18 +++++++++++-------\n 14 files changed, 119 insertions(+), 76 deletions(-)","diff":"diff --git a/include/ui/console.h b/include/ui/console.h\nindex 3ff51b492e5b..fe08b4dd040f 100644\n--- a/include/ui/console.h\n+++ b/include/ui/console.h\n@@ -179,6 +179,7 @@ typedef struct QemuDmaBuf {\n } QemuDmaBuf;\n \n typedef struct DisplayState DisplayState;\n+typedef struct DisplayGLCtx DisplayGLCtx;\n \n typedef struct DisplayChangeListenerOps {\n     const char *dpy_name;\n@@ -213,16 +214,6 @@ typedef struct DisplayChangeListenerOps {\n     void (*dpy_cursor_define)(DisplayChangeListener *dcl,\n                               QEMUCursor *cursor);\n \n-    /* required if GL */\n-    QEMUGLContext (*dpy_gl_ctx_create)(DisplayChangeListener *dcl,\n-                                       QEMUGLParams *params);\n-    /* required if GL */\n-    void (*dpy_gl_ctx_destroy)(DisplayChangeListener *dcl,\n-                               QEMUGLContext ctx);\n-    /* required if GL */\n-    int (*dpy_gl_ctx_make_current)(DisplayChangeListener *dcl,\n-                                   QEMUGLContext ctx);\n-\n     /* required if GL */\n     void (*dpy_gl_scanout_disable)(DisplayChangeListener *dcl);\n     /* required if GL */\n@@ -263,6 +254,26 @@ struct DisplayChangeListener {\n     QLIST_ENTRY(DisplayChangeListener) next;\n };\n \n+typedef struct DisplayGLCtxOps {\n+    /*\n+     * We only check if the GLCtx is compatible with a DCL via ops. A natural\n+     * evolution of this would be a callback to check some runtime requirements\n+     * and allow various DCL kinds.\n+     */\n+    const DisplayChangeListenerOps *compatible_dcl;\n+\n+    QEMUGLContext (*dpy_gl_ctx_create)(DisplayGLCtx *dgc,\n+                                       QEMUGLParams *params);\n+    void (*dpy_gl_ctx_destroy)(DisplayGLCtx *dgc,\n+                               QEMUGLContext ctx);\n+    int (*dpy_gl_ctx_make_current)(DisplayGLCtx *dgc,\n+                                   QEMUGLContext ctx);\n+} DisplayGLCtxOps;\n+\n+struct DisplayGLCtx {\n+    const DisplayGLCtxOps *ops;\n+};\n+\n DisplayState *init_displaystate(void);\n DisplaySurface *qemu_create_displaysurface_from(int width, int height,\n                                                 pixman_format_code_t format,\n@@ -409,8 +420,7 @@ void graphic_hw_gl_block(QemuConsole *con, bool block);\n \n void qemu_console_early_init(void);\n \n-void qemu_console_set_display_gl_ctx(QemuConsole *con,\n-                                     DisplayChangeListener *dcl);\n+void qemu_console_set_display_gl_ctx(QemuConsole *con, DisplayGLCtx *ctx);\n \n QemuConsole *qemu_console_lookup_by_index(unsigned int index);\n QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head);\ndiff --git a/include/ui/egl-context.h b/include/ui/egl-context.h\nindex 9374fe41e32b..c2761d747a4e 100644\n--- a/include/ui/egl-context.h\n+++ b/include/ui/egl-context.h\n@@ -4,10 +4,10 @@\n #include \"ui/console.h\"\n #include \"ui/egl-helpers.h\"\n \n-QEMUGLContext qemu_egl_create_context(DisplayChangeListener *dcl,\n+QEMUGLContext qemu_egl_create_context(DisplayGLCtx *dgc,\n                                       QEMUGLParams *params);\n-void qemu_egl_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx);\n-int qemu_egl_make_context_current(DisplayChangeListener *dcl,\n+void qemu_egl_destroy_context(DisplayGLCtx *dgc, QEMUGLContext ctx);\n+int qemu_egl_make_context_current(DisplayGLCtx *dgc,\n                                   QEMUGLContext ctx);\n \n #endif /* EGL_CONTEXT_H */\ndiff --git a/include/ui/gtk.h b/include/ui/gtk.h\nindex 7d22affd381a..101b147d1b98 100644\n--- a/include/ui/gtk.h\n+++ b/include/ui/gtk.h\n@@ -35,6 +35,7 @@ typedef struct GtkDisplayState GtkDisplayState;\n \n typedef struct VirtualGfxConsole {\n     GtkWidget *drawing_area;\n+    DisplayGLCtx dgc;\n     DisplayChangeListener dcl;\n     QKbdState *kbd;\n     DisplaySurface *ds;\n@@ -165,7 +166,7 @@ void gd_egl_update(DisplayChangeListener *dcl,\n void gd_egl_refresh(DisplayChangeListener *dcl);\n void gd_egl_switch(DisplayChangeListener *dcl,\n                    DisplaySurface *surface);\n-QEMUGLContext gd_egl_create_context(DisplayChangeListener *dcl,\n+QEMUGLContext gd_egl_create_context(DisplayGLCtx *dgc,\n                                     QEMUGLParams *params);\n void gd_egl_scanout_disable(DisplayChangeListener *dcl);\n void gd_egl_scanout_texture(DisplayChangeListener *dcl,\n@@ -187,7 +188,7 @@ void gd_egl_flush(DisplayChangeListener *dcl,\n void gd_egl_scanout_flush(DisplayChangeListener *dcl,\n                           uint32_t x, uint32_t y, uint32_t w, uint32_t h);\n void gtk_egl_init(DisplayGLMode mode);\n-int gd_egl_make_current(DisplayChangeListener *dcl,\n+int gd_egl_make_current(DisplayGLCtx *dgc,\n                         QEMUGLContext ctx);\n \n /* ui/gtk-gl-area.c */\n@@ -198,9 +199,9 @@ void gd_gl_area_update(DisplayChangeListener *dcl,\n void gd_gl_area_refresh(DisplayChangeListener *dcl);\n void gd_gl_area_switch(DisplayChangeListener *dcl,\n                        DisplaySurface *surface);\n-QEMUGLContext gd_gl_area_create_context(DisplayChangeListener *dcl,\n+QEMUGLContext gd_gl_area_create_context(DisplayGLCtx *dgc,\n                                         QEMUGLParams *params);\n-void gd_gl_area_destroy_context(DisplayChangeListener *dcl,\n+void gd_gl_area_destroy_context(DisplayGLCtx *dgc,\n                                 QEMUGLContext ctx);\n void gd_gl_area_scanout_dmabuf(DisplayChangeListener *dcl,\n                                QemuDmaBuf *dmabuf);\n@@ -215,7 +216,7 @@ void gd_gl_area_scanout_disable(DisplayChangeListener *dcl);\n void gd_gl_area_scanout_flush(DisplayChangeListener *dcl,\n                               uint32_t x, uint32_t y, uint32_t w, uint32_t h);\n void gtk_gl_area_init(void);\n-int gd_gl_area_make_current(DisplayChangeListener *dcl,\n+int gd_gl_area_make_current(DisplayGLCtx *dgc,\n                             QEMUGLContext ctx);\n \n /* gtk-clipboard.c */\ndiff --git a/include/ui/sdl2.h b/include/ui/sdl2.h\nindex f85c117a78f2..71bcf7ebdaee 100644\n--- a/include/ui/sdl2.h\n+++ b/include/ui/sdl2.h\n@@ -16,6 +16,7 @@\n #endif\n \n struct sdl2_console {\n+    DisplayGLCtx dgc;\n     DisplayChangeListener dcl;\n     DisplaySurface *surface;\n     DisplayOptions *opts;\n@@ -65,10 +66,10 @@ void sdl2_gl_switch(DisplayChangeListener *dcl,\n void sdl2_gl_refresh(DisplayChangeListener *dcl);\n void sdl2_gl_redraw(struct sdl2_console *scon);\n \n-QEMUGLContext sdl2_gl_create_context(DisplayChangeListener *dcl,\n+QEMUGLContext sdl2_gl_create_context(DisplayGLCtx *dgc,\n                                      QEMUGLParams *params);\n-void sdl2_gl_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx);\n-int sdl2_gl_make_context_current(DisplayChangeListener *dcl,\n+void sdl2_gl_destroy_context(DisplayGLCtx *dgc, QEMUGLContext ctx);\n+int sdl2_gl_make_context_current(DisplayGLCtx *dgc,\n                                  QEMUGLContext ctx);\n \n void sdl2_gl_scanout_disable(DisplayChangeListener *dcl);\ndiff --git a/include/ui/spice-display.h b/include/ui/spice-display.h\nindex ed298d58f06c..a2fbf62c528e 100644\n--- a/include/ui/spice-display.h\n+++ b/include/ui/spice-display.h\n@@ -86,6 +86,7 @@ typedef struct SimpleSpiceCursor SimpleSpiceCursor;\n \n struct SimpleSpiceDisplay {\n     DisplaySurface *ds;\n+    DisplayGLCtx dgc;\n     DisplayChangeListener dcl;\n     void *buf;\n     int bufsize;\ndiff --git a/ui/console.c b/ui/console.c\nindex 13c0d001c096..78583df92035 100644\n--- a/ui/console.c\n+++ b/ui/console.c\n@@ -78,7 +78,7 @@ struct QemuConsole {\n     DisplayState *ds;\n     DisplaySurface *surface;\n     int dcls;\n-    DisplayChangeListener *gl;\n+    DisplayGLCtx *gl;\n     int gl_block;\n     QEMUTimer *gl_unblock_timer;\n     int window_id;\n@@ -1458,17 +1458,24 @@ static bool dpy_compatible_with(QemuConsole *con,\n     return true;\n }\n \n-void qemu_console_set_display_gl_ctx(QemuConsole *con,\n-                                     DisplayChangeListener *dcl)\n+void qemu_console_set_display_gl_ctx(QemuConsole *con, DisplayGLCtx *gl)\n {\n     /* display has opengl support */\n-    assert(dcl->con);\n-    if (dcl->con->gl) {\n-        fprintf(stderr, \"can't register two opengl displays (%s, %s)\\n\",\n-                dcl->ops->dpy_name, dcl->con->gl->ops->dpy_name);\n+    assert(con);\n+    if (con->gl) {\n+        error_report(\"The console already has an OpenGL context.\");\n         exit(1);\n     }\n-    dcl->con->gl = dcl;\n+    con->gl = gl;\n+}\n+\n+static bool dpy_gl_compatible_with(QemuConsole *con, DisplayChangeListener *dcl)\n+{\n+    if (!con->gl) {\n+        return true;\n+    }\n+\n+    return con->gl->ops->compatible_dcl == dcl->ops;\n }\n \n void register_displaychangelistener(DisplayChangeListener *dcl)\n@@ -1480,8 +1487,7 @@ void register_displaychangelistener(DisplayChangeListener *dcl)\n \n     assert(!dcl->ds);\n \n-    if (dcl->con && dcl->con->gl &&\n-        dcl->con->gl != dcl) {\n+    if (dcl->con && !dpy_gl_compatible_with(dcl->con, dcl)) {\n         error_report(\"Display %s is incompatible with the GL context\",\n                      dcl->ops->dpy_name);\n         exit(1);\ndiff --git a/ui/egl-context.c b/ui/egl-context.c\nindex 368ffa49d82f..eb5f520fc4da 100644\n--- a/ui/egl-context.c\n+++ b/ui/egl-context.c\n@@ -1,7 +1,7 @@\n #include \"qemu/osdep.h\"\n #include \"ui/egl-context.h\"\n \n-QEMUGLContext qemu_egl_create_context(DisplayChangeListener *dcl,\n+QEMUGLContext qemu_egl_create_context(DisplayGLCtx *dgc,\n                                       QEMUGLParams *params)\n {\n    EGLContext ctx;\n@@ -24,12 +24,12 @@ QEMUGLContext qemu_egl_create_context(DisplayChangeListener *dcl,\n    return ctx;\n }\n \n-void qemu_egl_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx)\n+void qemu_egl_destroy_context(DisplayGLCtx *dgc, QEMUGLContext ctx)\n {\n     eglDestroyContext(qemu_egl_display, ctx);\n }\n \n-int qemu_egl_make_context_current(DisplayChangeListener *dcl,\n+int qemu_egl_make_context_current(DisplayGLCtx *dgc,\n                                   QEMUGLContext ctx)\n {\n    return eglMakeCurrent(qemu_egl_display,\ndiff --git a/ui/egl-headless.c b/ui/egl-headless.c\nindex 08327c40c6ee..94082a9da951 100644\n--- a/ui/egl-headless.c\n+++ b/ui/egl-headless.c\n@@ -38,12 +38,12 @@ static void egl_gfx_switch(DisplayChangeListener *dcl,\n     edpy->ds = new_surface;\n }\n \n-static QEMUGLContext egl_create_context(DisplayChangeListener *dcl,\n+static QEMUGLContext egl_create_context(DisplayGLCtx *dgc,\n                                         QEMUGLParams *params)\n {\n     eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,\n                    qemu_egl_rn_ctx);\n-    return qemu_egl_create_context(dcl, params);\n+    return qemu_egl_create_context(dgc, params);\n }\n \n static void egl_scanout_disable(DisplayChangeListener *dcl)\n@@ -157,10 +157,6 @@ static const DisplayChangeListenerOps egl_ops = {\n     .dpy_gfx_update          = egl_gfx_update,\n     .dpy_gfx_switch          = egl_gfx_switch,\n \n-    .dpy_gl_ctx_create       = egl_create_context,\n-    .dpy_gl_ctx_destroy      = qemu_egl_destroy_context,\n-    .dpy_gl_ctx_make_current = qemu_egl_make_context_current,\n-\n     .dpy_gl_scanout_disable  = egl_scanout_disable,\n     .dpy_gl_scanout_texture  = egl_scanout_texture,\n     .dpy_gl_scanout_dmabuf   = egl_scanout_dmabuf,\n@@ -170,6 +166,13 @@ static const DisplayChangeListenerOps egl_ops = {\n     .dpy_gl_update           = egl_scanout_flush,\n };\n \n+static const DisplayGLCtxOps eglctx_ops = {\n+    .compatible_dcl          = &egl_ops,\n+    .dpy_gl_ctx_create       = egl_create_context,\n+    .dpy_gl_ctx_destroy      = qemu_egl_destroy_context,\n+    .dpy_gl_ctx_make_current = qemu_egl_make_context_current,\n+};\n+\n static void early_egl_headless_init(DisplayOptions *opts)\n {\n     display_opengl = 1;\n@@ -188,6 +191,8 @@ static void egl_headless_init(DisplayState *ds, DisplayOptions *opts)\n     }\n \n     for (idx = 0;; idx++) {\n+        DisplayGLCtx *ctx;\n+\n         con = qemu_console_lookup_by_index(idx);\n         if (!con || !qemu_console_is_graphic(con)) {\n             break;\n@@ -197,7 +202,9 @@ static void egl_headless_init(DisplayState *ds, DisplayOptions *opts)\n         edpy->dcl.con = con;\n         edpy->dcl.ops = &egl_ops;\n         edpy->gls = qemu_gl_init_shader();\n-        qemu_console_set_display_gl_ctx(con, &edpy->dcl);\n+        ctx = g_new0(DisplayGLCtx, 1);\n+        ctx->ops = &eglctx_ops;\n+        qemu_console_set_display_gl_ctx(con, ctx);\n         register_displaychangelistener(&edpy->dcl);\n     }\n }\ndiff --git a/ui/gtk-egl.c b/ui/gtk-egl.c\nindex e891b61048a8..e3bd4bc27431 100644\n--- a/ui/gtk-egl.c\n+++ b/ui/gtk-egl.c\n@@ -197,14 +197,14 @@ void gd_egl_switch(DisplayChangeListener *dcl,\n     }\n }\n \n-QEMUGLContext gd_egl_create_context(DisplayChangeListener *dcl,\n+QEMUGLContext gd_egl_create_context(DisplayGLCtx *dgc,\n                                     QEMUGLParams *params)\n {\n-    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);\n+    VirtualConsole *vc = container_of(dgc, VirtualConsole, gfx.dgc);\n \n     eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,\n                    vc->gfx.esurface, vc->gfx.ectx);\n-    return qemu_egl_create_context(dcl, params);\n+    return qemu_egl_create_context(dgc, params);\n }\n \n void gd_egl_scanout_disable(DisplayChangeListener *dcl)\n@@ -360,10 +360,10 @@ void gtk_egl_init(DisplayGLMode mode)\n     display_opengl = 1;\n }\n \n-int gd_egl_make_current(DisplayChangeListener *dcl,\n+int gd_egl_make_current(DisplayGLCtx *dgc,\n                         QEMUGLContext ctx)\n {\n-    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);\n+    VirtualConsole *vc = container_of(dgc, VirtualConsole, gfx.dgc);\n \n     return eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,\n                           vc->gfx.esurface, ctx);\ndiff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c\nindex f1c7636cba98..fc5a082eb846 100644\n--- a/ui/gtk-gl-area.c\n+++ b/ui/gtk-gl-area.c\n@@ -170,10 +170,10 @@ void gd_gl_area_switch(DisplayChangeListener *dcl,\n     }\n }\n \n-QEMUGLContext gd_gl_area_create_context(DisplayChangeListener *dcl,\n+QEMUGLContext gd_gl_area_create_context(DisplayGLCtx *dgc,\n                                         QEMUGLParams *params)\n {\n-    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);\n+    VirtualConsole *vc = container_of(dgc, VirtualConsole, gfx.dgc);\n     GdkWindow *window;\n     GdkGLContext *ctx;\n     GError *err = NULL;\n@@ -199,7 +199,7 @@ QEMUGLContext gd_gl_area_create_context(DisplayChangeListener *dcl,\n     return ctx;\n }\n \n-void gd_gl_area_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx)\n+void gd_gl_area_destroy_context(DisplayGLCtx *dgc, QEMUGLContext ctx)\n {\n     /* FIXME */\n }\n@@ -278,7 +278,7 @@ void gtk_gl_area_init(void)\n     display_opengl = 1;\n }\n \n-int gd_gl_area_make_current(DisplayChangeListener *dcl,\n+int gd_gl_area_make_current(DisplayGLCtx *dgc,\n                             QEMUGLContext ctx)\n {\n     gdk_gl_context_make_current(ctx);\ndiff --git a/ui/gtk.c b/ui/gtk.c\nindex 077d38145de8..6a1f65d51894 100644\n--- a/ui/gtk.c\n+++ b/ui/gtk.c\n@@ -606,9 +606,6 @@ static const DisplayChangeListenerOps dcl_gl_area_ops = {\n     .dpy_mouse_set        = gd_mouse_set,\n     .dpy_cursor_define    = gd_cursor_define,\n \n-    .dpy_gl_ctx_create       = gd_gl_area_create_context,\n-    .dpy_gl_ctx_destroy      = gd_gl_area_destroy_context,\n-    .dpy_gl_ctx_make_current = gd_gl_area_make_current,\n     .dpy_gl_scanout_texture  = gd_gl_area_scanout_texture,\n     .dpy_gl_scanout_disable  = gd_gl_area_scanout_disable,\n     .dpy_gl_update           = gd_gl_area_scanout_flush,\n@@ -617,8 +614,14 @@ static const DisplayChangeListenerOps dcl_gl_area_ops = {\n     .dpy_has_dmabuf          = gd_has_dmabuf,\n };\n \n-#ifdef CONFIG_X11\n+static const DisplayGLCtxOps gl_area_ctx_ops = {\n+    .compatible_dcl          = &dcl_gl_area_ops,\n+    .dpy_gl_ctx_create       = gd_gl_area_create_context,\n+    .dpy_gl_ctx_destroy      = gd_gl_area_destroy_context,\n+    .dpy_gl_ctx_make_current = gd_gl_area_make_current,\n+};\n \n+#ifdef CONFIG_X11\n static const DisplayChangeListenerOps dcl_egl_ops = {\n     .dpy_name             = \"gtk-egl\",\n     .dpy_gfx_update       = gd_egl_update,\n@@ -628,9 +631,6 @@ static const DisplayChangeListenerOps dcl_egl_ops = {\n     .dpy_mouse_set        = gd_mouse_set,\n     .dpy_cursor_define    = gd_cursor_define,\n \n-    .dpy_gl_ctx_create       = gd_egl_create_context,\n-    .dpy_gl_ctx_destroy      = qemu_egl_destroy_context,\n-    .dpy_gl_ctx_make_current = gd_egl_make_current,\n     .dpy_gl_scanout_disable  = gd_egl_scanout_disable,\n     .dpy_gl_scanout_texture  = gd_egl_scanout_texture,\n     .dpy_gl_scanout_dmabuf   = gd_egl_scanout_dmabuf,\n@@ -641,6 +641,12 @@ static const DisplayChangeListenerOps dcl_egl_ops = {\n     .dpy_has_dmabuf          = gd_has_dmabuf,\n };\n \n+static const DisplayGLCtxOps egl_ctx_ops = {\n+    .compatible_dcl          = &dcl_egl_ops,\n+    .dpy_gl_ctx_create       = gd_egl_create_context,\n+    .dpy_gl_ctx_destroy      = qemu_egl_destroy_context,\n+    .dpy_gl_ctx_make_current = gd_egl_make_current,\n+};\n #endif\n \n #endif /* CONFIG_OPENGL */\n@@ -2034,6 +2040,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,\n             g_signal_connect(vc->gfx.drawing_area, \"realize\",\n                              G_CALLBACK(gl_area_realize), vc);\n             vc->gfx.dcl.ops = &dcl_gl_area_ops;\n+            vc->gfx.dgc.ops = &gl_area_ctx_ops;\n         } else {\n #ifdef CONFIG_X11\n             vc->gfx.drawing_area = gtk_drawing_area_new();\n@@ -2048,6 +2055,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,\n             gtk_widget_set_double_buffered(vc->gfx.drawing_area, FALSE);\n #pragma GCC diagnostic pop\n             vc->gfx.dcl.ops = &dcl_egl_ops;\n+            vc->gfx.dgc.ops = &egl_ctx_ops;\n             vc->gfx.has_dmabuf = qemu_egl_has_dmabuf();\n #else\n             abort();\n@@ -2083,7 +2091,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,\n     vc->gfx.dcl.con = con;\n \n     if (display_opengl) {\n-        qemu_console_set_display_gl_ctx(con, &vc->gfx.dcl);\n+        qemu_console_set_display_gl_ctx(con, &vc->gfx.dgc);\n     }\n     register_displaychangelistener(&vc->gfx.dcl);\n \ndiff --git a/ui/sdl2-gl.c b/ui/sdl2-gl.c\nindex 5b950fbbea2f..39cab8cde737 100644\n--- a/ui/sdl2-gl.c\n+++ b/ui/sdl2-gl.c\n@@ -132,10 +132,10 @@ void sdl2_gl_redraw(struct sdl2_console *scon)\n     }\n }\n \n-QEMUGLContext sdl2_gl_create_context(DisplayChangeListener *dcl,\n+QEMUGLContext sdl2_gl_create_context(DisplayGLCtx *dgc,\n                                      QEMUGLParams *params)\n {\n-    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);\n+    struct sdl2_console *scon = container_of(dgc, struct sdl2_console, dgc);\n     SDL_GLContext ctx;\n \n     assert(scon->opengl);\n@@ -167,17 +167,17 @@ QEMUGLContext sdl2_gl_create_context(DisplayChangeListener *dcl,\n     return (QEMUGLContext)ctx;\n }\n \n-void sdl2_gl_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx)\n+void sdl2_gl_destroy_context(DisplayGLCtx *dgc, QEMUGLContext ctx)\n {\n     SDL_GLContext sdlctx = (SDL_GLContext)ctx;\n \n     SDL_GL_DeleteContext(sdlctx);\n }\n \n-int sdl2_gl_make_context_current(DisplayChangeListener *dcl,\n+int sdl2_gl_make_context_current(DisplayGLCtx *dgc,\n                                  QEMUGLContext ctx)\n {\n-    struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);\n+    struct sdl2_console *scon = container_of(dgc, struct sdl2_console, dgc);\n     SDL_GLContext sdlctx = (SDL_GLContext)ctx;\n \n     assert(scon->opengl);\ndiff --git a/ui/sdl2.c b/ui/sdl2.c\nindex bb186a381acd..0bd30504cfcc 100644\n--- a/ui/sdl2.c\n+++ b/ui/sdl2.c\n@@ -778,13 +778,17 @@ static const DisplayChangeListenerOps dcl_gl_ops = {\n     .dpy_mouse_set           = sdl_mouse_warp,\n     .dpy_cursor_define       = sdl_mouse_define,\n \n-    .dpy_gl_ctx_create       = sdl2_gl_create_context,\n-    .dpy_gl_ctx_destroy      = sdl2_gl_destroy_context,\n-    .dpy_gl_ctx_make_current = sdl2_gl_make_context_current,\n     .dpy_gl_scanout_disable  = sdl2_gl_scanout_disable,\n     .dpy_gl_scanout_texture  = sdl2_gl_scanout_texture,\n     .dpy_gl_update           = sdl2_gl_scanout_flush,\n };\n+\n+static const DisplayGLCtxOps gl_ctx_ops = {\n+    .compatible_dcl          = &dcl_gl_ops,\n+    .dpy_gl_ctx_create       = sdl2_gl_create_context,\n+    .dpy_gl_ctx_destroy      = sdl2_gl_destroy_context,\n+    .dpy_gl_ctx_make_current = sdl2_gl_make_context_current,\n+};\n #endif\n \n static void sdl2_display_early_init(DisplayOptions *o)\n@@ -860,6 +864,7 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o)\n #ifdef CONFIG_OPENGL\n         sdl2_console[i].opengl = display_opengl;\n         sdl2_console[i].dcl.ops = display_opengl ? &dcl_gl_ops : &dcl_2d_ops;\n+        sdl2_console[i].dgc.ops = display_opengl ? &gl_ctx_ops : NULL;\n #else\n         sdl2_console[i].opengl = 0;\n         sdl2_console[i].dcl.ops = &dcl_2d_ops;\n@@ -867,7 +872,7 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o)\n         sdl2_console[i].dcl.con = con;\n         sdl2_console[i].kbd = qkbd_state_init(con);\n         if (display_opengl) {\n-            qemu_console_set_display_gl_ctx(con, &sdl2_console[i].dcl);\n+            qemu_console_set_display_gl_ctx(con, &sdl2_console[i].dgc);\n         }\n         register_displaychangelistener(&sdl2_console[i].dcl);\n \ndiff --git a/ui/spice-display.c b/ui/spice-display.c\nindex ec501f129f07..798e0f6167e7 100644\n--- a/ui/spice-display.c\n+++ b/ui/spice-display.c\n@@ -908,12 +908,12 @@ static void spice_gl_switch(DisplayChangeListener *dcl,\n     }\n }\n \n-static QEMUGLContext qemu_spice_gl_create_context(DisplayChangeListener *dcl,\n+static QEMUGLContext qemu_spice_gl_create_context(DisplayGLCtx *dgc,\n                                                   QEMUGLParams *params)\n {\n     eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,\n                    qemu_egl_rn_ctx);\n-    return qemu_egl_create_context(dcl, params);\n+    return qemu_egl_create_context(dgc, params);\n }\n \n static void qemu_spice_gl_scanout_disable(DisplayChangeListener *dcl)\n@@ -1105,10 +1105,6 @@ static const DisplayChangeListenerOps display_listener_gl_ops = {\n     .dpy_mouse_set           = display_mouse_set,\n     .dpy_cursor_define       = display_mouse_define,\n \n-    .dpy_gl_ctx_create       = qemu_spice_gl_create_context,\n-    .dpy_gl_ctx_destroy      = qemu_egl_destroy_context,\n-    .dpy_gl_ctx_make_current = qemu_egl_make_context_current,\n-\n     .dpy_gl_scanout_disable  = qemu_spice_gl_scanout_disable,\n     .dpy_gl_scanout_texture  = qemu_spice_gl_scanout_texture,\n     .dpy_gl_scanout_dmabuf   = qemu_spice_gl_scanout_dmabuf,\n@@ -1118,6 +1114,13 @@ static const DisplayChangeListenerOps display_listener_gl_ops = {\n     .dpy_gl_update           = qemu_spice_gl_update,\n };\n \n+static const DisplayGLCtxOps gl_ctx_ops = {\n+    .compatible_dcl          = &display_listener_gl_ops,\n+    .dpy_gl_ctx_create       = qemu_spice_gl_create_context,\n+    .dpy_gl_ctx_destroy      = qemu_egl_destroy_context,\n+    .dpy_gl_ctx_make_current = qemu_egl_make_context_current,\n+};\n+\n #endif /* HAVE_SPICE_GL */\n \n static void qemu_spice_display_init_one(QemuConsole *con)\n@@ -1130,6 +1133,7 @@ static void qemu_spice_display_init_one(QemuConsole *con)\n #ifdef HAVE_SPICE_GL\n     if (spice_opengl) {\n         ssd->dcl.ops = &display_listener_gl_ops;\n+        ssd->dgc.ops = &gl_ctx_ops;\n         ssd->gl_unblock_bh = qemu_bh_new(qemu_spice_gl_unblock_bh, ssd);\n         ssd->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME,\n                                              qemu_spice_gl_block_timer, ssd);\n@@ -1156,7 +1160,7 @@ static void qemu_spice_display_init_one(QemuConsole *con)\n     qemu_spice_create_host_memslot(ssd);\n \n     if (spice_opengl) {\n-        qemu_console_set_display_gl_ctx(con, &ssd->dcl);\n+        qemu_console_set_display_gl_ctx(con, &ssd->dgc);\n     }\n     register_displaychangelistener(&ssd->dcl);\n }\n","prefixes":["PULL","v2","16/36"]}