Skip to content

渲染 ​

MyGo 在 GPU 上绘制:在 macOS 上用 Metal,在 Windows 上用 Direct3D 11, 在 GPU 驱动不可用的地方用 Windows 自带的软件渲染器 WARP,在 Linux 上 用 OpenGL(在 GTK 提供的 GtkGLArea 中),在浏览器中用 WebGL 2(使用 Linux 的着色器)。着色器根据到边缘的距离计算圆角矩形、 边框、渐变和阴影,因此它们在任何尺寸和缩放下都保持锐利;文本来自字形 图集(atlas),只上传发生变化的部分。

有 GPU 时,每一帧都在 GPU 上绘制。在 Linux 上,第一个原生 UI 窗口会 加载 OpenGL:Mesa 驱动约占 50 MB,并且常驻,大约相当于一个小型应用 其余部分的大小。在 OpenGL 无法运行于 GPU 的地方,例如虚拟机或 WSL (在 WSL 中 GALLIUM_DRIVER=d3d12 可以让 Mesa 用上 GPU),Linux 会在 CPU 上绘制:在高密度显示器上,用多个核心绘制一整个大窗口约需 1 毫秒; 而典型的变化部分(例如指针下的按钮)不到其十分之一,因为它只重绘那 一部分,合成器也只取那一部分。设置 MYGO_GPU=0 可在所有地方使用 CPU 渲染器,例如用于对比;在 Linux 上设置 MYGO_GPU=1 可即使本该运行在 CPU 上也用 OpenGL 绘制。

设置 MYGO_FRAME_STATS=1 可记录每一耗时超过 8 ms 的帧,或设置 MYGO_FRAME_STATS=4 以毫秒为单位指定其他阈值(all 记录每一帧)。 每行日志告知构建帧(以及用了几轮 pass)、布局、绘制和提交(present) 各花了多久,帧是在 GPU 上还是内存中绘制的(当窗口没有 GPU 渲染器时), 期间进程分配了多少内存、布局了多少段文本,以及垃圾回收器是否运行, 还有 goroutine 帮助标记所花的时间:

mygo: frame 412 took 17.3 ms: build 3.1 (2 passes), layout 1.2, paint 0.8, present 11.5 (drawn on the GPU), other 0.7; meanwhile the process made about 2312 allocations, 171.0 KB, 12 text layouts; GC: 1 cycles ended, 4.1 ms of assists

分配和回收器统计的是整个进程的,包括其他 goroutine 的,统计方式与 runtime/metrics 相同:一次一个 span,因此较小的计数会偏低。变量未 设置时,帧不做任何测量。

MyGo 只在有变化时才绘制帧:输入、Invalidate、After,或运动中的 动画。空闲的窗口什么都不绘制,并在最后一帧之后两秒释放它绘制在内存中 的帧。

在 macOS 上做动画的窗口为显示器保留三帧,比帧轮替所需的两个多一个: 只有两个时,120 Hz 的显示器经常两个都占着,导致帧要等其中一个空出来, 有些帧因此画不出来。第三帧的开销约为窗口每像素 4 字节(sRGB 色域之外 为 8 字节),直到窗口空闲。