22 changes: 16 additions & 6 deletions ui/dbus-listener.c
Expand Up @@ -27,9 +27,11 @@
#include "dbus.h"
#include <gio/gunixfdlist.h>

#ifdef CONFIG_OPENGL
#include "ui/shader.h"
#include "ui/egl-helpers.h"
#include "ui/egl-context.h"
#endif
#include "trace.h"

struct _DBusDisplayListener {
Expand All @@ -48,6 +50,7 @@ struct _DBusDisplayListener {

G_DEFINE_TYPE(DBusDisplayListener, dbus_display_listener, G_TYPE_OBJECT)

#ifdef CONFIG_GBM
static void dbus_update_gl_cb(GObject *source_object,
GAsyncResult *res,
gpointer user_data)
Expand Down Expand Up @@ -149,7 +152,7 @@ static void dbus_cursor_dmabuf(DisplayChangeListener *dcl,
DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
DisplaySurface *ds;
GVariant *v_data = NULL;
egl_fb cursor_fb;
egl_fb cursor_fb = EGL_FB_INIT;

if (!dmabuf) {
qemu_dbus_display1_listener_call_mouse_set(
Expand Down Expand Up @@ -229,19 +232,22 @@ static void dbus_gl_refresh(DisplayChangeListener *dcl)
ddl->gl_updates = 0;
}
}
#endif

static void dbus_refresh(DisplayChangeListener *dcl)
{
graphic_hw_update(dcl->con);
}

#ifdef CONFIG_GBM
static void dbus_gl_gfx_update(DisplayChangeListener *dcl,
int x, int y, int w, int h)
{
DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);

ddl->gl_updates++;
}
#endif

static void dbus_gfx_update(DisplayChangeListener *dcl,
int x, int y, int w, int h)
Expand Down Expand Up @@ -296,6 +302,7 @@ static void dbus_gfx_update(DisplayChangeListener *dcl,
DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
}

#ifdef CONFIG_GBM
static void dbus_gl_gfx_switch(DisplayChangeListener *dcl,
struct DisplaySurface *new_surface)
{
Expand All @@ -311,6 +318,7 @@ static void dbus_gl_gfx_switch(DisplayChangeListener *dcl,
width, height, 0, 0, width, height);
}
}
#endif

static void dbus_gfx_switch(DisplayChangeListener *dcl,
struct DisplaySurface *new_surface)
Expand Down Expand Up @@ -339,14 +347,13 @@ static void dbus_cursor_define(DisplayChangeListener *dcl,
DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
GVariant *v_data = NULL;

cursor_get(c);
v_data = g_variant_new_from_data(
G_VARIANT_TYPE("ay"),
c->data,
c->width * c->height * 4,
TRUE,
(GDestroyNotify)cursor_put,
c);
(GDestroyNotify)cursor_unref,
cursor_ref(c));

qemu_dbus_display1_listener_call_cursor_define(
ddl->proxy,
Expand All @@ -362,6 +369,7 @@ static void dbus_cursor_define(DisplayChangeListener *dcl,
NULL);
}

#ifdef CONFIG_GBM
const DisplayChangeListenerOps dbus_gl_dcl_ops = {
.dpy_name = "dbus-gl",
.dpy_gfx_update = dbus_gl_gfx_update,
Expand All @@ -379,6 +387,7 @@ const DisplayChangeListenerOps dbus_gl_dcl_ops = {
.dpy_gl_release_dmabuf = dbus_release_dmabuf,
.dpy_gl_update = dbus_scanout_update,
};
#endif

const DisplayChangeListenerOps dbus_dcl_ops = {
.dpy_name = "dbus",
Expand Down Expand Up @@ -407,11 +416,12 @@ dbus_display_listener_constructed(GObject *object)
{
DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(object);

ddl->dcl.ops = &dbus_dcl_ops;
#ifdef CONFIG_GBM
if (display_opengl) {
ddl->dcl.ops = &dbus_gl_dcl_ops;
} else {
ddl->dcl.ops = &dbus_dcl_ops;
}
#endif

G_OBJECT_CLASS(dbus_display_listener_parent_class)->constructed(object);
}
Expand Down
29 changes: 21 additions & 8 deletions ui/dbus.c
Expand Up @@ -30,8 +30,10 @@
#include "qom/object_interfaces.h"
#include "sysemu/sysemu.h"
#include "ui/dbus-module.h"
#ifdef CONFIG_OPENGL
#include "ui/egl-helpers.h"
#include "ui/egl-context.h"
#endif
#include "audio/audio.h"
#include "audio/audio_int.h"
#include "qapi/error.h"
Expand All @@ -41,19 +43,26 @@

static DBusDisplay *dbus_display;

#ifdef CONFIG_OPENGL
static QEMUGLContext dbus_create_context(DisplayGLCtx *dgc,
QEMUGLParams *params)
{
#ifdef CONFIG_GBM
eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
qemu_egl_rn_ctx);
#endif
return qemu_egl_create_context(dgc, params);
}

static bool
dbus_is_compatible_dcl(DisplayGLCtx *dgc,
DisplayChangeListener *dcl)
{
return dcl->ops == &dbus_gl_dcl_ops || dcl->ops == &dbus_console_dcl_ops;
return
#ifdef CONFIG_GBM
dcl->ops == &dbus_gl_dcl_ops ||
#endif
dcl->ops == &dbus_console_dcl_ops;
}

static void
Expand Down Expand Up @@ -84,6 +93,7 @@ static const DisplayGLCtxOps dbus_gl_ops = {
.dpy_gl_ctx_destroy_texture = dbus_destroy_texture,
.dpy_gl_ctx_update_texture = dbus_update_texture,
};
#endif

static NotifierList dbus_display_notifiers =
NOTIFIER_LIST_INITIALIZER(dbus_display_notifiers);
Expand Down Expand Up @@ -112,10 +122,12 @@ dbus_display_init(Object *o)
DBusDisplay *dd = DBUS_DISPLAY(o);
g_autoptr(GDBusObjectSkeleton) vm = NULL;

#ifdef CONFIG_OPENGL
dd->glctx.ops = &dbus_gl_ops;
if (display_opengl) {
dd->glctx.gls = qemu_gl_init_shader();
}
#endif
dd->iface = qemu_dbus_display1_vm_skeleton_new();
dd->consoles = g_ptr_array_new_with_free_func(g_object_unref);

Expand Down Expand Up @@ -152,7 +164,9 @@ dbus_display_finalize(Object *o)
g_clear_object(&dd->iface);
g_free(dd->dbus_addr);
g_free(dd->audiodev);
#ifdef CONFIG_OPENGL
g_clear_pointer(&dd->glctx.gls, qemu_gl_fini_shader);
#endif
dbus_display = NULL;
}

Expand Down Expand Up @@ -220,7 +234,7 @@ dbus_display_complete(UserCreatable *uc, Error **errp)
dd->audiodev);
return;
}
audio_state->drv->set_dbus_server(audio_state, dd->server);
audio_state->drv->set_dbus_server(audio_state, dd->server, dd->p2p);
}

