-
Notifications
You must be signed in to change notification settings - Fork 25
/
webgpu-polyfill.js
81 lines (73 loc) · 2.67 KB
/
webgpu-polyfill.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
class WebGPUInteropPolyfill {
getTextureFormat() {
return 'rgba8unorm';
}
transferToGPUTexture(opts) {
this._device = opts.device;
this._outTexture = this._device.createTexture({
size: [this.canvas.width, this.canvas.height],
format: 'rgba8unorm',
usage:
GPUTextureUsage.TEXTURE_BINDING |
GPUTextureUsage.COPY_DST |
GPUTextureUsage.RENDER_ATTACHMENT,
});
this._device.queue.copyExternalImageToTexture(
{ source: this.canvas },
{ texture: this._outTexture },
[this.canvas.width, this.canvas.height]);
return this._outTexture;
}
transferBackFromGPUTexture() {
const canvas = new OffscreenCanvas(this.canvas.width, this.canvas.height);
const ctx = canvas.getContext("webgpu");
ctx.configure({
device: this._device,
format: this._outTexture.format,
});
const mod = this._device.createShaderModule({ code: `
@vertex fn mainvs(@builtin(vertex_index) VertexIndex : u32) -> @builtin(position) vec4f {
var pos = array(vec2(3.0, 0.0), vec2(-1.0, -2.0), vec2(-1.0, 2.0));
return vec4f(pos[VertexIndex], 0.0, 1.0);
}
@group(0) @binding(0) var myTexture: texture_2d<f32>;
@fragment fn mainfs(@builtin(position) position : vec4f) -> @location(0) vec4f {
return textureLoad(myTexture, vec2i(position.xy), 0);
}`
});
const pipeline = this._device.createRenderPipeline({
layout: 'auto',
vertex: {module: mod, entryPoint: 'mainvs'},
fragment: {module: mod, entryPoint: 'mainfs',
targets: [{ format: this._outTexture.format }]},
});
const bindGroup = this._device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [{ binding: 0, resource: this._outTexture.createView() }],
});
const encoder = this._device.createCommandEncoder();
const pass = encoder.beginRenderPass({
colorAttachments: [{
view: ctx.getCurrentTexture().createView(),
clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 0.0 },
loadOp: 'clear',
storeOp: 'store',
}],
});
pass.setPipeline(pipeline);
pass.setBindGroup(0, bindGroup);
pass.draw(3);
pass.end();
this._device.queue.submit([encoder.finish()]);
this._outTexture.destroy();
delete this._outTexture;
this.clearRect(0, 0, canvas.width, canvas.height);
this.drawImage(canvas, 0, 0, canvas.width, canvas.height);
}
}
for (const ctx of [CanvasRenderingContext2D, OffscreenCanvasRenderingContext2D]) {
for (const f of Object.getOwnPropertyNames(WebGPUInteropPolyfill.prototype)) {
if (f === 'constructor' || ctx.prototype.hasOwnProperty(f)) continue;
ctx.prototype[f] = WebGPUInteropPolyfill.prototype[f];
}
}