Compare commits

..

7 Commits

Author SHA1 Message Date
Gerd Hoffmann
c5ce833344 vnc: add configurable keyboard delay
Limits the rate kbd events from the vnc server are forwarded to the
guest, so input devices which are typically low-bandwidth can keep
up even on bulky input.

v2: update documentation too.
v3: spell fixes.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Tested-by: Yang Hongyang <hongyang.yang@easystack.cn>
Message-id: 1464762150-25817-1-git-send-email-kraxel@redhat.com
2016-06-03 08:23:26 +02:00
Gerd Hoffmann
8efa5f29f8 sdl2: skip init without outputs
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Tested-by: Cole Robinson <crobinso@redhat.com>
Message-id: 1464790116-32405-1-git-send-email-kraxel@redhat.com
2016-06-03 08:23:26 +02:00
Alexander Graf
0c426e4534 vnc: Add support for color map
Our current VNC code does not handle color maps (aka non-true-color) at all
and aborts if a client requests them. There are 2 major issues with this:

 1) A VNC viewer on an 8-bit X11 system may request color maps
 2) RealVNC _always_ starts requesting color maps, then moves on to full color

In order to support these 2 use cases, let's just create a fake color map
that covers exactly our normal true color 8 bit color space. That way we don't
lose anything over a client that wants true color.

Reported-by: Sascha Wehnert <swehnert@suse.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Pavel Butsykin <pbutsykin@virtuozzo.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
Message-id: 1464099559-20789-1-git-send-email-den@openvz.org

Actually this is a very old patch originally submitted in 2013 by
Alexander. The situation is still the same with RealVNC, it does not
connect by default to QEMU VNC. The problem is that this client is
really popular. This is better to be kludged.

Signed-off-by: Pavel Butsykin <pbutsykin@virtuozzo.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
CC: Gerd Hoffmann <kraxel@redhat.com>
CC: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2016-06-03 08:23:26 +02:00
Pavel Dovgalyuk
435deffefb SDL2: add bgrx pixel format
This patch adds support of b8g8r8x8 pixel format for SDL2.

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-id: 20160517072848.4540.34695.stgit@PASHA-ISP
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2016-06-03 08:23:26 +02:00
Gerd Hoffmann
41cc5239f3 gtk: fix unchecked vc dereference
Spotted by Coverity.

Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 1463737748-1062-1-git-send-email-kraxel@redhat.com
2016-06-03 08:23:26 +02:00
Cole Robinson
daafc661cc ui: spice: Exit if gl=on EGL init fails
The user explicitly requested spice GL, so if we know it isn't
going to work we should exit

Signed-off-by: Cole Robinson <crobinso@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-id: e3789e35b16f9e3cc6f2652f91c52d88ba6d6936.1463588606.git.crobinso@redhat.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2016-06-03 08:23:26 +02:00
Cole Robinson
38a55bddcc ui: egl: Replace fprintf with error_report
Signed-off-by: Cole Robinson <crobinso@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-id: c880920f6e40a506394d89dbbe1f67c63d359c17.1463588606.git.crobinso@redhat.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2016-06-03 08:23:26 +02:00
13 changed files with 123 additions and 272 deletions

View File