consoles = g_array_new(FALSE, FALSE, sizeof(guint32));
Expand Down Expand Up @@ -451,12 +465,11 @@ early_dbus_init(DisplayOptions *opts)
DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAYGL_MODE_OFF;

if (mode != DISPLAYGL_MODE_OFF) {
if (egl_rendernode_init(opts->u.dbus.rendernode, mode) < 0) {
error_report("dbus: render node init failed");
exit(1);
}

display_opengl = 1;
#ifdef CONFIG_OPENGL
egl_init(opts->u.dbus.rendernode, mode, &error_fatal);
#else
error_report("dbus: GL rendering is not supported");
#endif
}

type_register(&dbus_vc_type_info);
Expand Down
16 changes: 8 additions & 8 deletions ui/egl-headless.c
@@ -1,7 +1,7 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "sysemu/sysemu.h"
#include "qapi/error.h"
#include "ui/console.h"
#include "ui/egl-helpers.h"
#include "ui/egl-context.h"
Expand Down Expand Up @@ -191,21 +191,21 @@ static const DisplayGLCtxOps eglctx_ops = {

static void early_egl_headless_init(DisplayOptions *opts)
{
display_opengl = 1;
DisplayGLMode mode = DISPLAYGL_MODE_ON;

if (opts->has_gl) {
mode = opts->gl;
}

egl_init(opts->u.egl_headless.rendernode, mode, &error_fatal);
}

static void egl_headless_init(DisplayState *ds, DisplayOptions *opts)
{
DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAYGL_MODE_ON;
QemuConsole *con;
egl_dpy *edpy;
int idx;

if (egl_rendernode_init(opts->u.egl_headless.rendernode, mode) < 0) {
error_report("egl: render node init failed");
exit(1);
}

for (idx = 0;; idx++) {
DisplayGLCtx *ctx;

Expand Down
78 changes: 72 additions & 6 deletions ui/egl-helpers.c
Expand Up @@ -19,13 +19,57 @@
#include "qemu/error-report.h"
#include "ui/console.h"
#include "ui/egl-helpers.h"
#include "sysemu/sysemu.h"
#include "qapi/error.h"

EGLDisplay *qemu_egl_display;
EGLConfig qemu_egl_config;
DisplayGLMode qemu_egl_mode;

/* ------------------------------------------------------------------ */

#if defined(CONFIG_X11) || defined(CONFIG_GBM)
static const char *egl_get_error_string(void)
{
EGLint error = eglGetError();

switch (error) {
case EGL_SUCCESS:
return "EGL_SUCCESS";
case EGL_NOT_INITIALIZED:
return "EGL_NOT_INITIALIZED";
case EGL_BAD_ACCESS:
return "EGL_BAD_ACCESS";
case EGL_BAD_ALLOC:
return "EGL_BAD_ALLOC";
case EGL_BAD_ATTRIBUTE:
return "EGL_BAD_ATTRIBUTE";
case EGL_BAD_CONTEXT:
return "EGL_BAD_CONTEXT";
case EGL_BAD_CONFIG:
return "EGL_BAD_CONFIG";
case EGL_BAD_CURRENT_SURFACE:
return "EGL_BAD_CURRENT_SURFACE";
case EGL_BAD_DISPLAY:
return "EGL_BAD_DISPLAY";
case EGL_BAD_SURFACE:
return "EGL_BAD_SURFACE";
case EGL_BAD_MATCH:
return "EGL_BAD_MATCH";
case EGL_BAD_PARAMETER:
return "EGL_BAD_PARAMETER";
case EGL_BAD_NATIVE_PIXMAP:
return "EGL_BAD_NATIVE_PIXMAP";
case EGL_BAD_NATIVE_WINDOW:
return "EGL_BAD_NATIVE_WINDOW";
case EGL_CONTEXT_LOST:
return "EGL_CONTEXT_LOST";
default:
return "Unknown EGL error";
}
}
#endif

static void egl_fb_delete_texture(egl_fb *fb)
{
if (!fb->delete_texture) {
Expand Down Expand Up @@ -438,29 +482,29 @@ static int qemu_egl_init_dpy(EGLNativeDisplayType dpy,

qemu_egl_display = qemu_egl_get_display(dpy, platform);
if (qemu_egl_display == EGL_NO_DISPLAY) {
error_report("egl: eglGetDisplay failed");
error_report("egl: eglGetDisplay failed: %s", egl_get_error_string());
return -1;
}

b = eglInitialize(qemu_egl_display, &major, &minor);
if (b == EGL_FALSE) {
error_report("egl: eglInitialize failed");
error_report("egl: eglInitialize failed: %s", egl_get_error_string());
return -1;
}

b = eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API);
if (b == EGL_FALSE) {
error_report("egl: eglBindAPI failed (%s mode)",
gles ? "gles" : "core");
error_report("egl: eglBindAPI failed (%s mode): %s",
gles ? "gles" : "core", egl_get_error_string());
return -1;
}

b = eglChooseConfig(qemu_egl_display,
gles ? conf_att_gles : conf_att_core,
&qemu_egl_config, 1, &n);
if (b == EGL_FALSE || n != 1) {
error_report("egl: eglChooseConfig failed (%s mode)",
gles ? "gles" : "core");
error_report("egl: eglChooseConfig failed (%s mode): %s",
gles ? "gles" : "core", egl_get_error_string());
return -1;
}

Expand Down Expand Up @@ -527,3 +571,25 @@ EGLContext qemu_egl_init_ctx(void)

return ectx;
}

bool egl_init(const char *rendernode, DisplayGLMode mode, Error **errp)
{
ERRP_GUARD();

if (mode == DISPLAYGL_MODE_OFF) {
error_setg(errp, "egl: turning off GL doesn't make sense");
return false;
}

#ifdef CONFIG_GBM
if (egl_rendernode_init(rendernode, mode) < 0) {
error_setg(errp, "egl: render node init failed");
return false;
}
display_opengl = 1;
return true;
#else
error_setg(errp, "egl: not available on this platform");
return false;
#endif
}
6 changes: 4 additions & 2 deletions ui/meson.build
Expand Up @@ -83,15 +83,17 @@ if dbus_display
'--interface-prefix', 'org.qemu.',
'--c-namespace', 'QemuDBus',
'--generate-c-code', '@BASENAME@'])
dbus_ss.add(when: [gio, pixman, opengl, gbm],
dbus_display1_lib = static_library('dbus-display1', dbus_display1, dependencies: gio)
dbus_display1_dep = declare_dependency(link_with: dbus_display1_lib, include_directories: include_directories('.'))
dbus_ss.add(when: [gio, pixman, dbus_display1_dep],
if_true: [files(
'dbus-chardev.c',
'dbus-clipboard.c',
'dbus-console.c',
'dbus-error.c',
'dbus-listener.c',
'dbus.c',
), dbus_display1])
), opengl, gbm])
ui_modules += {'dbus' : dbus_ss}
endif

