Electron sharedTexture.subtle 实战指南:SharedTextureSubtle 对象的导入、跨进程传输与 GPU 资源生命周期管理
SharedTextureSubtle 是 Electron sharedTexture 模块面向高级用户提供的「subtle(底层)」API 集合,用于将 Windows NT HANDLE、macOS IOSurface、Linux NativePixmap 等平台原生共享纹理句柄导入 Electron 并转换为 VideoFrame,且支持跨进程传输。读完本文,你能掌握 importSharedTexture / finishTransferSharedTexture 的完整参数结构、SharedTextureImportedSubtle 上五个核心方法的用法,以及基于同步令牌(Sync Token)与释放回调的 GPU 资源生命周期管理方案,并能在离屏渲染(OSR)场景中把纹理送入 WebGPU 渲染管线。
一、背景:subtle API 在整个 sharedTexture 体系中的位置
Electron 的 sharedTexture 模块(见 sharedTexture 模块文档)负责把外部共享纹理导入 Electron,并转换为 Web 标准的 VideoFrame,支持所有 Web 渲染体系(WebGPU、WebGL 等),且纹理引用可以跨 Electron 进程传递。该模块的常规 API 有三个:
sharedTexture.importSharedTexture(options):仅主进程可用,返回SharedTextureImported,通过allReferencesReleased回调在所有进程引用全部释放时被通知;sharedTexture.sendSharedTexture(options, ...args):仅主进程可用,把已导入的纹理发送给指定WebFrameMain对应的渲染进程(有 1000ms 超时,要求接收端已注册接收回调);sharedTexture.setSharedTextureReceiver(callback):仅渲染进程可用,注册接收纹理的回调。
而 sharedTexture.subtle 是一个 Experimental(实验性) 属性,返回一个 SharedTextureSubtle 对象,为高级用户提供更细粒度的控制:它不依赖 importSharedTexture 的托管式生命周期(allReferencesReleased),而是把「导入、转移、同步、释放」每一步都暴露为显式方法,让用户自己决定何时、如何释放 GPU 进程中的底层资源。正如模块文档所述,实验性 API 标记为 Experimental,未来可能变化或移除,使用时应以当前仓库版本为准。
模块文档同时指向了一份设计说明 shell/common/api/shared_texture/README.md,其中解释了实现基于 Chromium 的 SharedImage 基础设施,以及为何要引入同步令牌来管理帧的跨进程生命周期——这正是下文第四节展开的原理依据。
二、SharedTextureSubtle 对象:两个核心方法
SharedTextureSubtle 对象定义在 docs/api/structures/shared-texture-subtle.md,包含两个方法:
2.1 sharedTexture.subtle.importSharedTexture(textureInfo)
- 参数:
textureInfoSharedTextureImportTextureInfo —— 要导入的共享纹理的信息; - 返回:SharedTextureImportedSubtle —— 导入的共享纹理对象。
它的作用是从给定选项导入共享纹理。注意与托管版 sharedTexture.importSharedTexture(options) 的差异:subtle 版本只接收 textureInfo,不提供 allReferencesReleased 回调;所有进程间引用的释放都要由你显式管理。典型输入来源是 OSR paint 事件中的 event.texture.textureInfo(见 OffscreenSharedTexture 结构,其中 handle 字段即 SharedTextureHandle)。
2.2 sharedTexture.subtle.finishTransferSharedTexture(transfer)
- 参数:
transferSharedTextureTransfer —— 共享纹理的传输对象; - 返回:SharedTextureImportedSubtle —— 从传输对象恢复出的已导入共享纹理。
它与 startTransferSharedTexture 配对使用:源进程用 startTransferSharedTexture 生成可序列化的 SharedTextureTransfer,把 transfer 字符串(不透明数据)经 IPC 等任意通道传送到目标进程,目标进程调用 finishTransferSharedTexture 即可在本进程重新获得对同一 GPU 纹理的引用。从 SharedTextureTransfer 文档看,其字段(transfer、syncToken、pixelFormat、codedSize、visibleRect、timestamp)均为 Readonly,transfer 字符串「可以在 Electron 进程之间传递」。
从源码设计文档 shell/common/api/shared_texture/README.md 可以确认其底层机制:实现使用 SharedImageInterface->ImportSharedImage 和 ClientSharedImage->Export 序列化足够信息,使另一进程能重新获取指向同一 SharedImageBacking(GPU 进程中的 Mailbox 引用)的 SharedImage,并复用 mojo 序列化器把结果序列化为字符串——这就是 transfer 字段可以裸串跨进程传输的原因。
三、导入输入结构:SharedTextureImportTextureInfo
importSharedTexture 接收的 SharedTextureImportTextureInfo 完整字段如下,是编写纹理导入代码时的关键参数清单:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
pixelFormat |
string | 是 | 纹素的像素格式,取值见下表 |
colorSpace |
ColorSpace | 否 | 纹理的色域 |
codedSize |
Size | 是 | 共享纹理的完整尺寸 |
visibleRect |
Rectangle | 否 | [0, 0, codedSize.width, codedSize.height] 的子区域;常见情况下就是全区域 |
timestamp |
number | 否 | 以微秒为单位的时间戳,会反映到 VideoFrame 上 |
handle |
SharedTextureHandle | 是 | 共享纹理句柄 |
pixelFormat 支持六种格式:
bgra:32bpp BGRA(字节序),1 平面;rgba:32bpp RGBA(字节序),1 平面;rgbaf16:半浮点(half float)RGBA,1 平面;nv12:12bpp,Y 平面后跟 2x2 交错 UV 平面;nv16:16bpp,Y 平面后跟 2x1 交错 UV 平面;p010le:4:2:0 10-bit YUV(小端),Y 平面后跟 2x2 交错 UV 平面。
其中 YUV 系格式(nv12/nv16/p010le)正是视频帧的典型编码,而 OSR 导出的纹理则为 rgba/bgra/rgbaf16(见 OffscreenSharedTexture 文档中 textureInfo.pixelFormat 的枚举)。
平台句柄:SharedTextureHandle
handle 字段是平台相关的 SharedTextureHandle:
- Windows:
ntHandle(Buffer)持有共享纹理。注意该 NT HANDLE 仅在当前进程内有效;rgba、bgra、rgbaf16格式的输出纹理句柄不带 keyed mutex,而nv12格式的句柄带 keyed mutex。 - macOS:
ioSurface(Buffer)持有 IOSurfaceRef;该 IOSurface 是当前进程本地的(非全局)。 - Linux:
nativePixmap对象包含各平面信息——planes数组中每个平面含stride、offset、size(字节)与fd(底层内存对象(通常是 dmabuf)的文件描述符);另有modifier(来自 GBM 库,传给 EGL 驱动)与supportsZeroCopyWebGpuImport(是否支持零拷贝导入 WebGPU)。
这里有一个非常重要的前提约束(由设计文档 shell/common/api/shared_texture/README.md 明确说明):调用 importSharedTexture 时,句柄必须已经对当前进程可见。Windows 的 NT HANDLE 是进程本地的,跨进程需要 DuplicateHandle;macOS 的全局 IOSurface(kIOSurfaceIsGlobal)是已废弃选项,更常规的方式是把 mach_port 经 IPC 传递——而 Chromium 的 IPC 内部已透明处理这些问题(这也是 OSR paint 事件能直接使用句柄的原因,因为句柄已经过 IPC 传输)。另外,Windows 上不能使用非 NT HANDLE(对其调用 CloseHandle 是非法操作会导致 Chromium 崩溃),Electron 在导入时会对 NT HANDLE 做 duplicate。
四、输出对象:SharedTextureImportedSubtle 的五个方法
importSharedTexture 与 finishTransferSharedTexture 都返回 SharedTextureImportedSubtle。它提供五个方法,覆盖了「取帧、释放、再转移、同步」的完整生命周期:
4.1 getVideoFrame() → VideoFrame
创建使用当前进程中已导入共享纹理的 VideoFrame。用完后可调用 VideoFrame.close();文档特别指出「底层资源会在内部等待 GPU 完成」,即不需要手动等待 GPU 命令缓冲执行完毕即可 close 帧。
4.2 release(callback?) —— 释放与 GPU 完成通知
释放该对象的资源。如果一次传输后获得了多个 SharedTextureImported 对象(subtle 场景下即多个 SharedTextureImportedSubtle),必须逐个 release,最后一个释放时 GPU 进程中的资源才会真正销毁。
可选的 callback 参数在 GPU 命令缓冲完成使用该共享纹理时触发,提供了一个精确的时机来安全释放依赖资源。文档给出的两个典型场景:
- 若本对象由
finishTransferSharedTexture创建,可以用该回调通知源进程安全释放当初调用startTransferSharedTexture的原始对象; - 也可以安全释放当初用于
importSharedTexture的源共享纹理。
4.3 startTransferSharedTexture() → SharedTextureTransfer
创建一个可序列化、可转移到其他进程的 SharedTextureTransfer。把其中的 transfer 字符串通过 IPC 发给目标进程后,对方用 finishTransferSharedTexture 取回 SharedTextureImportedSubtle。
4.4 getFrameCreationSyncToken() → SharedTextureSyncToken
面向高级用户。通常应在 finishTransferSharedTexture 之后调用,得到的 SharedTextureSyncToken(内含一个不透明的 syncToken 字符串)应回传给调用过 startTransferSharedTexture 的源对象,目的是防止源对象在目标对象尚未于 GPU 进程中异步拿到引用之前就释放底层资源。
4.5 setReleaseSyncToken(syncToken)
面向高级用户。设置后,本对象的底层资源不会释放,直到所设置的 SharedTextureSyncToken 在 GPU 进程中被满足(signaled)。文档说明其价值:使用同步令牌后,用户不再需要使用 release 回调来做生命周期管理——两种机制(回调与令牌)可以二选一,或组合使用。
底层原理:为什么需要 Sync Token
设计文档 shell/common/api/shared_texture/README.md 对这一机制有详细解释:GPU 调用大多是异步的,通过各客户端进程的 GpuChannel 提交到 GPU 进程的命令缓冲。当两个进程持有引用同一 Mailbox 的两个 SharedImage 实例时,无法直接知道 GPU 何时用完资源,这通常由 SyncToken 保证——例如可以把主进程中 SharedImage 的销毁调度到一个空 SyncToken 上;而在渲染进程中用 WebGPU(或 WebGL)管线使用同一纹理时,WebGPU 会生成销毁令牌,确保渲染完成前不会销毁。实现上,Electron 使用 gpu::ContextSupport 注册「某个 SyncToken 被释放(signaled)」的回调:当你对已导入的共享纹理对象调用 release() 且它已通过 VideoFrame 进入 WebGPU 管线时,Electron 会等待 WebGPU 渲染完成,然后运行你的回调,通知你去释放依赖资源(如主进程中的原始导入对象、源纹理等)。
五、端到端实战:OSR 纹理经 subtle API 跨进程送入 WebGPU 渲染
仓库测试用例 spec/api-shared-texture-spec.ts 中的 "successfully imported and rendered with subtle api" 用例(约第 34 行起)完整演示了 subtle API 的工作流,配套的 preload/renderer 代码在 spec/fixtures/api/shared-texture/subtle/ 目录下。主进程侧的关键步骤(摘自 spec/api-shared-texture-spec.ts):
// 1. 用 OSR 开启共享纹理导出,获得纹理句柄来源
const osr = new BrowserWindow({
width: 128,
height: 128,
webPreferences: { offscreen: { useSharedTexture: true } }
});
osr.webContents.setFrameRate(1);
osr.webContents.on('paint', (event) => {
// Step 1: 纹理句柄输入源(来自 OSR paint 事件)
const texture = event.texture;
// Step 2: subtle 导入 —— 只传 textureInfo,返回 SharedTextureImportedSubtle
const importedSubtle = sharedTexture.subtle.importSharedTexture(texture.textureInfo);
// Step 3: 生成可序列化传输对象
const transfer = importedSubtle.startTransferSharedTexture();
// Step 4: 把 transfer 字符串经 IPC 发给渲染进程
win.webContents.send('shared-texture', id, transfer);
});
ipcMain.on('shared-texture-done', (event, id) => {
const { importedSubtle, texture } = capturedTextures.get(id);
// Step 13: 释放主进程侧的导入对象
// Step 14: 在 GPU 完成使用后(release 回调内)释放源纹理
importedSubtle.release(() => {
texture.release();
});
});
渲染进程侧(spec/fixtures/api/shared-texture/subtle/preload.js 与 spec/fixtures/api/shared-texture/subtle/renderer.js):
// preload.js —— 接收传输对象并恢复纹理
ipcRenderer.on('shared-texture', async (e, id, transfer) => {
// Step 5: 从 transfer 恢复出 SharedTextureImportedSubtle
const importedSubtle = sharedTexture.subtle.finishTransferSharedTexture(transfer);
await cb(id, importedSubtle);
// Step 10: 带回调释放;GPU 命令缓冲完成后通知主进程
importedSubtle.release(() => {
ipcRenderer.send('shared-texture-done', id);
});
});
// renderer.js —— 取帧并用 WebGPU 渲染
const frame = importedSubtle.getVideoFrame(); // Step 7: 获取 VideoFrame
await window.renderFrame(frame); // Step 8: WebGPU 渲染
frame.close(); // Step 9: 用完关闭帧
这个链路验证了 subtle API 的完整闭环:OSR paint 事件产出平台句柄 → 主进程 importSharedTexture → startTransferSharedTexture 生成可跨进程传输的 SharedTextureTransfer → 渲染进程 finishTransferSharedTexture 恢复引用 → getVideoFrame 送入 WebGPU 管线 → 两级 release 回调按「GPU 完成」事件逐级向上游释放资源,确保主进程侧的源纹理(texture.release())一定在所有 GPU 使用完成之后才被释放。测试最终通过截屏像素比对(误差 < 1%)验证渲染结果正确。
六、适用前提、限制与选型建议
- 实验性 API:
sharedTexture.subtle及其相关结构均标记为 Experimental,未来可能调整或移除;且当前测试用例 spec/api-shared-texture-spec.ts 中注明「目前仅在 macOS arm64 上能正确运行」(process.platform !== 'darwin' || process.arch !== 'arm64'时整体跳过),其他平台的可用性请以当前仓库实测为准。 - 句柄可见性前提:调用
importSharedTexture时平台句柄必须已对当前进程可用(Windows 的 NT HANDLE 为进程本地、macOS 的 IOSurface 为进程本地引用);若要在渲染进程直接导入,需自行保证句柄在该进程内可见(设计文档建议优先利用 Electron/Chromium IPC 的透明句柄传递能力)。 - 生命周期责任划分:
- 追求简单、由 Electron 托管生命周期(所有引用释放后自动回调)→ 用托管版
sharedTexture.importSharedTexture+sendSharedTexture/setSharedTextureReceiver; - 需要精确控制跨进程转移与 GPU 释放时机(例如自己维护 IPC 通道、自定义释放顺序)→ 用
sharedTexture.subtle,配合startTransferSharedTexture/finishTransferSharedTexture手动传输,并用release(callback)或getFrameCreationSyncToken+setReleaseSyncToken二选一做生命周期管理。
- 追求简单、由 Electron 托管生命周期(所有引用释放后自动回调)→ 用托管版
- 多引用释放规则:一次传输后若得到多个导入对象,必须每个都调用
release,最后一个释放时 GPU 进程中的资源才销毁。 - 配套文档:
sharedTexture模块总览见 docs/api/shared-texture.md;设计原理(SharedImage、SyncToken、跨进程句柄处理)见 shell/common/api/shared_texture/README.md;相关结构文档 SharedTextureImportedSubtle、SharedTextureTransfer、SharedTextureSyncToken、SharedTextureHandle、SharedTextureImportTextureInfo 均位于docs/api/structures/目录下,可作为参数参考的权威来源。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00