云桌面(VDI)spice协议优化的关键技术——显示篇

关于spice协议的背景知识介绍参阅https://spice-space.org/

一. 动态选择编码策略

    X86平台软解码性能足够,非流式数据可以全部使用无损编码。由于LZ4是无损编码中解码最快但流量最大的,故可使用于静态系统图像的显示,实时统计非流式数据达到一定容忍流量(由实时带宽决定)时,变换编码策略为GLZ。GLZ相对于LZ有更快的解码速度,极少量不能使用GLZ编码的图像可以用LZ4。特别的,实时统计流式数据达到一定流量(可知是较大区域的视频播放),变换编码策略为jpeg,由于流式数据一般仍使用jpeg编码(换成H.264会显著增加服务端CPU占用),非流式数据用同样的编码可以在硬解码时避免一起拷贝到内存做合并。为什么不用QUIC?主要由于常见的X86云终端如8300、8350、3865等会对LZ系(包括GLZ、LZ4)解码做CPU指令优化,如果是普通PC可以按照图像情况分别选用QUIC或GLZ。

    ARM平台软解码性能不足,终端需要硬解码。以常见的RK3188终端为例,VPU只支持H.264和JPEG硬解码,非流式数据为了性能需要大部分采用JPEG编码,但为了避免有损解码带来的不清晰和边缘细线残留,可以采取措施:1)区分图像是否有Alpha通道,有则使用GLZ编码;2)只有RGB通道的需要根据JPEG编码的特点对非被4整除长度或宽度的边缘,在向canvas贴图时重绘边缘。

二. 硬解码

    X86终端一般为intel系列CPU,使用libva硬解。非流式数据使用libva硬解有一定难度,因为硬解后的数据不会拷贝回内存而是直接显示,而GTK界面数据是在内存中通过X11显示的,处理交叠关系比较复杂,同时因为cache的原因,需要在显存中做图像裁剪。流式数据使用libva硬解就容易多了,可以使用gstreamer的vaapi插件来支持。

    ARM终端的硬解方案一般由相应的ARM芯片厂商提供,可参阅相关文档。需要注意的是,尽量减少内存拷贝,ARM终端的内存位宽一般较低。

三. 多线程

    原生的协程相比线程能够减少创建的开销和避免无意义的调度,但是并不十分适合ARM平台。协程适合于高并发吞吐的场景,牺牲了线程的公平性,如果存在一个较长时间的计算任务(如图像解码),将影响到IO任务的响应延时,即会影响其它同步进行的数据处理(如音频播放)。而且单线程的协程方案并不能从根本上避免阻塞,如文件操作、内存缺页。所以对于云桌面终端这种并不需要应对高并发的场景,使用多线程更能兼顾各个channel数据处理的公平性,从而在显示复杂动画网页时不会影响音频播放和外设重定向。实际操作上,是将spice的每一个channel作为一个线程,分别接受数据和处理。

四. 解码与渲染并行

    对于非流式数据,存在很多细小的图像,其解码时间小于渲染时间,如果并行会导致待渲染数据淤积而丢失,画面残缺或痕迹不消失。对于流失数据则非常适用,一是流式数据有区域大小限制,过小的不会形成流,一般解码时间大于渲染时间,二是即使发生少量丢失也不影响观看体验(类似视频丢帧)。

五. 优化QXL指令

    所谓QXL CACHE机制,就是先发一张大图作为缓存,后面连续几张图像都是从这张大图中裁剪,所以不必再发图像数据,只需要cache id和裁剪区域。这种机制目的是减少图像数据的多次编解码,解码一次反复利用。但是在ARM平台上由于内存拷贝速度较慢,裁剪的优势并没有体现出来,而且往往一张cache的大图只能使用其中的互不重合的几小部分。所以不如在形成QXL指令时就不作cache,由服务端裁剪后分别发送,对终端处理反而更快。

    对终端处理压力最大的是draw copy指令,对于该指令可做一定程度合并,在较小的时间区间内,同一区域内即将被覆盖的指令就不再发送。 

你可能感兴趣的:(云桌面)