这是 Apple 关于 WebGPU API 的草案提案。它最初是对 Metal 到 JavaScript 的映射,但这不会是它的最终形态。Metal 中不仅有一些内容与 Vulkan 和 D3D12 不完全契合,我们也不希望被 Metal API 绑定。因此,请将其视为一项正在进行的工作。文末有一个小的源代码示例(尽管有点过时)。
与传统的原生 GPU API 的主要区别在于
interface WebGPURenderingContext : CanvasRenderingContext {
// -- Identification and feature detection
readonly attribute DOMString name;
boolean supportsFeatureSet(WebGPUFeatureSet featureSet);
// -- Library creation
WebGPULibrary createLibrary(DOMString sourceCode);
// -- Command queue creation
WebGPUCommandQueue createCommandQueue();
// @@ Do we need createCommandQueueWithMaxCommandBufferCount?
// -- Resources
WebGPUBuffer createBuffer(ArrayBufferView data);
WebGPUTexture createTexture(WebGPUTextureDescriptor descriptor);
WebGPUSamplerState createSamplerState(WebGPUSamplerDescriptor descriptor);
// -- Rendering objects
WebGPUDepthStencilState createDepthStencilState(WebGPUDepthStencilDescriptor descriptor);
WebGPURenderPipelineState createRenderPipelineState(WebGPURenderPipelineDescriptor
descriptor);
// @@ Do we need the completion block versions?
// -- Compute
WebGPUComputePipelineState createComputePipelineState(WebGPUFunction function);
WebGPUComputePipelineState createComputePipelineState(WebGPUComputePipelineDescriptor
descriptor);
// -- Getting the rendering destination
WebGPUDrawable nextDrawable();
// @@ Come up with a better way to do this.
};
interface WebGPUCommandQueue {
attribute DOMString label;
WebGPUCommandBuffer createCommandBuffer();
};
interface WebGPUCommandBuffer {
// -- Command Encoders
WebGPURenderCommandEncoder createRenderCommandEncoder(WebGPURenderPassDescriptor
descriptor);
WebGPUBlitCommandEncoder createBlitCommandEncoder();
WebGPUComputeCommandEncoder createComputeCommandEncoder();
// -- Status
readonly attribute WebGPUStatus status;
readonly attribute DOMString error; // @@ need enum
// - Execution
void commit();
void presentDrawable(WebGPUDrawable drawable);
readonly attribute Promise scheduled;
readonly attribute Promise completed;
// @@ Should the completed promise be the return value of commit()?
// @@ Maybe add enqueue or invent some way to offload filling the buffer
// to workers?
};
interface WebGPUDrawable {
readonly attribute WebGPUTexture texture; // @@ Only the framebuffer should have this.
void present();
};
interface WebGPUCommandEncoder {
readonly attribute DOMString label;
void endEncoding();
// @@ Debugging helpers?
}
interface WebGPURenderCommandEncoder : WebGPUCommandEncoder {
// -- State
// @@ Should these be attributes?
void setBlendColor(float red, float green, float blue, float alpha);
void setCullMode(WebGPUCullMode mode);
void setDepthBias(float bias, float scale, float clamp);
void setDepthClipMode(WebGPUDepthClipMode mode);
void setDepthStencilState(WebGPUDepthStencilState depthStencilState);
void setFrontFacingWinding(WebGPUWinding mode);
void setRenderPipelineState(WebGPURenderPipelineState pipelineState);
// @@ Use Geometry interfaces?
void setScissorRect(float x, float y, float width, float height);
void setStencilReferenceValue(unsigned long value);
// @@ Check if we can overload here
void setStencilReferenceValue(unsigned long front, unsigned long back);
void setTriangleFillMode(WebGPUTriangleFill mode);
void setViewport(WebGPUViewportDictionary viewport);
void setVisibilityResultMode(WebGPUVisibilityResultMode mode, unsigned long offset);
// -- Resources
void setVertexBuffer(WebGPUBuffer buffer, unsigned long offset, unsigned long index);
void setVertexBuffers(WebGPUBuffer[] buffers, unsigned long[] offsets,
unsigned long startIndex, unsigned long count);
// @@ need setVertexBytes?
void setVertexSamplerState(WebGPUSamplerState samplerState, unsigned long index);
void setVertexSamplerStates(WebGPUSamplerState[] samplerState, unsigned long startIndex,
unsigned long count);
void setVertexTexture(WebGPUTexture texture, unsigned long index);
void setVertexTextures(WebGPUTexture[] textures, unsigned long startIndex,
unsigned long count);
void setFragmentBuffer(WebGPUBuffer buffer, unsigned long offset, unsigned long index);
void setFragmentBuffers(WebGPUBuffer[] buffers, unsigned long[] offsets,
unsigned long startIndex, unsigned long count);
// @@ need setFragmentBytes?
void setFragmentSamplerState(WebGPUSamplerState samplerState, unsigned long index);
void setFragmentSamplerStates(WebGPUSamplerState[] samplerState, unsigned long startIndex,
unsigned long count);
void setFragmentTexture(WebGPUTexture texture, unsigned long index);
void setFragmentTextures(WebGPUTexture[] textures, unsigned long startIndex,
unsigned long count);
// -- Drawing
void drawPrimitives(unsigned long type, unsigned long start, unsigned long count);
// @@ add drawInstanced and drawIndexed
};
interface WebGPUBlitCommandEncoder : WebGPUCommandEncoder {
// -- Copying Data Between Two Buffers
void copyFromBufferToBuffer(WebGPUBuffer source, unsigned long sourceOffset,
WebGPUBuffer destination,
unsigned long destinationOffset, unsigned long size);
// -- Copying Data From a Buffer to a Texture
void copyFromBufferToTexture(WebGPUBuffer buffer, unsigned long sourceOffset,
unsigned long sourceBytesPerRow,
unsigned long sourceBytesPerImage, WebGPUSize size,
WebGPUTexture texture,
unsigned long destinationSlice, unsigned long destinationLevel,
WebGPUOrigin origin);
// -- Copying Data Between Two Textures
void copyFromTextureToTexture();
// -- Copying Data from a Texture to a Buffer
void copyFromTextureToBuffer();
// - Image Operations
void fillBuffer(WebGPUBuffer buffer, unsigned long start,
unsigned long count, unsigned long value);
void generateMipmapsForTexture();
}
interface WebGPUComputeCommandEncoder : WebGPUCommandEncoder {
// - Specifying the Compute Pipeline State
void setComputePipelineState(WebGPUComputePipelineState state);
// -- Buffers and Textures
void setBuffer(WebGPUBuffer buffer, unsigned long offset, unsigned long index);
void setBuffers(WebGPUBuffer[] buffers, unsigned long[] offsets,
unsigned long startIndex, unsigned long count);
void setBuffer(ArrayBufferView bufferView, unsigned long index);
void setTexture(WebGPUTexture texture, unsigned long index);
void setTextures(WebGPUTexture[] textures, unsigned long startIndex, unsigned long count);
void setSamplerState(WebGPUSamplerState samplerState, unsigned long index);
void setSamplerStates(WebGPUSamplerState[] samplerStates, unsigned long startIndex,
unsigned long count);
// @@ do we need setThreadgroupMemoryLength?
// -- Executing
void dispatch(WebGPUSize threadgroupsPerGrid, WebGPUSize threadsPerThreadgroup);
// @@ dispatchThreadgroupsWithIndirectBuffer?
};
interface WebGPUViewport {
attribute double originX;
attribute double originY;
attribute double width;
attribute double height;
attribute double znear;
attribute double zfar;
};
[ Constructor ]
interface WebGPURenderPipelineDescriptor {
attribute DOMString label;
attribute WebGPUFunction vertexFunction;
attribute WebGPUVertexDescriptor vertexDescriptor;
attribute WebGPUFunction fragmentFunction;
attribute unsigned long sampleCount;
attribute boolean alphaToCoverageEnabled;
attribute boolean alphaToOneEnabled;
attribute boolean rasterizationEnabled;
readonly attribute WebGPURenderPipelineColorAttachmentDescriptor[] colorAttachments;
attribute WebGPUPixelFormat depthAttachmentPixelFormat;
attribute WebGPUPixelFormat stencilAttachmentPixelFormat;
void reset();
};
interface WebGPURenderPipelineState {
attribute DOMString label;
};
[ Constructor ]
interface WebGPUComputePipelineDescriptor {
attribute DOMString label;
attribute WebGPUFunction computeFunction;
attribute boolean threadGroupSizeIsMultipleOfThreadExecutionWidth;
void reset();
};
interface WebGPUComputePipelineState {
attribute unsigned long maxTotalThreadsPerThreadgroup;
attribute unsigned long threadExecutionWidth;
};
[ Constructor ]
interface WebGPUDepthStencilDescriptor {
attribute DOMString label;
attribute WebGPUCompareFunction depthCompareFunction;
attribute boolean depthWriteEnabled;
attribute WebGPUStencilDescriptor backFaceStencil;
attribute WebGPUStencilDescriptor frontFaceStencil;
};
[ Constructor ]
interface WebGPUStencilDescriptor {
// -- Specifying Stencil Functions and Operations
attribute WebGPUStencilOperation stencilFailureOperation;
attribute WebGPUStencilOperation depthFailureOperation;
attribute WebGPUStencilOperation depthStencilPassOperation;
attribute WebGPUCompareFunction stencilCompareFunction;
// -- Specifying Stencil Bit Mask Properties
attribute unsigned int readMask;
attribute unsigned int writeMask;
}
interface WebGPUDepthStencilState {
attribute DOMString label;
};
interface WebGPUSamplerDescriptor {
attribute WebGPUSamplerAddressMode rAddressMode;
attribute WebGPUSamplerAddressMode sAddressMode;
attribute WebGPUSamplerAddressMode tAddressMode;
attribute WebGPUSamplerMinMagFilter minFilter;
attribute WebGPUSamplerMinMagFilter magFilter;
attribute WebGPUSamplerMipFilter mipFilter;
attribute float lodMinClamp;
attribute float lodMaxClamp;
attribute boolean lodAverage;
attribute unsigned long maxAnisotropy;
attribute boolean normalizedCoordinates;
attribute WebGPUCompareFunction compareFunction;
attribute DOMString label;
}
interface WebGPUSamplerState {
attribute DOMString label;
};
interface WebGPURenderPassAttachmentDescriptor {
// -- Texture
attribute WebGPUTexture texture;
attribute unsigned long level;
attribute unsigned long slice;
attribute unsigned long depthPlane;
// -- Rendering Pass Actions
attribute WebGPULoadAction loadAction;
attribute WebGPUStoreAction storeAction;
// -- Specifying the Texture to Resolve Multisample Data
attribute WebGPUTexture resolveTexture;
attribute unsigned long resolveLevel;
attribute unsigned long resolveSlice;
attribute unsigned long resolveDepthPlane;
};
interface WebGPURenderPassColorAttachmentDescriptor : WebGPURenderPassAttachmentDescriptor {
attribute float[] clearColor; // @@ should color be a type?
};
interface WebGPURenderPassDepthAttachmentDescriptor : WebGPURenderPassAttachmentDescriptor {
attribute double clearDepth;
attribute WebGPUMultisampleDepthResolveFilter depthResolveFilter;
};
interface WebGPURenderPassStencilAttachmentDescriptor : WebGPURenderPassAttachmentDescriptor {
attribute unsigned long clearStencil;
};
[ Constructor ]
interface WebGPURenderPassDescriptor {
readonly attribute WebGPURenderPassColorAttachmentDescriptor[] colorAttachments;
attribute WebGPURenderPassDepthAttachmentDescriptor depthAttachment;
attribute WebGPURenderPassStencilAttachmentDescriptor stencilAttachment;
attribute WebGPUBuffer visibilityResultBuffer;
};
interface WebGPURenderPipelineColorAttachmentDescriptor {
// -- Pipeline state
attribute WebGPUPixelFormat pixelFormat;
attribute WebGPUColorWriteMask writeMask;
// -- Blending
attribute boolean blendingEnabled;
attribute WebGPUBlendOperation rgbBlendOperation;
attribute WebGPUBlendOperation alphaBlendOperation;
// -- Blend Factors
attribute WebGPUBlendFactor sourceRGBBlendFactor;
attribute WebGPUBlendFactor destinationRGBBlendFactor;
attribute WebGPUBlendFactor sourceAlphaBlendFactor;
attribute WebGPUBlendFactor destinationAlphaBlendFactor;
};
interface WebGPUResource {
readonly attribute WebGPUCPUCacheMode cpuCacheMode;
readonly attribute WebGPUStorageMode storageMode;
readonly attribute DOMString label;
void setPurgeableState(DOMString state);
}
interface WebGPUOrigin {
attribute unsigned long x;
attribute unsigned long y;
attribute unsigned long z;
};
interface WebGPUSize {
attribute unsigned long width;
attribute unsigned long height;
attribute unsigned long depth;
};
interface WebGPURegion {
attribute WebGPUOrigin origin;
attribute WebGPUSize size;
}
interface WebGPUTexture : WebGPUResource {
// @@ need API to provide data from <img>, <canvas>, <video> etc
// -- Copying Data into a Texture Image
void replaceRegion(WebGPURegion region, unsigned long mipmapLevel, unsigned long slice,
ArrayBufferView bytes, unsigned long bytesPerRow,
unsigned long bytesPerImage);
void replaceRegion(WebGPURegion region, unsigned long mipmapLevel,
ArrayBufferView bytes, unsigned long bytesPerRow);
// -- Copying Data from a Texture Image
ArrayBufferView getBytes(unsigned long bytesPerRow, unsigned long bytesPerImage,
WebGPURegion region, unsigned long mipmapLevel, unsigned long slice);
// -- Creating Textures by Reusing Image Data
WebGPUTexture newTextureView(DOMString pixelFormat, DOMString textureType,
WebGPURange levelRange, WebGPURange sliceRange);
// -- Querying Texture Attributes
readonly attribute DOMString textureType;
readonly attribute DOMString pixelFormat;
readonly attribute unsigned long width;
readonly attribute unsigned long height;
readonly attribute unsigned long depth;
readonly attribute unsigned long mipmapLevelCount;
readonly attribute unsigned long arrayLength;
readonly attribute unsigned long sampleCount;
readonly attribute boolean framebufferOnly;
readonly attribute WebGPUResource rootResource;
readonly attribute WebGPUTextureUsage usage;
// -- Querying Parent Texture Attributes
readonly attribute WebGPUTexture parentTexture;
readonly attribute unsigned long parentRelativeLevel;
readonly attribute unsigned long parentRelativeSlice;
// -- Querying Source Buffer Attributes
readonly attribute WebGPUBuffer buffer;
readonly attribute unsigned long bufferOffset;
readonly attribute unsigned long bufferBytesPerRow;
};
[ Constructor ]
interface WebGPUTextureDescriptor {
attribute DOMString textureType;
attribute DOMString pixelFormat;
attribute unsigned long width;
attribute unsigned long height;
attribute unsigned long depth;
attribute unsigned long mipmapLevelCount;
attribute unsigned long sampleCount;
attribute unsigned long arrayCount;
attribute WebGPUResourceOptions resourceOptions;
attribute WebGPUCPUCacheMode cpuCacheMode;
attribute WebGPUStorageMode storageMode;
attribute WebGPUTextureUsage usage;
};
interface WebGPUBuffer : WebGPUResource {
WebGPUTexture createTexture(WebGPUTextureDescriptor descriptor,
unsigned long offset, unsigned long bytesPerRow);
readonly attribute unsigned long length;
readonly attribute ArrayBufferView contents;
};
interface WebGPULibrary {
readonly attribute DOMString sourceCode;
attribute DOMString label;
readonly attribute DOMString[] functionNames;
WebGPUFunction functionWithName(DOMString name);
};
interface WebGPUFunction {
readonly attribute DOMString name;
readonly attribute WebGPUFunctionType functionType;
readonly attribute WebGPUVertexAttributes[] vertexAttributes;
};
enum WebGPUCompareFunction {
"never",
"less",
"equal",
"lessequal",
"greater",
"notequal",
"greaterequal",
"always"
};
enum WebGPUPixelFormat {
"BGRA8Unorm",
etc
};
enum WebGPULoadAction {
"dontcare",
"load",
"clear"
};
enum WebGPUStoreAction {
"dontcare",
"store",
"multisampleresolve"
};
enum WebGPUPrimitiveType {
"point",
"line",
"linestrip",
"triangle",
"trianglestrip"
};
enum WebGPUFunctionType {
"fragment",
"vertex"
};
enum WebGPUStencilOperation {
"keep",
"zero",
"replace",
"incrementclamp",
"decrementclamp",
"invert",
"incrementwrap",
"decrementwrap"
};
enum WebGPUStatus {
"notenqueued",
"enqueued",
"committed",
"scheduled",
"completed",
"error"
};
enum WebGPUSamplerAddressMode {
"clamptoedge",
"mirrorclamptoedge",
"repeat",
"mirrorrepeat",
"clamptozero"
};
enum WebGPUSamplerMinMagFilter {
"nearest",
"linear"
};
enum WebGPUSamplerMipFilter {
"notmipmapped",
"nearest",
"linear"
};
enum WebGPUCullMode {
"none",
"front",
"back"
};
enum WebGPUIndexType {
"uint16",
"uint32"
};
enum WebGPUVisibilityResultMode {
"disabled",
"boolean",
"counting"
};
enum WebGPUWinding {
"clockwise",
"counterclockwise"
};
enum WebGPUDepthClipMode {
"clip",
"clamp"
};
enum WebGPUTriangleFillMode {
"fill",
"lines"
};
enum WebGPUCPUCacheMode {
"defaultcache",
"writecombined"
};
enum WebGPUStorageMode {
"shared",
"managed",
"private"
};
enum WebGPUResourceOptions {
"cpucachemodedefaultcache",
"cpucachemodewritecombined",
"storagemodeshared",
"storagemodemanaged",
"storagemodeprivate",
"optioncpucachemodedefaultcache",
"optioncpucachemodewritecombined"
};
enum WebGPUTextureUsage {
"unknown",
"shaderread",
"shaderwrite",
"rendertarget",
"pixelformatview"
};
enum WebGPUBlendOperation {
"add",
"subtract",
"reversesubtract",
"min",
"max"
};
enum WebGPUBlendFactor {
"zero",
"one",
"sourcecolor",
"oneminussourcecolor",
"sourcealpha",
"oneminussourcealpha",
"destinationcolor",
"oneminusdestinationcolor",
"destinationalpha",
"oneminusdestinationalpha",
"sourcealphasaturated",
"blendcolor",
"oneminusblendcolor",
"blendalpha",
"oneminusblendalpha",
};
enum WebGPUColorWriteMask {
// This is a mask, so the calling site
// should take an array of them.
"none",
"red",
"green",
"blue",
"alpha",
"all"
}
enum WebGPUMultisampleDepthResolveFilter {
"sample0",
"min",
"max"
};
enum WebGPUFeatureSet {
// some names like...
"level1",
"level2"
};
WebGPU 接受 Metal Shading Language 的一种变体,称为 WebGPU 着色语言。
从标准 Metal 到 WebGPU 语言的高级变化包括
buffer<T>
类型。此类型表现得像数组,但会重写索引访问以禁止越界访问。最终,WebGPU 将接受某种 IR 格式的着色器,类似于 DXIL 或 SPIR-V。目前尚不清楚是否会有一种人类可读的着色格式。
绘制三角形
let canvas = document.querySelector("canvas");
canvas.width = 500;
canvas.height = 500;
let gpu = canvas.getContext("Webgpu");
let library = gpu.createLibrary(loadShaderFromScript("library"));
library.label = "Example label";
let vertexF = library.functionWithName("vertex_main");
let fragmentF = library.functionWithName("fragment_main");
let vertexData = new Float32Array([
// x y z 1 r g b 1
0, 0.75, 0, 1, 1, 0, 0, 1,
-0.75, -0.75, 0, 1, 0, 1, 0, 1,
0.75, -0.75, 0, 1, 0, 0, 1, 1
]);
let vertexBuffer = gpu.createBuffer(vertexData);
let pipelineDescriptor = new WebGPURenderPipelineDescriptor();
pipelineDescriptor.vertexFunction = vertexF;
pipelineDescriptor.fragmentFunction = fragmentF;
pipelineDescriptor.colorAttachments[0].pixelFormat = "BGRA8Unorm";
let pipelineState = gpu.createRenderPipelineState(pipelineDescriptor);
let drawable = gpu.nextDrawable();
let passDescriptor = new WebGPURenderPassDescriptor();
passDescriptor.colorAttachments[0].loadAction = "clear";
passDescriptor.colorAttachments[0].storeAction = "store";
passDescriptor.colorAttachments[0].clearColor = [0.8, 0.8, 0.8, 1.0];
passDescriptor.colorAttachments[0].texture = drawable.texture;
let commandQueue = gpu.createCommandQueue();
let commandBuffer = commandQueue.createCommandBuffer();
let commandEncoder = commandBuffer.createRenderCommandEncoder(passDescriptor);
commandEncoder.setRenderPipelineState(pipelineState);
commandEncoder.setVertexBuffer(vertexBuffer, 0, 0);
commandEncoder.drawPrimitives("triangle", 0, 3);
commandEncoder.endEncoding();
commandBuffer.presentDrawable(drawable);
commandBuffer.commit();
更新 uniforms
// Setup
let uniformData = new Float32Array([ 0.5 ]);
let uniformBuffer = gpu.createBuffer(uniformData);
// Each frame
let uniformBufferView = new Float32Array(uniformBuffer.contents);
uniformBufferView[0] = frameId * 10; // Some per-frame value
let commandEncoder = commandBuffer.createRenderCommandEncoder(passDescriptor);
commandEncoder.setRenderPipelineState(pipelineState);
commandEncoder.setVertexBuffer(vertexBuffer, 0, 0);
commandEncoder.setVertexBuffer(uniformBuffer, 0, 1);
commandEncoder.drawPrimitives("triangle", 0, 3);
commandEncoder.endEncoding();
commandBuffer.presentDrawable(drawable);
commandBuffer.commit();