@@ -284,7 +284,7 @@ static void virgl_resource_attach_backing(VirtIOGPU *g,
VIRTIO_GPU_FILL_CMD(att_rb);
trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id);
ret = virtio_gpu_create_mapping_iov(&att_rb, cmd, NULL, &res_iovs);
ret = virtio_gpu_create_mapping_iov(&att_rb, cmd, &res_iovs);
if (ret != 0) {
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
return;

View File

@@ -22,8 +22,6 @@
#include "qemu/log.h"
#include "qapi/error.h"
#define VIRTIO_GPU_VM_VERSION 1
static struct virtio_gpu_simple_resource*
virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
@@ -96,7 +94,7 @@ static void update_cursor_data_virgl(VirtIOGPU *g,
static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
{
struct virtio_gpu_scanout *s;
bool move = cursor->hdr.type == VIRTIO_GPU_CMD_MOVE_CURSOR;
bool move = cursor->hdr.type != VIRTIO_GPU_CMD_MOVE_CURSOR;
if (cursor->pos.scanout_id >= g->conf.max_outputs) {
return;
@@ -109,7 +107,7 @@ static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
move ? "move" : "update",
cursor->resource_id);
if (!move) {
if (move) {
if (!s->current_cursor) {
s->current_cursor = cursor_alloc(64, 64);
}
@@ -122,11 +120,6 @@ static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
g, s, cursor->resource_id);
}
dpy_cursor_define(s->con, s->current_cursor);
s->cursor = *cursor;
} else {
s->cursor.pos.x = cursor->pos.x;
s->cursor.pos.y = cursor->pos.y;
}
dpy_mouse_set(s->con, cursor->pos.x, cursor->pos.y,
cursor->resource_id ? 1 : 0);
@@ -502,11 +495,6 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g,
pixman_region_fini(&flush_region);
}
static void virtio_unref_resource(pixman_image_t *image, void *data)
{
pixman_image_unref(data);
}
static void virtio_gpu_set_scanout(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
@@ -583,15 +571,8 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
!= ((uint8_t *)pixman_image_get_data(res->image) + offset) ||
scanout->width != ss.r.width ||
scanout->height != ss.r.height) {
pixman_image_t *rect;
void *ptr = (uint8_t *)pixman_image_get_data(res->image) + offset;
rect = pixman_image_create_bits(format, ss.r.width, ss.r.height, ptr,
pixman_image_get_stride(res->image));
pixman_image_ref(res->image);
pixman_image_set_destroy_function(rect, virtio_unref_resource,
res->image);
/* realloc the surface ptr */
scanout->ds = qemu_create_displaysurface_pixman(rect);
scanout->ds = qemu_create_displaysurface_pixman(res->image);
if (!scanout->ds) {
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
return;
@@ -609,7 +590,7 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab,
struct virtio_gpu_ctrl_command *cmd,
uint64_t **addr, struct iovec **iov)
struct iovec **iov)
{
struct virtio_gpu_mem_entry *ents;
size_t esize, s;
@@ -635,16 +616,10 @@ int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab,
}
*iov = g_malloc0(sizeof(struct iovec) * ab->nr_entries);
if (addr) {
*addr = g_malloc0(sizeof(uint64_t) * ab->nr_entries);
}
for (i = 0; i < ab->nr_entries; i++) {
hwaddr len = ents[i].length;
(*iov)[i].iov_len = ents[i].length;
(*iov)[i].iov_base = cpu_physical_memory_map(ents[i].addr, &len, 1);
if (addr) {
(*addr)[i] = ents[i].addr;
}
if (!(*iov)[i].iov_base || len != ents[i].length) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for"
" resource %d element %d\n",
@@ -652,10 +627,6 @@ int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab,
virtio_gpu_cleanup_mapping_iov(*iov, i);
g_free(ents);
*iov = NULL;
if (addr) {
g_free(*addr);
*addr = NULL;
}
return -1;
}
}
@@ -679,8 +650,6 @@ static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *res)
virtio_gpu_cleanup_mapping_iov(res->iov, res->iov_cnt);
res->iov = NULL;
res->iov_cnt = 0;
g_free(res->addrs);
res->addrs = NULL;
}
static void
@@ -702,7 +671,7 @@ virtio_gpu_resource_attach_backing(VirtIOGPU *g,
return;
}
ret = virtio_gpu_create_mapping_iov(&ab, cmd, &res->addrs, &res->iov);
ret = virtio_gpu_create_mapping_iov(&ab, cmd, &res->iov);
if (ret != 0) {
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
return;
@@ -948,163 +917,11 @@ const GraphicHwOps virtio_gpu_ops = {
.gl_block = virtio_gpu_gl_block,
};
static const VMStateDescription vmstate_virtio_gpu_scanout = {
.name = "virtio-gpu-one-scanout",
.version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(resource_id, struct virtio_gpu_scanout),
VMSTATE_UINT32(width, struct virtio_gpu_scanout),
VMSTATE_UINT32(height, struct virtio_gpu_scanout),
VMSTATE_INT32(x, struct virtio_gpu_scanout),
VMSTATE_INT32(y, struct virtio_gpu_scanout),
VMSTATE_UINT32(cursor.resource_id, struct virtio_gpu_scanout),
VMSTATE_UINT32(cursor.hot_x, struct virtio_gpu_scanout),
VMSTATE_UINT32(cursor.hot_y, struct virtio_gpu_scanout),
VMSTATE_UINT32(cursor.pos.x, struct virtio_gpu_scanout),
VMSTATE_UINT32(cursor.pos.y, struct virtio_gpu_scanout),
VMSTATE_END_OF_LIST()
},
};
static const VMStateDescription vmstate_virtio_gpu_scanouts = {
.name = "virtio-gpu-scanouts",
.version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_INT32(enable, struct VirtIOGPU),
VMSTATE_UINT32_EQUAL(conf.max_outputs, struct VirtIOGPU),
VMSTATE_STRUCT_VARRAY_UINT32(scanout, struct VirtIOGPU,
conf.max_outputs, 1,
vmstate_virtio_gpu_scanout,
struct virtio_gpu_scanout),
VMSTATE_END_OF_LIST()
},
};
static const VMStateDescription vmstate_virtio_gpu_unmigratable = {
.name = "virtio-gpu-with-virgl",
.name = "virtio-gpu",
.unmigratable = 1,
};
static void virtio_gpu_save(QEMUFile *f, void *opaque)
{
VirtIOGPU *g = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(g);
struct virtio_gpu_simple_resource *res;
int i;
virtio_save(vdev, f);
/* in 2d mode we should never find unprocessed commands here */
assert(QTAILQ_EMPTY(&g->cmdq));
QTAILQ_FOREACH(res, &g->reslist, next) {
qemu_put_be32(f, res->resource_id);
qemu_put_be32(f, res->width);
qemu_put_be32(f, res->height);
qemu_put_be32(f, res->format);
qemu_put_be32(f, res->iov_cnt);
for (i = 0; i < res->iov_cnt; i++) {
qemu_put_be64(f, res->addrs[i]);
qemu_put_be32(f, res->iov[i].iov_len);
}
qemu_put_buffer(f, (void *)pixman_image_get_data(res->image),
pixman_image_get_stride(res->image) * res->height);
}
qemu_put_be32(f, 0); /* end of list */
vmstate_save_state(f, &vmstate_virtio_gpu_scanouts, g, NULL);
}
static int virtio_gpu_load(QEMUFile *f, void *opaque, int version_id)
{
VirtIOGPU *g = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(g);
struct virtio_gpu_simple_resource *res;
struct virtio_gpu_scanout *scanout;
uint32_t resource_id, pformat;
int i, ret;
if (version_id != VIRTIO_GPU_VM_VERSION) {
return -EINVAL;
}
ret = virtio_load(vdev, f, version_id);
if (ret) {
return ret;
}
resource_id = qemu_get_be32(f);
while (resource_id != 0) {
res = g_new0(struct virtio_gpu_simple_resource, 1);
res->resource_id = resource_id;
res->width = qemu_get_be32(f);
res->height = qemu_get_be32(f);
res->format = qemu_get_be32(f);
res->iov_cnt = qemu_get_be32(f);
/* allocate */
pformat = get_pixman_format(res->format);
if (!pformat) {
return -EINVAL;
}
res->image = pixman_image_create_bits(pformat,
res->width, res->height,
NULL, 0);
if (!res->image) {
return -EINVAL;
}
res->addrs = g_new(uint64_t, res->iov_cnt);
res->iov = g_new(struct iovec, res->iov_cnt);
/* read data */
for (i = 0; i < res->iov_cnt; i++) {
res->addrs[i] = qemu_get_be64(f);
res->iov[i].iov_len = qemu_get_be32(f);
}
qemu_get_buffer(f, (void *)pixman_image_get_data(res->image),
pixman_image_get_stride(res->image) * res->height);
/* restore mapping */
for (i = 0; i < res->iov_cnt; i++) {
hwaddr len = res->iov[i].iov_len;
res->iov[i].iov_base =
cpu_physical_memory_map(res->addrs[i], &len, 1);
if (!res->iov[i].iov_base || len != res->iov[i].iov_len) {
return -EINVAL;
}
}
QTAILQ_INSERT_HEAD(&g->reslist, res, next);
resource_id = qemu_get_be32(f);
}
/* load & apply scanout state */
vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1);
for (i = 0; i < g->conf.max_outputs; i++) {
scanout = &g->scanout[i];
if (!scanout->resource_id) {
continue;
}
res = virtio_gpu_find_resource(g, scanout->resource_id);
if (!res) {
return -EINVAL;
}
scanout->ds = qemu_create_displaysurface_pixman(res->image);
if (!scanout->ds) {
return -EINVAL;
}
dpy_gfx_replace_surface(scanout->con, scanout->ds);
dpy_gfx_update(scanout->con, 0, 0, scanout->width, scanout->height);
update_cursor(g, &scanout->cursor);
res->scanout_bitmask |= (1 << i);
}
return 0;
}
static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
@@ -1162,12 +979,7 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
}
}
if (virtio_gpu_virgl_enabled(g->conf)) {
vmstate_register(qdev, -1, &vmstate_virtio_gpu_unmigratable, g);
} else {
register_savevm(qdev, "virtio-gpu", -1, VIRTIO_GPU_VM_VERSION,
virtio_gpu_save, virtio_gpu_load, g);
}
vmstate_register(qdev, -1, &vmstate_virtio_gpu_unmigratable, g);
}
static void virtio_gpu_instance_init(Object *obj)

