aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2017-05-15 14:26:02 +0100
committerStefan Hajnoczi <stefanha@redhat.com>2017-05-15 14:26:47 +0100
commit384d9d554aa4de0aa81a5b0be074d8c02f0941d4 (patch)
tree8b3402c12d71ad53e50638d64b6482752f7597f1
parentba9915e1f87fec742775d64859e881e4ab611429 (diff)
parent7c9209e7bfb8c09ab5a4cadaa84928d146874a05 (diff)
downloadqemu-384d9d554aa4de0aa81a5b0be074d8c02f0941d4.zip
qemu-384d9d554aa4de0aa81a5b0be074d8c02f0941d4.tar.gz
qemu-384d9d554aa4de0aa81a5b0be074d8c02f0941d4.tar.bz2
Merge remote-tracking branch 'kraxel/tags/pull-ui-20170512-1' into staging
ui: add egl-headless ui: some vnc cleanups ui: absolute events for input-linux # gpg: Signature made Fri 12 May 2017 12:50:07 PM BST # gpg: using RSA key 0x4CB6D8EED3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" # Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138 * kraxel/tags/pull-ui-20170512-1: vnc: replace hweight_long() with ctpopl() vnc: simple clean up opengl: add egl-headless display egl: explicitly ask for core context egl-helpers: add missing error check egl-helpers: fix display init for x11 egl-helpers: drop support for gles and debug logging virtio-gpu: move virtio_gpu_gl_block ui: input-linux: Add absolute event support ui: Support non-zero minimum values for absolute input axes Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
-rw-r--r--hw/display/virtio-gpu-3d.c16
-rw-r--r--hw/display/virtio-gpu.c18
-rw-r--r--hw/input/virtio-input-hid.c6
-rw-r--r--include/hw/virtio/virtio-gpu.h1
-rw-r--r--include/qemu/bitops.h10
-rw-r--r--include/ui/console.h3
-rw-r--r--include/ui/egl-helpers.h3
-rw-r--r--include/ui/input.h11
-rw-r--r--ui/Makefile.objs1
-rw-r--r--ui/cocoa.m4
-rw-r--r--ui/egl-context.c7
-rw-r--r--ui/egl-headless.c158
-rw-r--r--ui/egl-helpers.c88
-rw-r--r--ui/gtk-egl.c2
-rw-r--r--ui/gtk.c4
-rw-r--r--ui/input-linux.c25
-rw-r--r--ui/input.c31
-rw-r--r--ui/sdl.c4
-rw-r--r--ui/sdl2.c4
-rw-r--r--ui/spice-input.c4
-rw-r--r--ui/vnc-enc-zrle.c1
-rw-r--r--ui/vnc.c10
-rw-r--r--vl.c16
23 files changed, 311 insertions, 116 deletions
diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-3d.c
index f49b7fe..8c106a6 100644
--- a/hw/display/virtio-gpu-3d.c
+++ b/hw/display/virtio-gpu-3d.c
@@ -600,6 +600,22 @@ void virtio_gpu_virgl_reset(VirtIOGPU *g)
}
}
+void virtio_gpu_gl_block(void *opaque, bool block)
+{
+ VirtIOGPU *g = opaque;
+
+ if (block) {
+ g->renderer_blocked++;
+ } else {
+ g->renderer_blocked--;
+ }
+ assert(g->renderer_blocked >= 0);
+
+ if (g->renderer_blocked == 0) {
+ virtio_gpu_process_cmdq(g);
+ }
+}
+
int virtio_gpu_virgl_init(VirtIOGPU *g)
{
int ret;
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index e1056f3..cfb5dfa 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -929,28 +929,14 @@ static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
return 0;
}
-static void virtio_gpu_gl_block(void *opaque, bool block)
-{
- VirtIOGPU *g = opaque;
-
- if (block) {
- g->renderer_blocked++;
- } else {
- g->renderer_blocked--;
- }
- assert(g->renderer_blocked >= 0);
-
- if (g->renderer_blocked == 0) {
- virtio_gpu_process_cmdq(g);
- }
-}
-
const GraphicHwOps virtio_gpu_ops = {
.invalidate = virtio_gpu_invalidate_display,
.gfx_update = virtio_gpu_update_display,
.text_update = virtio_gpu_text_update,
.ui_info = virtio_gpu_ui_info,
+#ifdef CONFIG_VIRGL
.gl_block = virtio_gpu_gl_block,
+#endif
};
static const VMStateDescription vmstate_virtio_gpu_scanout = {
diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c
index 3ee0c18..46c0381 100644
--- a/hw/input/virtio-input-hid.c
+++ b/hw/input/virtio-input-hid.c
@@ -484,12 +484,14 @@ static struct virtio_input_config virtio_tablet_config[] = {
.select = VIRTIO_INPUT_CFG_ABS_INFO,
.subsel = ABS_X,
.size = sizeof(virtio_input_absinfo),
- .u.abs.max = const_le32(INPUT_EVENT_ABS_SIZE - 1),
+ .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
+ .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
},{
.select = VIRTIO_INPUT_CFG_ABS_INFO,
.subsel = ABS_Y,
.size = sizeof(virtio_input_absinfo),
- .u.abs.max = const_le32(INPUT_EVENT_ABS_SIZE - 1),
+ .u.abs.min = const_le32(INPUT_EVENT_ABS_MIN),
+ .u.abs.max = const_le32(INPUT_EVENT_ABS_MAX),
},
{ /* end of list */ },
};
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
index f3ffdce..83f474f 100644
--- a/include/hw/virtio/virtio-gpu.h
+++ b/include/hw/virtio/virtio-gpu.h
@@ -169,6 +169,7 @@ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd);
void virtio_gpu_virgl_fence_poll(VirtIOGPU *g);
void virtio_gpu_virgl_reset(VirtIOGPU *g);
+void virtio_gpu_gl_block(void *opaque, bool block);
int virtio_gpu_virgl_init(VirtIOGPU *g);
#endif
diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h
index 1881284..3f0926c 100644
--- a/include/qemu/bitops.h
+++ b/include/qemu/bitops.h
@@ -201,16 +201,6 @@ static inline unsigned long find_first_zero_bit(const unsigned long *addr,
return find_next_zero_bit(addr, size, 0);
}
-static inline unsigned long hweight_long(unsigned long w)
-{
- unsigned long count;
-
- for (count = 0; w; w >>= 1) {
- count += w & 1;
- }
- return count;
-}
-
/**
* rol8 - rotate an 8-bit value left
* @word: value to rotate
diff --git a/include/ui/console.h b/include/ui/console.h
index d759338..7262bef 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -527,4 +527,7 @@ static inline void early_gtk_display_init(int opengl)
}
#endif
+/* egl-headless.c */
+void egl_headless_init(void);
+
#endif
diff --git a/include/ui/egl-helpers.h b/include/ui/egl-helpers.h
index 88a13e8..c785d60 100644
--- a/include/ui/egl-helpers.h
+++ b/include/ui/egl-helpers.h
@@ -21,7 +21,8 @@ int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc);
EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, Window win);
-int qemu_egl_init_dpy(EGLNativeDisplayType dpy, bool gles, bool debug);
+int qemu_egl_init_dpy_x11(EGLNativeDisplayType dpy);
+int qemu_egl_init_dpy_mesa(EGLNativeDisplayType dpy);
EGLContext qemu_egl_init_ctx(void);
#endif /* EGL_HELPERS_H */
diff --git a/include/ui/input.h b/include/ui/input.h
index d06a12d..3cfd0f3 100644
--- a/include/ui/input.h
+++ b/include/ui/input.h
@@ -8,7 +8,8 @@
#define INPUT_EVENT_MASK_REL (1<<INPUT_EVENT_KIND_REL)
#define INPUT_EVENT_MASK_ABS (1<<INPUT_EVENT_KIND_ABS)
-#define INPUT_EVENT_ABS_SIZE 0x8000
+#define INPUT_EVENT_ABS_MIN 0x0000
+#define INPUT_EVENT_ABS_MAX 0x7FFF
typedef struct QemuInputHandler QemuInputHandler;
typedef struct QemuInputHandlerState QemuInputHandlerState;
@@ -54,12 +55,14 @@ void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
uint32_t button_old, uint32_t button_new);
bool qemu_input_is_absolute(void);
-int qemu_input_scale_axis(int value, int size_in, int size_out);
+int qemu_input_scale_axis(int value,
+ int min_in, int max_in,
+ int min_out, int max_out);
InputEvent *qemu_input_event_new_move(InputEventKind kind,
InputAxis axis, int value);
void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value);
-void qemu_input_queue_abs(QemuConsole *src, InputAxis axis,
- int value, int size);
+void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value,
+ int min_in, int max_in);
void qemu_input_check_mode_change(void);
void qemu_add_mouse_mode_change_notifier(Notifier *notify);
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index 27566b3..aac6ae8 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -33,6 +33,7 @@ common-obj-y += shader.o
common-obj-y += console-gl.o
common-obj-y += egl-helpers.o
common-obj-y += egl-context.o
+common-obj-y += egl-headless.o
ifeq ($(CONFIG_GTK_GL),y)
common-obj-$(CONFIG_GTK) += gtk-gl-area.o
else
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 207555e..3a9bc4d 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -749,8 +749,8 @@ QemuCocoaView *cocoaView;
* clicks in the titlebar.
*/
if ([self screenContainsPoint:p]) {
- qemu_input_queue_abs(dcl->con, INPUT_AXIS_X, p.x, screen.width);
- qemu_input_queue_abs(dcl->con, INPUT_AXIS_Y, screen.height - p.y, screen.height);
+ qemu_input_queue_abs(dcl->con, INPUT_AXIS_X, p.x, 0, screen.width);
+ qemu_input_queue_abs(dcl->con, INPUT_AXIS_Y, screen.height - p.y, 0, screen.height);
}
} else {
qemu_input_queue_rel(dcl->con, INPUT_AXIS_X, (int)[event deltaX]);
diff --git a/ui/egl-context.c b/ui/egl-context.c
index 3a02b68..2161969 100644
--- a/ui/egl-context.c
+++ b/ui/egl-context.c
@@ -7,9 +7,10 @@ QEMUGLContext qemu_egl_create_context(DisplayChangeListener *dcl,
{
EGLContext ctx;
EGLint ctx_att[] = {
- EGL_CONTEXT_CLIENT_VERSION, params->major_ver,
- EGL_CONTEXT_MINOR_VERSION_KHR, params->minor_ver,
- EGL_NONE
+ EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
+ EGL_CONTEXT_CLIENT_VERSION, params->major_ver,
+ EGL_CONTEXT_MINOR_VERSION_KHR, params->minor_ver,
+ EGL_NONE
};
ctx = eglCreateContext(qemu_egl_display, qemu_egl_config,
diff --git a/ui/egl-headless.c b/ui/egl-headless.c
new file mode 100644
index 0000000..d8d800f
--- /dev/null
+++ b/ui/egl-headless.c
@@ -0,0 +1,158 @@
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "sysemu/sysemu.h"
+#include "ui/console.h"
+#include "ui/egl-helpers.h"
+#include "ui/egl-context.h"
+
+typedef struct egl_dpy {
+ DisplayChangeListener dcl;
+ DisplaySurface *ds;
+ int width, height;
+ GLuint texture;
+ GLuint framebuffer;
+ GLuint blit_texture;
+ GLuint blit_framebuffer;
+ bool y_0_top;
+} egl_dpy;
+
+static void egl_refresh(DisplayChangeListener *dcl)
+{
+ graphic_hw_update(dcl->con);
+}
+
+static void egl_gfx_update(DisplayChangeListener *dcl,
+ int x, int y, int w, int h)
+{
+}
+
+static void egl_gfx_switch(DisplayChangeListener *dcl,
+ struct DisplaySurface *new_surface)
+{
+ egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
+
+ edpy->ds = new_surface;
+}
+
+static void egl_scanout_disable(DisplayChangeListener *dcl)
+{
+ egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
+
+ edpy->texture = 0;
+ /* XXX: delete framebuffers here ??? */
+}
+
+static void egl_scanout_texture(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)
+{
+ egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
+
+ edpy->texture = backing_id;
+ edpy->y_0_top = backing_y_0_top;
+
+ /* source framebuffer */
+ if (!edpy->framebuffer) {
+ glGenFramebuffers(1, &edpy->framebuffer);
+ }
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, edpy->framebuffer);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, edpy->texture, 0);
+
+ /* dest framebuffer */
+ if (!edpy->blit_framebuffer) {
+ glGenFramebuffers(1, &edpy->blit_framebuffer);
+ glGenTextures(1, &edpy->blit_texture);
+ edpy->width = 0;
+ edpy->height = 0;
+ }
+ if (edpy->width != backing_width || edpy->height != backing_height) {
+ edpy->width = backing_width;
+ edpy->height = backing_height;
+ glBindTexture(GL_TEXTURE_2D, edpy->blit_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
+ edpy->width, edpy->height,
+ 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, edpy->blit_framebuffer);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, edpy->blit_texture, 0);
+ }
+}
+
+static void egl_scanout_flush(DisplayChangeListener *dcl,
+ uint32_t x, uint32_t y,
+ uint32_t w, uint32_t h)
+{
+ egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
+ GLuint y1, y2;
+
+ if (!edpy->texture || !edpy->ds) {
+ return;
+ }
+ assert(surface_width(edpy->ds) == edpy->width);
+ assert(surface_height(edpy->ds) == edpy->height);
+ assert(surface_format(edpy->ds) == PIXMAN_x8r8g8b8);
+
+ /* blit framebuffer, flip if needed */
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, edpy->framebuffer);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, edpy->blit_framebuffer);
+ glViewport(0, 0, edpy->width, edpy->height);
+ y1 = edpy->y_0_top ? edpy->height : 0;
+ y2 = edpy->y_0_top ? 0 : edpy->height;
+ glBlitFramebuffer(0, y1, edpy->width, y2,
+ 0, 0, edpy->width, edpy->height,
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ /* read pixels to surface */
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, edpy->blit_framebuffer);
+ glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ glReadPixels(0, 0, edpy->width, edpy->height,
+ GL_BGRA, GL_UNSIGNED_BYTE, surface_data(edpy->ds));
+
+ /* notify about updates */
+ dpy_gfx_update(edpy->dcl.con, x, y, w, h);
+}
+
+static const DisplayChangeListenerOps egl_ops = {
+ .dpy_name = "egl-headless",
+ .dpy_refresh = egl_refresh,
+ .dpy_gfx_update = egl_gfx_update,
+ .dpy_gfx_switch = egl_gfx_switch,
+
+ .dpy_gl_ctx_create = qemu_egl_create_context,
+ .dpy_gl_ctx_destroy = qemu_egl_destroy_context,
+ .dpy_gl_ctx_make_current = qemu_egl_make_context_current,
+ .dpy_gl_ctx_get_current = qemu_egl_get_current_context,
+
+ .dpy_gl_scanout_disable = egl_scanout_disable,
+ .dpy_gl_scanout_texture = egl_scanout_texture,
+ .dpy_gl_update = egl_scanout_flush,
+};
+
+void egl_headless_init(void)
+{
+ QemuConsole *con;
+ egl_dpy *edpy;
+ int idx;
+
+ if (egl_rendernode_init(NULL) < 0) {
+ error_report("egl: render node init failed");
+ exit(1);
+ }
+
+ for (idx = 0;; idx++) {
+ con = qemu_console_lookup_by_index(idx);
+ if (!con || !qemu_console_is_graphic(con)) {
+ break;
+ }
+
+ edpy = g_new0(egl_dpy, 1);
+ edpy->dcl.con = con;
+ edpy->dcl.ops = &egl_ops;
+ register_displaychangelistener(&edpy->dcl);
+ }
+}
diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index b7b6b2e..4a4d337 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -26,18 +26,6 @@ EGLConfig qemu_egl_config;
/* ---------------------------------------------------------------------- */
-static bool egl_gles;
-static int egl_debug;
-
-#define egl_dbg(_x ...) \
- do { \
- if (egl_debug) { \
- fprintf(stderr, "egl: " _x); \
- } \
- } while (0);
-
-/* ---------------------------------------------------------------------- */
-
#ifdef CONFIG_OPENGL_DMABUF
int qemu_egl_rn_fd;
@@ -92,6 +80,7 @@ static int qemu_egl_rendernode_open(const char *rendernode)
int egl_rendernode_init(const char *rendernode)
{
qemu_egl_rn_fd = -1;
+ int rc;
qemu_egl_rn_fd = qemu_egl_rendernode_open(rendernode);
if (qemu_egl_rn_fd == -1) {
@@ -105,7 +94,11 @@ int egl_rendernode_init(const char *rendernode)
goto err;
}
- qemu_egl_init_dpy((EGLNativeDisplayType)qemu_egl_rn_gbm_dev, false, false);
+ rc = qemu_egl_init_dpy_mesa((EGLNativeDisplayType)qemu_egl_rn_gbm_dev);
+ if (rc != 0) {
+ /* qemu_egl_init_dpy_mesa reports error */
+ goto err;
+ }
if (!epoxy_has_egl_extension(qemu_egl_display,
"EGL_KHR_surfaceless_context")) {
@@ -171,8 +164,6 @@ EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, Window win)
EGLSurface esurface;
EGLBoolean b;
- egl_dbg("eglCreateWindowSurface (x11 win id 0x%lx) ...\n",
- (unsigned long) win);
esurface = eglCreateWindowSurface(qemu_egl_display,
qemu_egl_config,
(EGLNativeWindowType)win, NULL);
@@ -220,20 +211,19 @@ EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, Window win)
* platform extensions (EGL_KHR_platform_gbm and friends) yet it doesn't seem
* like mesa will be able to advertise these (even though it can do EGL 1.5).
*/
-static EGLDisplay qemu_egl_get_display(void *native)
+static EGLDisplay qemu_egl_get_display(EGLNativeDisplayType native,
+ EGLenum platform)
{
EGLDisplay dpy = EGL_NO_DISPLAY;
-#ifdef EGL_MESA_platform_gbm
/* In practise any EGL 1.5 implementation would support the EXT extension */
if (epoxy_has_egl_extension(NULL, "EGL_EXT_platform_base")) {
PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplayEXT =
(void *) eglGetProcAddress("eglGetPlatformDisplayEXT");
- if (getPlatformDisplayEXT) {
- dpy = getPlatformDisplayEXT(EGL_PLATFORM_GBM_MESA, native, NULL);
+ if (getPlatformDisplayEXT && platform != 0) {
+ dpy = getPlatformDisplayEXT(platform, native, NULL);
}
}
-#endif
if (dpy == EGL_NO_DISPLAY) {
/* fallback */
@@ -242,7 +232,8 @@ static EGLDisplay qemu_egl_get_display(void *native)
return dpy;
}
-int qemu_egl_init_dpy(EGLNativeDisplayType dpy, bool gles, bool debug)
+static int qemu_egl_init_dpy(EGLNativeDisplayType dpy,
+ EGLenum platform)
{
static const EGLint conf_att_gl[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
@@ -253,75 +244,66 @@ int qemu_egl_init_dpy(EGLNativeDisplayType dpy, bool gles, bool debug)
EGL_ALPHA_SIZE, 0,
EGL_NONE,
};
- static const EGLint conf_att_gles[] = {
- EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL_RED_SIZE, 5,
- EGL_GREEN_SIZE, 5,
- EGL_BLUE_SIZE, 5,
- EGL_ALPHA_SIZE, 0,
- EGL_NONE,
- };
EGLint major, minor;
EGLBoolean b;
EGLint n;
- if (debug) {
- egl_debug = 1;
- setenv("EGL_LOG_LEVEL", "debug", true);
- setenv("LIBGL_DEBUG", "verbose", true);
- }
-
- egl_dbg("qemu_egl_get_display (dpy %p) ...\n", dpy);
- qemu_egl_display = qemu_egl_get_display(dpy);
+ qemu_egl_display = qemu_egl_get_display(dpy, platform);
if (qemu_egl_display == EGL_NO_DISPLAY) {
error_report("egl: eglGetDisplay failed");
return -1;
}
- egl_dbg("eglInitialize ...\n");
b = eglInitialize(qemu_egl_display, &major, &minor);
if (b == EGL_FALSE) {
error_report("egl: eglInitialize failed");
return -1;
}
- egl_dbg("eglBindAPI ...\n");
- b = eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API);
+ b = eglBindAPI(EGL_OPENGL_API);
if (b == EGL_FALSE) {
error_report("egl: eglBindAPI failed");
return -1;
}
- egl_dbg("eglChooseConfig ...\n");
- b = eglChooseConfig(qemu_egl_display,
- gles ? conf_att_gles : conf_att_gl,
+ b = eglChooseConfig(qemu_egl_display, conf_att_gl,
&qemu_egl_config, 1, &n);
if (b == EGL_FALSE || n != 1) {
error_report("egl: eglChooseConfig failed");
return -1;
}
-
- egl_gles = gles;
return 0;
}
+int qemu_egl_init_dpy_x11(EGLNativeDisplayType dpy)
+{
+#ifdef EGL_KHR_platform_x11
+ return qemu_egl_init_dpy(dpy, EGL_PLATFORM_X11_KHR);
+#else
+ return qemu_egl_init_dpy(dpy, 0);
+#endif
+}
+
+int qemu_egl_init_dpy_mesa(EGLNativeDisplayType dpy)
+{
+#ifdef EGL_MESA_platform_gbm
+ return qemu_egl_init_dpy(dpy, EGL_PLATFORM_GBM_MESA);
+#else
+ return qemu_egl_init_dpy(dpy, 0);
+#endif
+}
+
EGLContext qemu_egl_init_ctx(void)
{
static const EGLint ctx_att_gl[] = {
+ EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
EGL_NONE
};
- static const EGLint ctx_att_gles[] = {
- EGL_CONTEXT_CLIENT_VERSION, 2,
- EGL_NONE
- };
-
EGLContext ectx;
EGLBoolean b;
- egl_dbg("eglCreateContext ...\n");
ectx = eglCreateContext(qemu_egl_display, qemu_egl_config, EGL_NO_CONTEXT,
- egl_gles ? ctx_att_gles : ctx_att_gl);
+ ctx_att_gl);
if (ectx == EGL_NO_CONTEXT) {
error_report("egl: eglCreateContext failed");
return NULL;
diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index d53288f..cf48cca 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -246,7 +246,7 @@ void gtk_egl_init(void)
GdkDisplay *gdk_display = gdk_display_get_default();
Display *x11_display = gdk_x11_display_get_xdisplay(gdk_display);
- if (qemu_egl_init_dpy(x11_display, false, false) < 0) {
+ if (qemu_egl_init_dpy_x11(x11_display) < 0) {
return;
}
diff --git a/ui/gtk.c b/ui/gtk.c
index 7479cee..0213ad0 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -912,9 +912,9 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
return TRUE;
}
qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_X, x,
- surface_width(vc->gfx.ds));
+ 0, surface_width(vc->gfx.ds));
qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_Y, y,
- surface_height(vc->gfx.ds));
+ 0, surface_height(vc->gfx.ds));
qemu_input_event_sync();
} else if (s->last_set && s->ptr_owner == vc) {
qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_X, x - s->last_x);
diff --git a/ui/input-linux.c b/ui/input-linux.c
index dc0613c..49d52a6 100644
--- a/ui/input-linux.c
+++ b/ui/input-linux.c
@@ -169,6 +169,10 @@ struct InputLinux {
bool has_abs_x;
int num_keys;
int num_btns;
+ int abs_x_min;
+ int abs_x_max;
+ int abs_y_min;
+ int abs_y_max;
struct input_event event;
int read_offset;
@@ -314,6 +318,18 @@ static void input_linux_handle_mouse(InputLinux *il, struct input_event *event)
break;
}
break;
+ case EV_ABS:
+ switch (event->code) {
+ case ABS_X:
+ qemu_input_queue_abs(NULL, INPUT_AXIS_X, event->value,
+ il->abs_x_min, il->abs_x_max);
+ break;
+ case ABS_Y:
+ qemu_input_queue_abs(NULL, INPUT_AXIS_Y, event->value,
+ il->abs_y_min, il->abs_y_max);
+ break;
+ }
+ break;
case EV_SYN:
qemu_input_event_sync();
if (il->wheel != 0) {
@@ -351,7 +367,7 @@ static void input_linux_event(void *opaque)
if (il->num_keys) {
input_linux_handle_keyboard(il, &il->event);
}
- if (il->has_rel_x && il->num_btns) {
+ if ((il->has_rel_x || il->has_abs_x) && il->num_btns) {
input_linux_handle_mouse(il, &il->event);
}
}
@@ -364,6 +380,7 @@ static void input_linux_complete(UserCreatable *uc, Error **errp)
uint8_t keymap[KEY_CNT / 8], keystate[KEY_CNT / 8];
unsigned int i;
int rc, ver;
+ struct input_absinfo absinfo;
if (!il->evdev) {
error_setg(errp, "no input device specified");
@@ -402,6 +419,12 @@ static void input_linux_complete(UserCreatable *uc, Error **errp)
rc = ioctl(il->fd, EVIOCGBIT(EV_ABS, sizeof(absmap)), &absmap);
if (absmap & (1 << ABS_X)) {
il->has_abs_x = true;
+ rc = ioctl(il->fd, EVIOCGABS(ABS_X), &absinfo);
+ il->abs_x_min = absinfo.minimum;
+ il->abs_x_max = absinfo.maximum;
+ rc = ioctl(il->fd, EVIOCGABS(ABS_Y), &absinfo);
+ il->abs_y_min = absinfo.minimum;
+ il->abs_y_max = absinfo.maximum;
}
}
diff --git a/ui/input.c b/ui/input.c
index 830f912..290ca9f 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -166,6 +166,11 @@ void qmp_input_send_event(bool has_device, const char *device,
qemu_input_event_sync();
}
+static int qemu_input_transform_invert_abs_value(int value)
+{
+ return (int64_t)INPUT_EVENT_ABS_MAX - value + INPUT_EVENT_ABS_MIN;
+}
+
static void qemu_input_transform_abs_rotate(InputEvent *evt)
{
InputMoveEvent *move = evt->u.abs.data;
@@ -175,16 +180,16 @@ static void qemu_input_transform_abs_rotate(InputEvent *evt)
move->axis = INPUT_AXIS_Y;
} else if (move->axis == INPUT_AXIS_Y) {
move->axis = INPUT_AXIS_X;
- move->value = INPUT_EVENT_ABS_SIZE - 1 - move->value;
+ move->value = qemu_input_transform_invert_abs_value(move->value);
}
break;
case 180:
- move->value = INPUT_EVENT_ABS_SIZE - 1 - move->value;
+ move->value = qemu_input_transform_invert_abs_value(move->value);
break;
case 270:
if (move->axis == INPUT_AXIS_X) {
move->axis = INPUT_AXIS_Y;
- move->value = INPUT_EVENT_ABS_SIZE - 1 - move->value;
+ move->value = qemu_input_transform_invert_abs_value(move->value);
} else if (move->axis == INPUT_AXIS_Y) {
move->axis = INPUT_AXIS_X;
}
@@ -467,12 +472,17 @@ bool qemu_input_is_absolute(void)
return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS);
}
-int qemu_input_scale_axis(int value, int size_in, int size_out)
+int qemu_input_scale_axis(int value,
+ int min_in, int max_in,
+ int min_out, int max_out)
{
- if (size_in < 2) {
- return size_out / 2;
+ int64_t range_in = (int64_t)max_in - min_in;
+ int64_t range_out = (int64_t)max_out - min_out;
+
+ if (range_in < 1) {
+ return min_out + range_out / 2;
}
- return (int64_t)value * (size_out - 1) / (size_in - 1);
+ return ((int64_t)value - min_in) * range_out / range_in + min_out;
}
InputEvent *qemu_input_event_new_move(InputEventKind kind,
@@ -496,10 +506,13 @@ void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value)
qapi_free_InputEvent(evt);
}
-void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value, int size)
+void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value,
+ int min_in, int max_in)
{
InputEvent *evt;
- int scaled = qemu_input_scale_axis(value, size, INPUT_EVENT_ABS_SIZE);
+ int scaled = qemu_input_scale_axis(value, min_in, max_in,
+ INPUT_EVENT_ABS_MIN,
+ INPUT_EVENT_ABS_MAX);
evt = qemu_input_event_new_move(INPUT_EVENT_KIND_ABS, axis, scaled);
qemu_input_event_send(src, evt);
qapi_free_InputEvent(evt);
diff --git a/ui/sdl.c b/ui/sdl.c
index 37c21a00..b35a678 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -490,9 +490,9 @@ static void sdl_send_mouse_event(int dx, int dy, int x, int y, int state)
if (qemu_input_is_absolute()) {
qemu_input_queue_abs(dcl->con, INPUT_AXIS_X, x,
- real_screen->w);
+ 0, real_screen->w);
qemu_input_queue_abs(dcl->con, INPUT_AXIS_Y, y,
- real_screen->h);
+ 0, real_screen->h);
} else {
if (guest_cursor) {
x -= guest_x;
diff --git a/ui/sdl2.c b/ui/sdl2.c
index faf9bdf..21de052 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -298,8 +298,8 @@ static void sdl_send_mouse_event(struct sdl2_console *scon, int dx, int dy,
}
}
}
- qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_X, off_x + x, max_w);
- qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_Y, off_y + y, max_h);
+ qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_X, off_x + x, 0, max_w);
+ qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_Y, off_y + y, 0, max_h);
} else {
if (guest_cursor) {
x -= guest_x;
diff --git a/ui/spice-input.c b/ui/spice-input.c
index 8eeebdb..86293dd 100644
--- a/ui/spice-input.c
+++ b/ui/spice-input.c
@@ -172,8 +172,8 @@ static void tablet_position(SpiceTabletInstance* sin, int x, int y,
QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
spice_update_buttons(pointer, 0, buttons_state);
- qemu_input_queue_abs(NULL, INPUT_AXIS_X, x, pointer->width);
- qemu_input_queue_abs(NULL, INPUT_AXIS_Y, y, pointer->height);
+ qemu_input_queue_abs(NULL, INPUT_AXIS_X, x, 0, pointer->width);
+ qemu_input_queue_abs(NULL, INPUT_AXIS_Y, y, 0, pointer->height);
qemu_input_event_sync();
}
diff --git a/ui/vnc-enc-zrle.c b/ui/vnc-enc-zrle.c
index 5489870..fd63d4f 100644
--- a/ui/vnc-enc-zrle.c
+++ b/ui/vnc-enc-zrle.c
@@ -163,7 +163,6 @@ static void zrle_choose_palette_rle(VncState *vs, int w, int h,
if (packed_bytes < estimated_bytes) {
*use_rle = false;
*use_palette = true;
- estimated_bytes = packed_bytes;
}
}
}
diff --git a/ui/vnc.c b/ui/vnc.c
index 9c4edcd..47b49c7 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -1556,8 +1556,8 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y)
}
if (vs->absolute) {
- qemu_input_queue_abs(con, INPUT_AXIS_X, x, width);
- qemu_input_queue_abs(con, INPUT_AXIS_Y, y, height);
+ qemu_input_queue_abs(con, INPUT_AXIS_X, x, 0, width);
+ qemu_input_queue_abs(con, INPUT_AXIS_Y, y, 0, height);
} else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
qemu_input_queue_rel(con, INPUT_AXIS_X, x - 0x7FFF);
qemu_input_queue_rel(con, INPUT_AXIS_Y, y - 0x7FFF);
@@ -2061,15 +2061,15 @@ static void set_pixel_format(VncState *vs, int bits_per_pixel,
}
vs->client_pf.rmax = red_max ? red_max : 0xFF;
- vs->client_pf.rbits = hweight_long(red_max);
+ vs->client_pf.rbits = ctpopl(red_max);
vs->client_pf.rshift = red_shift;
vs->client_pf.rmask = red_max << red_shift;
vs->client_pf.gmax = green_max ? green_max : 0xFF;
- vs->client_pf.gbits = hweight_long(green_max);
+ vs->client_pf.gbits = ctpopl(green_max);
vs->client_pf.gshift = green_shift;
vs->client_pf.gmask = green_max << green_shift;
vs->client_pf.bmax = blue_max ? blue_max : 0xFF;
- vs->client_pf.bbits = hweight_long(blue_max);
+ vs->client_pf.bbits = ctpopl(blue_max);
vs->client_pf.bshift = blue_shift;
vs->client_pf.bmask = blue_max << blue_shift;
vs->client_pf.bits_per_pixel = bits_per_pixel;
diff --git a/vl.c b/vl.c
index 0451cce..5c9b40e 100644
--- a/vl.c
+++ b/vl.c
@@ -2050,6 +2050,7 @@ typedef enum DisplayType {
DT_SDL,
DT_COCOA,
DT_GTK,
+ DT_EGL,
DT_NONE,
} DisplayType;
@@ -2127,6 +2128,15 @@ static DisplayType select_display(const char *p)
error_report("VNC requires a display argument vnc=<display>");
exit(1);
}
+ } else if (strstart(p, "egl-headless", &opts)) {
+#ifdef CONFIG_OPENGL
+ request_opengl = 1;
+ display_opengl = 1;
+ display = DT_EGL;
+#else
+ fprintf(stderr, "egl support is disabled\n");
+ exit(1);
+#endif
} else if (strstart(p, "curses", &opts)) {
#ifdef CONFIG_CURSES
display = DT_CURSES;
@@ -4658,6 +4668,12 @@ int main(int argc, char **argv, char **envp)
qemu_spice_display_init();
}
+#ifdef CONFIG_OPENGL
+ if (display_type == DT_EGL) {
+ egl_headless_init();
+ }
+#endif
+
if (foreach_device_config(DEV_GDB, gdbserver_start) < 0) {
exit(1);
}