Expand Down
24 changes: 23 additions & 1 deletion ui/sdl2.c
Expand Up @@ -58,6 +58,11 @@ static Notifier mouse_mode_notifier;
#define SDL2_MAX_IDLE_COUNT (2 * GUI_REFRESH_INTERVAL_DEFAULT \
/ SDL2_REFRESH_INTERVAL_BUSY + 1)

/* introduced in SDL 2.0.10 */
#ifndef SDL_HINT_RENDER_BATCHING
#define SDL_HINT_RENDER_BATCHING "SDL_RENDER_BATCHING"
#endif

static void sdl_update_caption(struct sdl2_console *scon);

static struct sdl2_console *get_scon_from_window(uint32_t window_id)
Expand Down Expand Up @@ -99,9 +104,20 @@ void sdl2_window_create(struct sdl2_console *scon)
surface_width(scon->surface),
surface_height(scon->surface),
flags);
if (scon->opengl) {
const char *driver = "opengl";

if (scon->opts->gl == DISPLAYGL_MODE_ES) {
driver = "opengles2";
}

SDL_SetHint(SDL_HINT_RENDER_DRIVER, driver);
SDL_SetHint(SDL_HINT_RENDER_BATCHING, "1");
}
scon->real_renderer = SDL_CreateRenderer(scon->real_window, -1, 0);

