WebGPU 现已在 Safari 技术预览版中开放测试

WebGPU 是一个新的符合标准的 API,它能在 Web 上实现高性能 3D 图形和通用计算。WebGPU 程序用 JavaScript 编写,但暴露了 GPU 功能,首次允许在 Web 内容中使用 GPU 计算。从 Safari 技术预览版 185 开始,WebGPU 可以被启用用于早期测试和开发。

要启用 WebGPU,请在 Safari 偏好设置的功能标志标签页中,打开“WebGPU”、“GPU 进程:DOM 渲染”和“GPU 进程:Canvas 渲染”功能标志。如果您没有看到功能标志标签页,您需要先在“高级”标签页中勾选“显示网页开发者功能”。

在 Safari 技术预览版 185 中启用 WebGPU 后,请尝试这个 WebGPU 示例。它利用了 WebGPU 的许多最佳功能。

WebGPU JavaScript API

WebGPU API 通过 JavaScript 访问,类似于 WebGL。

创建 GPUDevice

为了使用 WebGPU,必须创建一个设备。资源和管道状态是从 GPUDevice 实例创建的。要创建一个具有默认限制和在所有支持 WebGPU 的设备上都支持的功能的设备,我们可以向 requestAdapterrequestDevice 的调用传递零参数。

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

配置 GPUCanvasContext

GPUCanvasContext 是一个接口,允许您配置内容在页面上相应的 HTMLCanvas 元素中显示的方式。

context = canvas.getContext('webgpu');
const canvasFormat = "bgra8unorm";

const contextConfiguration = {
    device: device,
    format: canvasFormat,
    alphaMode: 'opaque',
};
context.configure(contextConfiguration);

创建 GPURenderPipeline

GPURenderPipeline 或相应的 GPUComputePipeline 用于配置图形驱动程序的管道状态。然后,此管道状态会在 GPURenderPassEncoderGPUComputePassEncoder 中使用,如下面所示。

const shaderModule = device.createShaderModule({ code: wgslSource });
const vertexStageDescriptor = { module: shaderModule, entryPoint: "vsmain" };
const fragmentStageDescriptor = { module: shaderModule, entryPoint: "fsmain" };
const renderPipelineDescriptor = {
    layout: 'auto',
    vertex: vertexStageDescriptor,
    fragment: fragmentStageDescriptor,
    primitive: {topology: "triangle-list" },
};
const renderPipeline = device.createRenderPipeline(renderPipelineDescriptor);

发出绘制调用

创建 GPURenderPassEncoder 以向图形驱动程序发送绘制调用。在下面的示例中,我们绘制一个包含三个顶点的简单三角形。GPURenderPassEncoder 还可以绘制同一几何体的多个实例或从顶点缓冲区的偏移量处绘制。

const colorAttachmentDescriptor = {
    view: renderAttachment,
    loadOp: "clear",
    storeOp: "store",
    clearColor: { r: 0.15, g: 0.15, b: 0.5, a: 1 }
};
const renderPassDescriptor = { colorAttachments: [colorAttachmentDescriptor] };
const commandEncoder = device.createCommandEncoder();
const renderPassEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
renderPassEncoder.setPipeline(renderPipeline);
const vertexBufferSlot = 0;
renderPassEncoder.setVertexBuffer(vertexBufferSlot, vertexBuffer, 0);
renderPassEncoder.draw(3, 1, 0, 0); // 3 vertices, 1 instance, 0th vertex, 0th instance.
renderPassEncoder.end();
const commandBuffer = commandEncoder.finish();
const queue = device.queue;
queue.submit([commandBuffer]);

WebGPU 着色语言

WebGPU 引入了 WGSL,一种适用于 Web 的平台独立着色语言。以下是一个 WGSL 着色器源代码的示例,它将替代上述 API 调用中的 wgslSource

const wgslSource = `
    struct Vertex {
        @builtin(position) Position: vec4<f32>,
        @location(0) color: vec4<f32>,
    }

    @vertex fn vsmain(@builtin(vertex_index) VertexIndex: u32) -> Vertex
    {
        var pos: array<vec2<f32>, 3> = array<vec2<f32>, 3>(
            vec2<f32>( 0.0,  0.5),
            vec2<f32>(-0.5, -0.5),
            vec2<f32>( 0.5, -0.5));
        var vertex_out : Vertex;
        vertex_out.Position = vec4<f32>(pos[VertexIndex], 0.0, 1.0);
        vertex_out.color = vec4<f32>(pos[VertexIndex] + vec2<f32>(0.5, 0.5), 0.0, 1.0);
        return vertex_out;
    }

    @fragment fn fsmain(in: Vertex) -> @location(0) vec4<f32>
    {
        return in.color;
    }
`;

尝试 WebGPU 并提交错误!

我们很高兴在最新版 Safari 技术预览版中提供了 WebGPU 和 WGSL 的早期版本。请务必尝试一下。查看 WebGPU 示例的公共仓库。并在 bugs.webkit.org 提交您发现的错误或问题。