1.首先并不需要每个texture对应一个pipeline,可以在同一pipeline中使用不同的BindGroup,每个group对应不同的texture binding. e.g.
let sampler = device.createSampler({
magFilter: 'linear',
minFilter: 'linear',
});
let texture1 = device.createTexture({ ... });
let texture2 = device.createTexture({ ... });
const group1 = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [
{
binding: 1,
resource: sampler,
},
{
binding: 2,
resource: texture1.createView(),
}
]
});
const group2 = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [
{
binding: 1,
resource: sampler,
},
{
binding: 2,
resource: texture2.createView(),
}
]
});
然后在 rendering loop 中通过 setBindGroup 切换 group1 和 group 2 即可。
2.如果一组 textures 是同样的大小和格式,可以直接使用 texture_2d_array 去存储多个 image,这样即使一个group内,也可以在shader中通过切换array的index,来直接切换 texutre.
对于动态的 video texuture, 我们可以直接使用 importExternalTexture 进行引入,随着video播放,texture 会自动更新
const video = document.createElement('video');
video.loop = true;
video.autoplay = true;
video.muted = true;
video.src = '...';
await video.play();
const group = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [
{
binding: 1,
resource: sampler,
},
{
binding: 2,
resource: device.importExternalTexture({
source: video,
})
}
]
});
3.对于更新静态的 texutre,可以根据目标 image/texture 的类型进行 copy 更新,目前 webgpu 提供多个copy command,我们一般最主要会用到的:copyExternalImageToTexture ,可以更新外部image到gpu texture:
let texture = device.createTexture({ ... });
const img1 = document.createElement('img');
img1.src = '....';
await img1.decode();
const image1 = await createImageBitmap(img1);
device.queue.copyExternalImageToTexture(
{ source: image1 },
{ texture: texture },
[image1.width, image1.height]
);
...
...js
// 更新texture的image
const img2 = document.createElement('img');
img2.src = '....';
await img2.decode();
const image2 = await createImageBitmap(img2);
device.queue.copyExternalImageToTexture(
{ source: image2 },
{ texture: texture },
[image2.width, image2.height]
);
另外,也可以用 commandEncoder 执行 copyTextureToTexture 进行两个 gpu texutre 之间的copy 更新
// e.g. 创建两个texture,texture1 用于显示,tempTexture用于接收外部图片,图片loading 后进行 copy 更新
let texture1 = device.createTexture({ ... });
...
let tempTexture = device.createTexture({ ... });
let newImage = await loadImage() // 异步加载图片
device.queue.copyExternalImageToTexture(
{ source: newImage },
{ texture: tempTexture },
[newImage.width, newImage.height]
);
const commandEncoder = device.createCommandEncoder();
commandEncoder.copyTextureToTexture(
{ texture: tempTexture },
{ texture: texture1 }
);
device.queue.submit([commandEncoder.finish()]);
其他的更新texture API 使用方法,可以参阅 https://www.orillusion.com/webgpu.html#image-copies
4.对于 sampler,目前 webgpu 没有直接更新 sampler 的API,只能创建新的 sampler,并使用新的group进行渲染,e.g.
let linearSampler = device.createSampler({
magFilter: 'linear',
minFilter: 'linear',
});
const group = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [
{
binding: 1,
resource: linearSampler,
},
{
binding: 2,
resource: texture
}
]
});
let nearestSampler = device.createSampler({
magFilter: 'nearest',
minFilter: 'nearest',
});
const newGroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [
{
binding: 1,
resource: nearestSampler,
},
{
binding: 2,
resource: texture
}
]
});
group中其他的resource并不需要重新创建,可以复用