if (scon->opengl) {
scon->winctx = SDL_GL_GetCurrentContext();
scon->winctx = SDL_GL_CreateContext(scon->real_window);
}
sdl_update_caption(scon);
}
Expand All @@ -112,6 +128,8 @@ void sdl2_window_destroy(struct sdl2_console *scon)
return;
}

SDL_GL_DeleteContext(scon->winctx);
scon->winctx = NULL;
SDL_DestroyRenderer(scon->real_renderer);
scon->real_renderer = NULL;
SDL_DestroyWindow(scon->real_window);
Expand Down Expand Up @@ -841,6 +859,10 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o)
}
#endif

if (SDL_GetHintBoolean("QEMU_ENABLE_SDL_LOGGING", SDL_FALSE)) {
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE);
}

if (SDL_Init(SDL_INIT_VIDEO)) {
fprintf(stderr, "Could not initialize SDL(%s) - exiting\n",
SDL_GetError());
Expand Down
1 change: 0 additions & 1 deletion ui/shader/texture-blit-flip.vert
@@ -1,4 +1,3 @@

#version 300 es

in vec2 in_position;
Expand Down
1 change: 0 additions & 1 deletion ui/shader/texture-blit.frag
@@ -1,4 +1,3 @@

#version 300 es

uniform sampler2D image;
Expand Down
1 change: 0 additions & 1 deletion ui/shader/texture-blit.vert
@@ -1,4 +1,3 @@

#version 300 es

in vec2 in_position;
Expand Down
7 changes: 1 addition & 6 deletions ui/spice-core.c
Expand Up @@ -820,12 +820,7 @@ static void qemu_spice_init(void)
"incompatible with -spice port/tls-port");
exit(1);
}
if (egl_rendernode_init(qemu_opt_get(opts, "rendernode"),
DISPLAYGL_MODE_ON) != 0) {
error_report("Failed to initialize EGL render node for SPICE GL");
exit(1);
}
display_opengl = 1;
egl_init(qemu_opt_get(opts, "rendernode"), DISPLAYGL_MODE_ON, &error_fatal);
spice_opengl = 1;
}
#endif
Expand Down
8 changes: 4 additions & 4 deletions ui/spice-display.c
Expand Up @@ -460,11 +460,11 @@ void qemu_spice_cursor_refresh_bh(void *opaque)
if (ssd->cursor) {
QEMUCursor *c = ssd->cursor;
assert(ssd->dcl.con);
cursor_get(c);
cursor_ref(c);
qemu_mutex_unlock(&ssd->lock);
dpy_cursor_define(ssd->dcl.con, c);
qemu_mutex_lock(&ssd->lock);
cursor_put(c);
cursor_unref(c);
}

