diff options
author | Stefan Hajnoczi <stefanha@redhat.com> | 2017-05-15 14:26:02 +0100 |
---|---|---|
committer | Stefan Hajnoczi <stefanha@redhat.com> | 2017-05-15 14:26:47 +0100 |
commit | 384d9d554aa4de0aa81a5b0be074d8c02f0941d4 (patch) | |
tree | 8b3402c12d71ad53e50638d64b6482752f7597f1 | |
parent | ba9915e1f87fec742775d64859e881e4ab611429 (diff) | |
parent | 7c9209e7bfb8c09ab5a4cadaa84928d146874a05 (diff) | |
download | qemu-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.c | 16 | ||||
-rw-r--r-- | hw/display/virtio-gpu.c | 18 | ||||
-rw-r--r-- | hw/input/virtio-input-hid.c | 6 | ||||
-rw-r--r-- | include/hw/virtio/virtio-gpu.h | 1 | ||||
-rw-r--r-- | include/qemu/bitops.h | 10 | ||||
-rw-r--r-- | include/ui/console.h | 3 | ||||
-rw-r--r-- | include/ui/egl-helpers.h | 3 | ||||
-rw-r--r-- | include/ui/input.h | 11 | ||||
-rw-r--r-- | ui/Makefile.objs | 1 | ||||
-rw-r--r-- | ui/cocoa.m | 4 | ||||
-rw-r--r-- | ui/egl-context.c | 7 | ||||
-rw-r--r-- | ui/egl-headless.c | 158 | ||||
-rw-r--r-- | ui/egl-helpers.c | 88 | ||||
-rw-r--r-- | ui/gtk-egl.c | 2 | ||||
-rw-r--r-- | ui/gtk.c | 4 | ||||
-rw-r--r-- | ui/input-linux.c | 25 | ||||
-rw-r--r-- | ui/input.c | 31 | ||||
-rw-r--r-- | ui/sdl.c | 4 | ||||
-rw-r--r-- | ui/sdl2.c | 4 | ||||
-rw-r--r-- | ui/spice-input.c | 4 | ||||
-rw-r--r-- | ui/vnc-enc-zrle.c | 1 | ||||
-rw-r--r-- | ui/vnc.c | 10 | ||||
-rw-r--r-- | vl.c | 16 |
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 @@ -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; } @@ -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; } } @@ -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); @@ -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; @@ -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; } } } @@ -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; @@ -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); } |