mirror of
https://github.com/qemu/qemu.git
synced 2024-11-24 11:23:43 +08:00
ui: add egl-headless
ui: some vnc cleanups ui: absolute events for input-linux -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJZFaFvAAoJEEy22O7T6HE4TqgP/1bwf3/W6Xmg51A93URWK4uq RWGc9nCtIPh+CieqUByHGwDdV88p/6UBuLsXosHG3DM4olRgynAUOjTMBCe9Mq8Q nF2LSPW273Ir/H5bzrDP+3m6roxoMQQbSeXRuA5vQ8u4HpD+Y17T7NOeiwCLFg49 96zSKlucIWHFkGHO4n6fwWR+sIVhsPXwOykFO7EScGav5Ir9SuFJDUx+JeBQ7wot eOKiYEKaJKKnjFHFUYQnyUq+6cZBbuR9B3FRHaCNTxGuWjCXxPO8O1Pz4B2oIZH9 +pcvg+2f12Zw+dm0pMZHO5sH5hkIY7xzRMkFH0ifpscmGNuJT6oJ9xA4x+sJkAiX FrcunzAH939LtcgNloZq07PXhA8O+LqHiTKIPr1ZXomnW3jSmfuNvW1TwADJsL2E 1Pnateibdiz7Xyb4b7hcvgYvjXA3iKbMgfpvu4n7x2P5orHaylmadXFfBjiOJ+u+ z5n1ip3v417javuIAKwYepvHYjvkbcMPtUrkKwja6F+C3jvTH6wc+wMRrKPQxnOJ ZTPrlcEJOqSCYdzxI/fqg8B/HSDr1bcMX+odrCeJWC2O8deAld1aVXaFXz+JW483 zi2vIBh+kHh6VHDtJynv7Sv7mUCY7jWEiBY6AidnMLR6zomKtwrn7wWqxBbCvI5g IVWjoRqul6sTNl3ywMhc =FimK -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
384d9d554a
@ -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;
|
||||
|
@ -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 = {
|
||||
|
@ -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 */ },
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -527,4 +527,7 @@ static inline void early_gtk_display_init(int opengl)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* egl-headless.c */
|
||||
void egl_headless_init(void);
|
||||
|
||||
#endif
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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]);
|
||||
|
@ -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,
|
||||
|
158
ui/egl-headless.c
Normal file
158
ui/egl-headless.c
Normal file
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
4
ui/gtk.c
4
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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
31
ui/input.c
31
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);
|
||||
|
4
ui/sdl.c
4
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;
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
10
ui/vnc.c
10
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;
|
||||
|
16
vl.c
16
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user