View File

@@ -84,17 +84,6 @@ static const GraphicHwOps virtio_vga_ops = {
.gl_block = virtio_vga_gl_block,
};
static const VMStateDescription vmstate_virtio_vga = {
.name = "virtio-vga",
.version_id = 2,
.minimum_version_id = 2,
.fields = (VMStateField[]) {
/* no pci stuff here, saving the virtio device will handle that */
VMSTATE_STRUCT(vga, VirtIOVGA, 0, vmstate_vga_common, VGACommonState),
VMSTATE_END_OF_LIST()
}
};
/* VGA device wrapper around PCI device around virtio GPU */
static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
{
@@ -179,7 +168,6 @@ static void virtio_vga_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
dc->props = virtio_vga_properties;
dc->reset = virtio_vga_reset;
dc->vmsd = &vmstate_virtio_vga;
dc->hotpluggable = false;
k->realize = virtio_vga_realize;

View File

@@ -66,11 +66,17 @@ struct vmsvga_state_s {
uint8_t *fifo_ptr;
unsigned int fifo_size;
uint32_t *fifo;
uint32_t fifo_min;
uint32_t fifo_max;
uint32_t fifo_next;
uint32_t fifo_stop;
union {
uint32_t *fifo;
struct QEMU_PACKED {
uint32_t min;
uint32_t max;
uint32_t next_cmd;
uint32_t stop;
/* Add registers here when adding capabilities. */
uint32_t fifo[0];
} *cmd;
};
#define REDRAW_FIFO_LEN 512
struct vmsvga_rect_s {
@@ -192,7 +198,7 @@ enum {
*/
SVGA_FIFO_MIN = 0,
SVGA_FIFO_MAX, /* The distance from MIN to MAX must be at least 10K */
SVGA_FIFO_NEXT,
SVGA_FIFO_NEXT_CMD,
SVGA_FIFO_STOP,
/*
@@ -540,6 +546,8 @@ static inline void vmsvga_cursor_define(struct vmsvga_state_s *s,
}
#endif
#define CMD(f) le32_to_cpu(s->cmd->f)
static inline int vmsvga_fifo_length(struct vmsvga_state_s *s)
{
int num;
@@ -547,45 +555,21 @@ static inline int vmsvga_fifo_length(struct vmsvga_state_s *s)
if (!s->config || !s->enable) {
return 0;
}
s->fifo_min = le32_to_cpu(s->fifo[SVGA_FIFO_MIN]);
s->fifo_max = le32_to_cpu(s->fifo[SVGA_FIFO_MAX]);
s->fifo_next = le32_to_cpu(s->fifo[SVGA_FIFO_NEXT]);
s->fifo_stop = le32_to_cpu(s->fifo[SVGA_FIFO_STOP]);
/* Check range and alignment. */
if ((s->fifo_min | s->fifo_max | s->fifo_next | s->fifo_stop) & 3) {
return 0;
}
if (s->fifo_min < sizeof(uint32_t) * 4) {
return 0;
}
if (s->fifo_max > SVGA_FIFO_SIZE ||
s->fifo_min >= SVGA_FIFO_SIZE ||
s->fifo_stop >= SVGA_FIFO_SIZE ||
s->fifo_next >= SVGA_FIFO_SIZE) {
return 0;
}
if (s->fifo_max < s->fifo_min + 10 * 1024) {
return 0;
}
num = s->fifo_next - s->fifo_stop;
num = CMD(next_cmd) - CMD(stop);
if (num < 0) {
num += s->fifo_max - s->fifo_min;
num += CMD(max) - CMD(min);
}
return num >> 2;
}
static inline uint32_t vmsvga_fifo_read_raw(struct vmsvga_state_s *s)
{
uint32_t cmd = s->fifo[s->fifo_stop >> 2];
uint32_t cmd = s->fifo[CMD(stop) >> 2];
s->fifo_stop += 4;
if (s->fifo_stop >= s->fifo_max) {
s->fifo_stop = s->fifo_min;
s->cmd->stop = cpu_to_le32(CMD(stop) + 4);
if (CMD(stop) >= CMD(max)) {
s->cmd->stop = s->cmd->min;
}
s->fifo[SVGA_FIFO_STOP] = cpu_to_le32(s->fifo_stop);
return cmd;
}
@@ -597,15 +581,15 @@ static inline uint32_t vmsvga_fifo_read(struct vmsvga_state_s *s)
static void vmsvga_fifo_run(struct vmsvga_state_s *s)
{
uint32_t cmd, colour;
int args, len, maxloop = 1024;
int args, len;
int x, y, dx, dy, width, height;
struct vmsvga_cursor_definition_s cursor;
uint32_t cmd_start;
len = vmsvga_fifo_length(s);
while (len > 0 && --maxloop > 0) {
while (len > 0) {
/* May need to go back to the start of the command if incomplete */
cmd_start = s->fifo_stop;
cmd_start = s->cmd->stop;
switch (cmd = vmsvga_fifo_read(s)) {
case SVGA_CMD_UPDATE:
@@ -764,8 +748,7 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
break;
rewind:
s->fifo_stop = cmd_start;
s->fifo[SVGA_FIFO_STOP] = cpu_to_le32(s->fifo_stop);
s->cmd->stop = cmd_start;
break;
}
}
@@ -1022,6 +1005,19 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
case SVGA_REG_CONFIG_DONE:
if (value) {
s->fifo = (uint32_t *) s->fifo_ptr;
/* Check range and alignment. */
if ((CMD(min) | CMD(max) | CMD(next_cmd) | CMD(stop)) & 3) {
break;
}
if (CMD(min) < (uint8_t *) s->cmd->fifo - (uint8_t *) s->fifo) {
break;
}
if (CMD(max) > SVGA_FIFO_SIZE) {
break;
}
if (CMD(max) < CMD(min) + 10 * 1024) {
break;
}
vga_dirty_log_stop(&s->vga);
}
s->config = !!value;

View File

@@ -32,7 +32,6 @@ struct virtio_gpu_simple_resource {
uint32_t width;
uint32_t height;
uint32_t format;
uint64_t *addrs;
struct iovec *iov;
unsigned int iov_cnt;
uint32_t scanout_bitmask;
@@ -47,7 +46,6 @@ struct virtio_gpu_scanout {
int x, y;
int invalidate;
uint32_t resource_id;
struct virtio_gpu_update_cursor cursor;
QEMUCursor *current_cursor;
};
@@ -152,7 +150,7 @@ void virtio_gpu_get_display_info(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd);
int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab,
struct virtio_gpu_ctrl_command *cmd,
uint64_t **addr, struct iovec **iov);
struct iovec **iov);
void virtio_gpu_cleanup_mapping_iov(struct iovec *iov, uint32_t count);
void virtio_gpu_process_cmdq(VirtIOGPU *g);

View File

@@ -1410,6 +1410,14 @@ everybody else. 'ignore' completely ignores the shared flag and
allows everybody connect unconditionally. Doesn't conform to the rfb
spec but is traditional QEMU behavior.
@item key-delay-ms
Set keyboard delay, for key down and key up events, in milliseconds.
Default is 1. Keyboards are low-bandwidth devices, so this slowdown
can help the device and guest to keep up and not lose events in case
events are arriving in bulk. Possible causes for the latter are flaky
network connections, or scripts for automated testing.
@end table
ETEXI

View File

@@ -2,6 +2,7 @@
#include <glob.h>
#include <dirent.h>
#include "qemu/error-report.h"
#include "ui/egl-helpers.h"
EGLDisplay *qemu_egl_display;
@@ -74,13 +75,13 @@ int egl_rendernode_init(void)
qemu_egl_rn_fd = qemu_egl_rendernode_open();
if (qemu_egl_rn_fd == -1) {
fprintf(stderr, "egl: no drm render node available\n");
error_report("egl: no drm render node available");
goto err;
}
qemu_egl_rn_gbm_dev = gbm_create_device(qemu_egl_rn_fd);
if (!qemu_egl_rn_gbm_dev) {
fprintf(stderr, "egl: gbm_create_device failed\n");
error_report("egl: gbm_create_device failed");
goto err;
}
@@ -88,18 +89,18 @@ int egl_rendernode_init(void)
if (!epoxy_has_egl_extension(qemu_egl_display,
"EGL_KHR_surfaceless_context")) {
fprintf(stderr, "egl: EGL_KHR_surfaceless_context not supported\n");
error_report("egl: EGL_KHR_surfaceless_context not supported");
goto err;
}
if (!epoxy_has_egl_extension(qemu_egl_display,
"EGL_MESA_image_dma_buf_export")) {
fprintf(stderr, "egl: EGL_MESA_image_dma_buf_export not supported\n");
error_report("egl: EGL_MESA_image_dma_buf_export not supported");
goto err;
}
qemu_egl_rn_ctx = qemu_egl_init_ctx();
if (!qemu_egl_rn_ctx) {
fprintf(stderr, "egl: egl_init_ctx failed\n");
error_report("egl: egl_init_ctx failed");
goto err;
}
@@ -156,13 +157,13 @@ EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, Window win)
qemu_egl_config,
(EGLNativeWindowType)win, NULL);
if (esurface == EGL_NO_SURFACE) {
fprintf(stderr, "egl: eglCreateWindowSurface failed\n");
error_report("egl: eglCreateWindowSurface failed");
return NULL;
}
b = eglMakeCurrent(qemu_egl_display, esurface, esurface, ectx);
if (b == EGL_FALSE) {
fprintf(stderr, "egl: eglMakeCurrent failed\n");
error_report("egl: eglMakeCurrent failed");
return NULL;
}
@@ -204,21 +205,21 @@ int qemu_egl_init_dpy(EGLNativeDisplayType dpy, bool gles, bool debug)
egl_dbg("eglGetDisplay (dpy %p) ...\n", dpy);
qemu_egl_display = eglGetDisplay(dpy);
if (qemu_egl_display == EGL_NO_DISPLAY) {
fprintf(stderr, "egl: eglGetDisplay failed\n");
error_report("egl: eglGetDisplay failed");
return -1;
}
egl_dbg("eglInitialize ...\n");
b = eglInitialize(qemu_egl_display, &major, &minor);
if (b == EGL_FALSE) {
fprintf(stderr, "egl: eglInitialize failed\n");
error_report("egl: eglInitialize failed");
return -1;
}
egl_dbg("eglBindAPI ...\n");
b = eglBindAPI(gles ? EGL_OPENGL_ES_API : EGL_OPENGL_API);
if (b == EGL_FALSE) {
fprintf(stderr, "egl: eglBindAPI failed\n");
error_report("egl: eglBindAPI failed");
return -1;
}
@@ -227,7 +228,7 @@ int qemu_egl_init_dpy(EGLNativeDisplayType dpy, bool gles, bool debug)
gles ? conf_att_gles : conf_att_gl,
&qemu_egl_config, 1, &n);
if (b == EGL_FALSE || n != 1) {
fprintf(stderr, "egl: eglChooseConfig failed\n");
error_report("egl: eglChooseConfig failed");
return -1;
}
@@ -252,13 +253,13 @@ EGLContext qemu_egl_init_ctx(void)
ectx = eglCreateContext(qemu_egl_display, qemu_egl_config, EGL_NO_CONTEXT,
egl_gles ? ctx_att_gles : ctx_att_gl);
if (ectx == EGL_NO_CONTEXT) {
fprintf(stderr, "egl: eglCreateContext failed\n");
error_report("egl: eglCreateContext failed");
return NULL;
}
b = eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, ectx);
if (b == EGL_FALSE) {
fprintf(stderr, "egl: eglMakeCurrent failed\n");
error_report("egl: eglMakeCurrent failed");
return NULL;
}

View File

@@ -1477,13 +1477,14 @@ static void gd_grab_pointer(VirtualConsole *vc, const char *reason)
static void gd_ungrab_pointer(GtkDisplayState *s)
{
VirtualConsole *vc = s->ptr_owner;
GdkDisplay *display = gtk_widget_get_display(vc->gfx.drawing_area);
GdkDisplay *display;
if (vc == NULL) {
return;
}
s->ptr_owner = NULL;
display = gtk_widget_get_display(vc->gfx.drawing_area);
#if GTK_CHECK_VERSION(3, 20, 0)
gd_grab_update(vc, vc->s->kbd_owner == vc, false);
gdk_device_warp(gd_get_pointer(display),

View File

@@ -116,6 +116,9 @@ void sdl2_2d_switch(DisplayChangeListener *dcl,
case PIXMAN_r8g8b8x8:
format = SDL_PIXELFORMAT_RGBA8888;
break;
case PIXMAN_b8g8r8x8:
format = SDL_PIXELFORMAT_BGRX8888;
break;
default:
g_assert_not_reached();
}

View File

@@ -794,6 +794,9 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
}
}
sdl2_num_outputs = i;
if (sdl2_num_outputs == 0) {
return;
}
sdl2_console = g_new0(struct sdl2_console, sdl2_num_outputs);
for (i = 0; i < sdl2_num_outputs; i++) {
QemuConsole *con = qemu_console_lookup_by_index(i);

View File

@@ -833,9 +833,11 @@ void qemu_spice_init(void)
"incompatible with -spice port/tls-port");
exit(1);
}
if (egl_rendernode_init() == 0) {
display_opengl = 1;
if (egl_rendernode_init() != 0) {
error_report("Failed to initialize EGL render node for SPICE GL");
exit(1);
}
display_opengl = 1;
}
#endif
}

