demo网站

Shaders:

//
// vert
//
@vertex
fn main(
  @builtin(vertex_index) VertexIndex : u32
) -> @builtin(position) vec4f {
  var pos = array<vec2f, 3>(
    vec2(0.0, 0.5),
    vec2(-0.5, -0.5),
    vec2(0.5, -0.5)
  );

  return vec4f(pos[VertexIndex], 0.0, 1.0);
}

//
// frag
//

@fragment
fn main() -> @location(0) vec4f {
  return vec4(1.0, 0.0, 0.0, 1.0);
}

Utils:

export function quitIfWebGPUNotAvailable(
  adapter: GPUAdapter | null,
  device: GPUDevice | null
): asserts device {
  if (!device) {
    quitIfAdapterNotAvailable(adapter);
    fail('Unable to get a device for an unknown reason');
  }

  device.lost.then((reason) => {
    fail(`Device lost ("${reason.reason}"):\\n${reason.message}`);
  });
  device.onuncapturederror = (ev) => {
    fail(`Uncaptured error:\\n${ev.error.message}`);
  };
}

完整代码:

import triangleVertWGSL from '../../shaders/triangle.vert.wgsl';
import redFragWGSL from '../../shaders/red.frag.wgsl';
import { quitIfWebGPUNotAvailable } from '../util';

const canvas = document.querySelector('canvas') as HTMLCanvasElement;
const adapter = await navigator.gpu?.requestAdapter();
const device = await adapter?.requestDevice();
quitIfWebGPUNotAvailable(adapter, device);

const context = canvas.getContext('webgpu') as GPUCanvasContext;

//表示显示设备的物理像素与 CSS 像素的比例。这个属性在许多现代浏览器中都可以用来确定显示设备的分辨率和缩放比例。
const devicePixelRatio = window.devicePixelRatio;
canvas.width = canvas.clientWidth * devicePixelRatio;
canvas.height = canvas.clientHeight * devicePixelRatio;
const presentationFormat = navigator.gpu.getPreferredCanvasFormat();

context.configure({
  device,
  format: presentationFormat,
  alphaMode: 'premultiplied',
});

const pipeline = device.createRenderPipeline({
  layout: 'auto',
  vertex: {
    module: device.createShaderModule({
      code: triangleVertWGSL,
    }),
  },
  fragment: {
    module: device.createShaderModule({
      code: redFragWGSL,
    }),
    targets: [
      {
        format: presentationFormat,
      },
    ],
  },
  primitive: {
    topology: 'triangle-list',
  },
});

function frame() {
  const commandEncoder = device.createCommandEncoder();
  const textureView = context.getCurrentTexture().createView();

  const renderPassDescriptor: GPURenderPassDescriptor = {
    colorAttachments: [
      {
        view: textureView,
        clearValue: [0, 0, 0, 1],
        loadOp: 'clear',
        storeOp: 'store',
      },
    ],
  };

  const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
  passEncoder.setPipeline(pipeline);
  passEncoder.draw(3);
  passEncoder.end();

  device.queue.submit([commandEncoder.finish()]);
  requestAnimationFrame(frame);
}

requestAnimationFrame(frame);

navigator

navigator 是一个全局对象,用于提供有关浏览器的信息以及访问浏览器的某些功能。

Adapter:

适配器是 WebGPU 的一个对象,表示系统上可用的 WebGPU 实现。这可能是硬件加速的(例如,集成显卡或独立显卡)或软件实现的。

Device:

Device是与Adapter的逻辑连接。它为你提供了与适配器交互的接口。

Device将底层的硬件(如显卡)抽象为一个统一的接口,使得你不需要直接处理底层硬件细节。

Device是所有通过它创建的 WebGPU 对象的根所有者。也就是说,设备负责管理和清理这些对象。