1.1、初始化qemu
void qemu_init(int argc, char **argv, char **envp)
{
...
qemu_init_displays();
...
}
1.2、显示部分初始化
static void qemu_init_displays(void)
{
DisplayState *ds;
/* init local displays */
ds = init_displaystate();
qemu_display_init(ds, &dpy);
/* must be after terminal init, SDL library changes signal handlers */
os_setup_signal_handling();
/* init remote displays */
#ifdef CONFIG_VNC
qemu_opts_foreach(qemu_find_opts("vnc"),
vnc_init_func, NULL, &error_fatal);
#endif
if (using_spice) {
qemu_spice.display_init();
}
}
1.3、spice显示部分初始化
static struct QemuSpiceOps real_spice_ops = {
.init = qemu_spice_init,
.display_init = qemu_spice_display_init,
.migrate_info = qemu_spice_migrate_info,
.set_passwd = qemu_spice_set_passwd,
.set_pw_expire = qemu_spice_set_pw_expire,
.display_add_client = qemu_spice_display_add_client,
.add_interface = qemu_spice_add_interface,
.qmp_query = qmp_query_spice_real,
};
void qemu_spice_display_init(void)
{
QemuOptsList *olist = qemu_find_opts("spice");
QemuOpts *opts = QTAILQ_FIRST(&olist->head);
QemuConsole *spice_con, *con;
const char *str;
int i;
str = qemu_opt_get(opts, "display");
if (str) {
int head = qemu_opt_get_number(opts, "head", 0);
Error *err = NULL;
spice_con = qemu_console_lookup_by_device_name(str, head, &err);
if (err) {
error_report("Failed to lookup display/head");
exit(1);
}
} else {
spice_con = NULL;
}
for (i = 0;; i++) {
con = qemu_console_lookup_by_index(i);
if (!con || !qemu_console_is_graphic(con)) {
break;
}
if (qemu_spice_have_display_interface(con)) {
continue;
}
if (spice_con != NULL && spice_con != con) {
continue;
}
qemu_spice_display_init_one(con);
}
qemu_spice_display_init_done();
}
1.4、初始化一个spice显示
static void qemu_spice_display_init_one(QemuConsole *con)
{
SimpleSpiceDisplay *ssd = g_new0(SimpleSpiceDisplay, 1);
qemu_spice_display_init_common(ssd);
ssd->dcl.ops = &display_listener_ops;
#ifdef HAVE_SPICE_GL
if (spice_opengl) {
ssd->dcl.ops = &display_listener_gl_ops;
ssd->gl_unblock_bh = qemu_bh_new(qemu_spice_gl_unblock_bh, ssd);
ssd->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME, qemu_spice_gl_block_timer, ssd);
ssd->gls = qemu_gl_init_shader();
ssd->have_surface = false;
ssd->have_scanout = false;
}
#endif
ssd->dcl.con = con;
ssd->qxl.base.sif = &dpy_interface.base;
qemu_spice_add_display_interface(&ssd->qxl, con);
#if SPICE_SERVER_VERSION >= 0x000e02 /* release 0.14.2 */
char device_address[256] = "";
if (qemu_spice_fill_device_address(con, device_address, 256)) {
spice_qxl_set_device_info(&ssd->qxl,
device_address,
qemu_console_get_head(con),
1);
}
#endif
qemu_spice_create_host_memslot(ssd);
register_displaychangelistener(&ssd->dcl);
}
1.5、添加显示接口
int qemu_spice_add_display_interface(QXLInstance *qxlin, QemuConsole *con)
{
if (g_slist_find(spice_consoles, con)) {
return -1;
}
qxlin->id = qemu_console_get_index(con);
spice_consoles = g_slist_append(spice_consoles, con);
return qemu_spice_add_interface(&qxlin->base);
}
static int qemu_spice_add_interface(SpiceBaseInstance *sin)
{
if (!spice_server) {
if (QTAILQ_FIRST(&qemu_spice_opts.head) != NULL) {
error_report("Oops: spice configured but not active");
exit(1);
}
/*
* Create a spice server instance.
* It does *not* listen on the network.
* It handles QXL local rendering only.
*
* With a command line like '-vnc :0 -vga qxl' you'll end up here.
*/
spice_server = spice_server_new();
spice_server_set_sasl_appname(spice_server, "qemu");
spice_server_init(spice_server, &core_interface);
qemu_add_vm_change_state_handler(vm_change_state_handler, NULL);
}
return spice_server_add_interface(spice_server, sin);
}