编程 Ebitengine 2.10:桌面平台改纯 Go,顺带把无头测试和 shader 预编译做了

2026-09-18 21:02:05

Ebitengine 2.10 发布说明:桌面纯 Go、应用虚拟化与 shader 预编译

  • 项目地址:https://github.com/hajimehoshi/ebiten
  • 发布说明:https://ebitengine.org/en/documents/2.10.html

v2.10.0 发布日期:2026-09-08。这一版的三条主线是桌面平台纯 Go 支持、应用虚拟化(VM)与 shader 预编译,另外在文本渲染、IME 输入和窗口操作上有若干改动。从 Ebitengine 2.10 起要求 Go 1.25 或更高版本。

桌面平台纯 Go 支持(issues #1162, #2284)

macOS 与 Linux/BSD 的实现不再依赖 Cgo。桌面平台的 Ebitengine 应用只用 Go 就能构建,不需要 C 编译器和开发头文件,交叉编译到其他操作系统也更容易。Windows 实现此前已经不需要 Cgo。

OS API 与共享库通过 PureGo 调用。Linux 等平台仍然需要运行库(窗口系统、图形、音频相关的库)存在。移动平台和部分主机构建仍然需要 Cgo。

应用虚拟化(VM,issue #3438)

Ebitengine 应用现在可以作为独立进程的 guest 运行,由 host 控制:

  • host 向 guest 发送输入,并控制游戏何时 update/draw;
  • guest 向 host 发送绘图命令,host 用自己的图形后端执行;
  • host 可以按每个 player 接收独立音频流。

两个主要用途:一是嵌入另一个 Ebitengine 游戏,例如在游戏编辑器里做预览;二是从程序或 AI agent 做自动化测试——向 guest 发送输入、按指定 tick 数推进游戏、捕获渲染与音频输出来验证结果。

不是每个 Ebitengine 应用都能作为 VM guest。应用作者必须显式 opt-in:启用 ebitenginevmguest build tag,或者设置 ebiten.RunGameOptions.VMGuestEndpoint

run-ebitengine-app-headless skill 文件面向 AI agent:加载后 agent 会自动调试应用;测试是无头的,不弹窗口,agent 可以捕获并检查 guest 真实渲染输出的图像,也能发送输入复现 bug、检查音频输出,改代码后重复操作验证修复。

host 侧使用新的实验性 exp/vmhost 包。构建 guest 有两种方式:

  • ebitenginevmguest build tag,运行时用环境变量 EBITENGINE_VM_ENDPOINT 指定 host endpoint。这种方式不需要改源码,但必须重新构建应用;
  • 在程序里设置 ebiten.RunGameOptions.VMGuestEndpoint,不用 build tag。

边界条件:guest 模式仅在桌面平台支持,guest 不使用自己的窗口或 GPU,host 仍需图形环境渲染。该 VM 特性不包含软件渲染器,因此无法在无 GPU 的 CI 环境使用。host 与 guest 必须使用同一 Ebitengine 版本。exp/vmhost 是实验性包,API 未来可能变化。

Shader 预编译(issues #2861, #3157, #3035)

新的实验性 exp/shaderprecomp 包允许应用使用预编译 shader,减少运行时的 shader 编译工作,缩短加载时间。shadercollector 工具从指定包收集 Kage 源(含依赖),用专用指令或 manifest 标记要收集的 shader,并为每个图形后端输出源码。

DirectX 和 Metal 需要另外用各自平台的编译器把输出源码编译成二进制,并在应用初始化时注册。现有的 ebiten.NewShader 调用与绘图代码可以保持不变。

预编译并不消除全部运行时编译:Kage 源仍要转换成中间表示;OpenGL 下转 GLSL 这一步可以提前完成,但 GPU 驱动仍会在运行时编译链接 GLSL。shadercollector 还会输出标识每个 shader 源的 SourceID,把原始 Kage 源与预编译数据关联。即使是同一个 Kage 源,ID 也可能随 Ebitengine 版本变化,因此升级 Ebitengine 时要重新收集并预编译 shader。exp/shaderprecomp 是实验性的,API 可能变化。

Kage 变更

新增:

  • 对整数和定长数组的 for range 支持(#2905, #1897);
  • 按位 &^ 与一元 ^ 运算符(#2753);
  • imageSrc1AtFromSrc0Pos 等函数,名字明确表示取第 0 个源图的坐标;原有 imageSrc1At 行为不变(#2813);
  • imageDstTextureSizeimageSrc0TextureSizeimageSrc3TextureSize(#3476)。

废弃:

  • imageSrc1At()imageSrc3At()imageSrc1AtFromSrc0Pos()imageSrc3AtFromSrc0Pos()
  • imageSrc1UnsafeAt()~imageSrc3UnsafeAt()...FromSrc0Pos()

Bug 修复:

  • 修复常量表达式除零导致的编译器 panic,现在报编译错误(#3533);
  • 数组用 == / != 比较现在报编译错误(此前被接受,但在某些图形后端会 shader 编译失败,#3535)。

彩色 Emoji 与文本渲染(issues #2649, #2956, #3456, #3457)

text/v2 包现在渲染彩色 emoji,使用字体内嵌的位图与彩色字形;应用必须提供含彩色字形的字体。双向文本此前已支持,本次修复了左右混合文本的视觉顺序。新函数 text.AdvanceAt 返回指定位置的插入符位置,也处理双向文本。

更多平台上的 IME 输入(issues #2736, #2831, #3446)

exp/textinput 包现在支持 Linux/UNIX 与 Android/iOS。新的 textinput.Composer 通过回调提供组合文本与提交文本,可以把 IME 输入集成到自定义文本编辑器和输入框中。旧的 textinput.Field 已废弃,新输入框应使用 textinput.Composerexp/textinput 仍为实验性。

窗口与桌面改进

  • 改善窗口缩放时的渲染,修复扭曲输出与临时黑区(#2615, #3477, #3478);
  • 新增查询系统浅色/深色模式,应用也可指定首选颜色模式,桌面端会影响窗口标题栏外观(#3386, #3387, #3480);
  • 应用现在可以无窗口运行,运行中也可改变窗口可见性(#3470);
  • Windows 上可执行文件内嵌的图标自动用作窗口图标(#3459);
  • 桌面端 ebiten.AbsPather 接口提供被拖放文件/目录的绝对路径(#3252)。

其他新特性

  • Linux 现在可用 framebuffer device(fbdev)和 EGL,在不依赖 X11/Wayland 的情况下渲染。需要兼容设备与 EGL 驱动,可用于无窗口系统的手持主机等设备(#3491);
  • Windows/macOS/Linux 新增手柄振动支持(#2014);
  • (*audio.Player).SetVolume 现在接受大于 1 的值(#3359);
  • 新增面向 AI agent 的 skill files,用于通过无头执行自动调试和编写 Kage shader。

新增 API

ebiten.AbsPatherebiten.ColorModeColorModeUnknown/Light/Darkebiten.SystemColorMode()/PreferredColorMode()/SetPreferredColorMode()(*ebiten.ColorScale).Set()/SetWithColor()ebiten.CursorPositionF()ebiten.TouchPositionF()/inpututil.TouchPositionFInPreviousTick()ebiten.IsCapsLockOn()/IsNumLockOn()ebiten.MaxImageSize()ebiten.ScreenSize()ebiten.RunOnMainThread()ebiten.IsWindowVisible()/SetWindowVisible()(*ebiten.Image).RecyclableSubImage()/Recycle()ebiten.RunGameOptions.VMGuestEndpoint(*audio.Player).PauseAndStopReading()text.AdvanceAt()text.Glyph.AdvanceX/AdvanceY/Coloredtext.LazyGlyph/AppendLazyGlyphs()text.VariationAxis/(*text.GoTextFaceSource).AppendVariationAxes()textinput.Composer/SessionOptions/Composition/Commit

废弃 API

  • (*audio.Player).Close()PauseAndStopReading()
  • text.Advance()text.AdvanceAt()
  • textinput.Fieldtextinput.Composer

Bug 修复(部分)

  • 修复分数显示缩放下窗口尺寸与全屏分辨率不正确,以及浏览器中渲染模糊(#2978, #2225, #2958);
  • 修复 macOS 启动前设置全屏导致黑屏,以及禁用 Vsync 无效(#3508, #3392);
  • 修复 macOS 部分手柄按键无法识别(#3471);
  • 修复修饰键状态更新不正确、浏览器滚轮输入不平滑;
  • 修复 IME 输入丢失与组合期间切换焦点的问题;
  • 修复 Android OpenGL 上下文丢失后的渲染恢复与挂起卡死;
  • 修复 Proton/DXVK 下 DirectX 初始化崩溃(#3489);
  • 修复缩放文本在目标边缘被裁剪,以及同一字体源并发使用的数据竞争;
  • 修复音频重采样/seek 长度与播放位置不正确及流损坏。

性能

  • 改变 GPU 资源恢复方式,减少保留绘图历史的工作量;
  • 减少矢量图形纹理图集占用;
  • text/v2 延迟字形图像创建,减少不必要的图像创建与 draw call;
  • (*ebiten.Image).RecyclableSubImageRecycle 允许复用子图对象以减少内存分配(Recycle 只能用于 RecyclableSubImage 创建的图像);
  • 减少窗口操作中的锁使用。

v2.10.1(2026-09-10)Bug 修复

  • 修复桌面窗口隐藏/最小化/完全被遮挡时不限内存增长(可能导致 OOM 崩溃或恢复窗口时长时间冻结,#3686);
  • 修复隐藏或被遮挡窗口恢复可见后仍显示旧帧(#3698);
  • 修复 Windows 副显示器在左侧时光标命中测试与光标图像更新不正确(#3696);
  • 修复 Windows/macOS 读取手柄设备名的潜在缓冲区溢出(#3693, #3695);
  • 修复 Linux 手柄轮询中设备通知队列溢出可触发的崩溃(#3694);
  • 修复 Linux 输入事件队列溢出后手柄按键错误保持按下/释放(#3697);
  • 修复 macOS OpenGL 上下文操作与 macOS/iOS 手柄振动中不安全指针处理(#3701);
  • 修复 cmd/ebitenmobile 因 Go 1.25 构建失败(#3688)。

v2.10.2(2026-09-14)Bug 修复

  • 修复 Ebitengine 应用在 macOS 13 Ventura 无法运行(#3704)。
复制全文 生成海报 Go Ebitengine 游戏开发 Cgo purego

推荐文章

程序员茄子在线接单