View File

@@ -1629,6 +1629,7 @@ static void reset_keys(VncState *vs)
for(i = 0; i < 256; i++) {
if (vs->modifiers_state[i]) {
qemu_input_event_send_key_number(vs->vd->dcl.con, i, false);
qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
vs->modifiers_state[i] = 0;
}
}
@@ -1638,9 +1639,9 @@ static void press_key(VncState *vs, int keysym)
{
int keycode = keysym2scancode(vs->vd->kbd_layout, keysym) & SCANCODE_KEYMASK;
qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, true);
qemu_input_event_send_key_delay(0);
qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
qemu_input_event_send_key_delay(0);
qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
}
static int current_led_state(VncState *vs)
@@ -1792,6 +1793,7 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
if (qemu_console_is_graphic(NULL)) {
qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, down);
qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
} else {
bool numlock = vs->modifiers_state[0x45];
bool control = (vs->modifiers_state[0x1d] ||
@@ -1913,6 +1915,7 @@ static void vnc_release_modifiers(VncState *vs)
continue;
}
qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
}
}
@@ -2094,6 +2097,24 @@ static void set_pixel_conversion(VncState *vs)
}
}
static void send_color_map(VncState *vs)
{
int i;
vnc_write_u8(vs, VNC_MSG_SERVER_SET_COLOUR_MAP_ENTRIES);
vnc_write_u8(vs, 0); /* padding */
vnc_write_u16(vs, 0); /* first color */
vnc_write_u16(vs, 256); /* # of colors */
for (i = 0; i < 256; i++) {
PixelFormat *pf = &vs->client_pf;
vnc_write_u16(vs, (((i >> pf->rshift) & pf->rmax) << (16 - pf->rbits)));
vnc_write_u16(vs, (((i >> pf->gshift) & pf->gmax) << (16 - pf->gbits)));
vnc_write_u16(vs, (((i >> pf->bshift) & pf->bmax) << (16 - pf->bbits)));
}
}
static void set_pixel_format(VncState *vs,
int bits_per_pixel, int depth,
int big_endian_flag, int true_color_flag,
@@ -2101,8 +2122,15 @@ static void set_pixel_format(VncState *vs,
int red_shift, int green_shift, int blue_shift)
{
if (!true_color_flag) {
vnc_client_error(vs);
return;
/* Expose a reasonable default 256 color map */
bits_per_pixel = 8;
depth = 8;
red_max = 7;
green_max = 7;
blue_max = 3;
red_shift = 0;
green_shift = 3;
blue_shift = 6;
}
switch (bits_per_pixel) {
@@ -2132,6 +2160,10 @@ static void set_pixel_format(VncState *vs,
vs->client_pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
vs->client_be = big_endian_flag;
if (!true_color_flag) {
send_color_map(vs);
}
set_pixel_conversion(vs);
graphic_hw_invalidate(vs->vd->dcl.con);
@@ -3248,6 +3280,9 @@ static QemuOptsList qemu_vnc_opts = {
},{
.name = "lock-key-sync",
.type = QEMU_OPT_BOOL,
},{
.name = "key-delay-ms",
.type = QEMU_OPT_NUMBER,
},{
.name = "sasl",
.type = QEMU_OPT_BOOL,
@@ -3486,6 +3521,7 @@ void vnc_display_open(const char *id, Error **errp)
#endif
int acl = 0;
int lock_key_sync = 1;
int key_delay_ms;
if (!vs) {
error_setg(errp, "VNC display not active");
@@ -3604,6 +3640,7 @@ void vnc_display_open(const char *id, Error **errp)
reverse = qemu_opt_get_bool(opts, "reverse", false);
lock_key_sync = qemu_opt_get_bool(opts, "lock-key-sync", true);
key_delay_ms = qemu_opt_get_number(opts, "key-delay-ms", 1);
sasl = qemu_opt_get_bool(opts, "sasl", false);
#ifndef CONFIG_VNC_SASL
if (sasl) {
@@ -3735,6 +3772,7 @@ void vnc_display_open(const char *id, Error **errp)
}
#endif
vs->lock_key_sync = lock_key_sync;
vs->key_delay_ms = key_delay_ms;
device_id = qemu_opt_get(opts, "display");
if (device_id) {

View File

@@ -155,6 +155,7 @@ struct VncDisplay
DisplayChangeListener dcl;
kbd_layout_t *kbd_layout;
int lock_key_sync;
int key_delay_ms;
QemuMutex mutex;
QEMUCursor *cursor;