跳到主要内容

计算着色与图像处理

卷积、直方图、降噪是 数据并行公式,不是 getImageData 循环。场景图(源图 id、ROI、参数)留在 CPU;像素数组是投影。生产默认仍是 WebGL2 浮点 FBO ping-pong;真正的 compute 只在 requestAdapter() 成功后上 WebGPU。结果若每帧 readPixels 回 JS,GPGPU 被一次同步吃掉。

1. 场景怎么切

CPU:源 ImageBitmap / 视频帧句柄、kernel、ROI
↓ 上传一次
GPU:storage / 浮点纹理上跑公式
↓ 下一趟渲染直接采样
偶尔:缩小后再读回给 UI 数字

不要热路径 2D getImageData 做卷积再 texImage2D 回去。那是 Canvas 像素管线 的处理表面。

export async function tryComputeHistogram(
device: GPUDevice,
pipeline: GPUComputePipeline,
bindGroup: GPUBindGroup,
workgroups: number,
): Promise<void> {
const encoder = device.createCommandEncoder();
const pass = encoder.beginComputePass();
pass.setPipeline(pipeline);
pass.setBindGroup(0, bindGroup);
pass.dispatchWorkgroups(workgroups);
pass.end();
device.queue.submit([encoder.finish()]);
}

export function hasFloatColor(gl: WebGL2RenderingContext): boolean {
return gl.getExtension("EXT_color_buffer_float") !== null;
}

export function runKernelPass(
gl: WebGL2RenderingContext,
readTex: WebGLTexture,
writeFbo: WebGLFramebuffer,
width: number,
height: number,
drawQuad: (gl: WebGL2RenderingContext) => void,
): void {
gl.bindFramebuffer(gl.FRAMEBUFFER, writeFbo);
gl.viewport(0, 0, width, height);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, readTex);
drawQuad(gl);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
}

离线卷积走 texel / UV,全屏三角形不要乘场景相机。只有「场景里一块处理板」才用世界矩形 × viewProj,kernel 仍在纹素空间。WebGL2 默认:全屏三角形 + 浮点附件,见 Compute 章。没 EXT_color_buffer_float 时不要用 RGBA8 假装积分。读写必须拆成 ping-pong。Transform feedback 适合粒子状态,不适合邻域卷积。

适用:全图像素同一 kernel、直方图、粒子全体积分且结果留在 GPU。
不适用:几十像素的 CPU 循环;每帧要把 1080p 直方图读回做 UI——缩小到 256 bin 或隔帧 mapAsync

2. 哪层必须 CPU,哪层进 GPU

归属
选哪张源、kernel 系数、业务阈值CPU 文档
texel / storage bufferGPU 投影
「图上有哪些可点对象」CPU 场景,禁止从直方图反推
导出 PNG离线读 FBO;热路径禁止全屏读回

WebGPU:mapAsync 不要在 rAF 里 await,双 staging 隔帧,见 读回陷阱。adapter 为 null 是产品路径:降级浮点 FBO 或降级 CPU,不要 throw「请换浏览器」。

跨源源图无 CORS,compute 写完的表面一样 taint,readPixels / toBlob 仍失败,见 CORS。drawing buffer 原点左下,若把读回当 ImageData 必须翻 Y。

源图尺寸夹紧 MAX_TEXTURE_SIZE / WebGPU limits。上下文丢失后 storage 句柄作废,从 CPU 持有的 ImageBitmap 重建,不要假定 GPU 里还有「处理结果文档」。

3. 失败形态

症状原因
结果阶梯状8bit FBO 当浮点积分
ping-pong 花屏读写同一张纹理
算完比 CPU 还慢每帧全屏 readPixels / rAF 里 await mapAsync
WebGPU 局域网挂非安全上下文,或 adapter null 没降级
导出 SecurityError跨源纹理污染了目标

权威资料

核对日期:2026-08-26