if (ssd->mouse_x != -1 && ssd->mouse_y != -1) {
Expand Down Expand Up @@ -765,8 +765,8 @@ static void display_mouse_define(DisplayChangeListener *dcl,
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);

qemu_mutex_lock(&ssd->lock);
cursor_get(c);
cursor_put(ssd->cursor);
cursor_ref(c);
cursor_unref(ssd->cursor);
ssd->cursor = c;
ssd->hot_x = c->hot_x;
ssd->hot_y = c->hot_y;
Expand Down
8 changes: 2 additions & 6 deletions ui/vnc.c
Expand Up @@ -988,10 +988,10 @@ static void vnc_mouse_set(DisplayChangeListener *dcl,

static int vnc_cursor_define(VncState *vs)
{
QEMUCursor *c = vs->vd->cursor;
QEMUCursor *c = qemu_console_get_cursor(vs->vd->dcl.con);
int isize;

if (!vs->vd->cursor) {
if (!c) {
return -1;
}

Expand Down Expand Up @@ -1029,11 +1029,7 @@ static void vnc_dpy_cursor_define(DisplayChangeListener *dcl,
VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
VncState *vs;

cursor_put(vd->cursor);
g_free(vd->cursor_mask);

vd->cursor = c;
cursor_get(vd->cursor);
vd->cursor_msize = cursor_get_mono_bpl(c) * c->height;
vd->cursor_mask = g_malloc0(vd->cursor_msize);
cursor_get_mono_mask(c, 0, vd->cursor_mask);
Expand Down
1 change: 0 additions & 1 deletion ui/vnc.h
Expand Up @@ -159,7 +159,6 @@ struct VncDisplay
QKbdState *kbd;
QemuMutex mutex;

QEMUCursor *cursor;
int cursor_msize;
uint8_t *cursor_mask;

Expand Down