kkokkojeong / ExWebGPU

WebGPU examples
2 stars 0 forks source link

From WebGL to WebGPU #7

Open kkokkojeong opened 1 year ago

kkokkojeong commented 1 year ago
kkokkojeong commented 1 year ago
button.onclick = async () => {
  const constraints = { video: { frameRate: 120 } };
  const stream = await navigator.mediaDevices.getUserMedia(constraints);
  const track = stream.getTracks()[0];

  const trackSettings = track.getSettings();
  canvas.width = trackSettings.width;
  canvas.height = trackSettings.height;

  const video = document.createElement("video");
  video.srcObject = stream;
  await video.play();
  canvas.classList.add('fullscreen');
  (function render() {
    const videoFrame = new VideoFrame(video);
    applyFilter(videoFrame);
    requestAnimationFrame(render);
  })();
};

const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();

const format = navigator.gpu.getPreferredCanvasFormat();
const context = document.querySelector("canvas").getContext("webgpu");
context.configure({ device, format });

const module = device.createShaderModule({
  code: `
    @vertex
    fn vertexMain(@builtin(vertex_index) i : u32) -> @builtin(position) vec4f {
      const quadPos = array(vec2f(-1, 1), vec2f(-1, -1), vec2f(1, 1), vec2f(1, -1));
      return vec4f(quadPos[i], 0, 1);
    }

    @group(0) @binding(0) var myTexture: texture_external;

    @fragment
    fn fragmentMain(@builtin(position) position : vec4f) -> @location(0) vec4f {
      let result = textureLoad(myTexture, vec2u(position.xy));
      if (position.x > f32(textureDimensions(myTexture).x / 2)) {
         return result;
      }
      let gray = dot(result.xyz, vec3f(0.21, 0.71, 0.07));
      return vec4f(gray, gray, gray, 1);
    }
  `,
});
const pipeline = device.createRenderPipeline({
  layout: "auto",
  vertex: {
    module,
    entryPoint: "vertexMain",
  },
  fragment: {
    module,
    entryPoint: "fragmentMain",
    targets: [{ format }],
  },
  primitive: {
    topology: "triangle-strip",
  },
});

function applyFilter(videoFrame) {
  const texture = device.importExternalTexture({ source: videoFrame });
  const bindgroup = device.createBindGroup({
    layout: pipeline.getBindGroupLayout(0),
    entries: [{ binding: 0, resource: texture }],
  });

  const commandEncoder = device.createCommandEncoder();
  const colorAttachments = [
    {
      view: context.getCurrentTexture().createView(),
      loadOp: "clear",
      storeOp: "store",
    },
  ];

  const passEncoder = commandEncoder.beginRenderPass({ colorAttachments });
  passEncoder.setPipeline(pipeline);
  passEncoder.setBindGroup(0, bindgroup);
  passEncoder.draw(4);
  passEncoder.end();
  device.queue.submit([commandEncoder.finish()]);
  videoFrame.close();
}
kkokkojeong commented 1 year ago