QXL message flow:
以上绿色线表示为一个图形绘制流程,当GuestOS上的一个user应用需要产生一个渲染操作的时候,
- 由Guest APP发送请求给Guest的图形引擎(GDI/X)
- 图形引擎将命令传送给qxl驱动
- qxl驱动将命令翻译为qxl命令推送到qemu中qxl设备的消息队列里面
- libspice从队列里面取数据,将其加入到display Tree中
- display Tree包含了命令的集合,执行这些命令会产生显示内容。这棵树也可以优化掉那些会被覆盖掉的命令。这个命令树还用来检测video数据流。
- 当一条命令从队列中取出发给客户端是,发送的命令被转换为Spice协议消息,同时这个命令从发送队列和树上移除。
- 当一个命令不再使用时,libspice将其放入驱动release ring,qxl驱动释放掉命令资源。client收到图形命令后用其来更新显示。
QXL–>VDI
Spice中的VDI是一个接口规范,此类接口设计的主要目标是在尽量不改变原有代码的情况下,通过动态库的方式来为原有软件提供全新的功能组件。qemu也是通过VDI借口与Spice交互的
VDI接口规范本身非常简单,它仅为开发人员提供一种标准的开发方式,具体的VDI接口功能则由程序员自己负责。具体的约束总结如下:
- 必须包含一个固定的BaseInterface结构体成员。
- Back-end与Front-end的交互关系初始化工作由Back-end负责发起。
- Back-end负责实现与Back-end内部强相关且Front-end感兴趣的功能接口。
- Front-end负责实现与Front-end内部强相关且Back-end感兴趣的功能接口。
QXLInterface是最主要也是最复杂的一个VDI,并且与其他VDI不同的是,Front-end有一个单独的网络处理模型, QXLInterface在Front-end有自己单独的处理线程。Back-end端需要实现Qxl device,同时需要Guest OS的Driver配合工作。另外,Qemu需要Spice为其提供相关的接口来完成一些交互工作。
QXL图形子系统
Spice server通过通道(channel)与client通信,每个通道类型专用于特定类型的数据。每个通道使用一个特定的tcp socket(可以是ssl或非安全的)。
主通道和输入通道受handler函数(在reds.c中实现)控制,显示和光标通道在red worker线程(每个display一个线程)里面处理,音频回放和录音通道有自己的handler(snd_worker.c)。libspice和VDI主机程序(比如qemu)通过为每个功能(qxl,agent,keyboard,mouse等)定义的接口来通信。
与其它spice server中的子系统不同,图形子系统是与spice server并行的一个专门线程。这种架构可以使qemu流程与处理和渲染图形命令独立开来,因为后者会占用大量cpu资源。Red server在每个新的qxl接口中初始化一个dispatcher,dispatcher创建一个red worker。red worker处理的命令来自三处:1) 同步的qxl设备命令;2)red server命令;3)异步qxl设备命令。其中1)和2)由red dispatcher通过socket传送,3)由red worker从qxl设备ring中通过接口取出。
Red Worker(red_worker.c)
spice server为每个qxl设备实例运行一个red worker线程。
red worker的作用主要有:
* 处理qxl设备命令;
* 处理从dispatcher收到的消息;
* channel pipe和pipe item;
* 显示和光标通道;
* 图形压缩(使用quic,lz,glz);
* 视频流---识别、编码、创建流;
* 缓存---client共享的pixman缓存、光标、调色板缓存
* Cairo和OpenGL渲染----canvas,surface等
Red Dispatcher(red_dispatcher.c)
* 每个qxl实例一个dispatcher
* 初始化red worker,创建red worker线程
* 使用socketpair通道调度worker
* qxl设备使用QxlWorker接口,dispatcher实现并attach这些接口,将设备调用翻译成在worker管道中传递的消息。
QXL指令
qxl指令分为异步和同步。
QXL指令代码流程
Spice源码流程