{"id":20461389,"url":"https://github.com/antvis/g-device-api","last_synced_at":"2025-04-13T06:17:46.782Z","repository":{"id":194626075,"uuid":"691026415","full_name":"antvis/g-device-api","owner":"antvis","description":"A Device API references WebGPU implementations","archived":false,"fork":false,"pushed_at":"2024-12-18T08:37:54.000Z","size":4047,"stargazers_count":22,"open_issues_count":4,"forks_count":5,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-04-10T18:49:04.962Z","etag":null,"topics":["hardware-abstraction-layer","webgl","webgpu"],"latest_commit_sha":null,"homepage":"https://observablehq.com/@antv/g-device-api","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/antvis.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-09-13T11:04:02.000Z","updated_at":"2025-04-07T11:25:33.000Z","dependencies_parsed_at":"2023-11-06T17:55:51.325Z","dependency_job_id":"1a1090df-52e8-41c5-b2e2-10bb2cc7ca95","html_url":"https://github.com/antvis/g-device-api","commit_stats":{"total_commits":117,"total_committers":4,"mean_commits":29.25,"dds":"0.10256410256410253","last_synced_commit":"f5aea083fa23b0f293eab27264294e61c4c83a6f"},"previous_names":["strawberry-vis/g-device-api","berry-vis/g-device-api"],"tags_count":51,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antvis%2Fg-device-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antvis%2Fg-device-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antvis%2Fg-device-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antvis%2Fg-device-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/antvis","download_url":"https://codeload.github.com/antvis/g-device-api/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248329707,"owners_count":21085589,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hardware-abstraction-layer","webgl","webgpu"],"created_at":"2024-11-15T12:25:09.002Z","updated_at":"2025-04-13T06:17:46.749Z","avatar_url":"https://github.com/antvis.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @antv/g-device-api\n\nThis is a set of Device API also known as the hardware adaptation layer(HAL).\nIt is implemented using WebGL1/2 \u0026 WebGPU underneath and inspired by [noclip](https://github.com/magcius/noclip.website).\n\n[![Build Status](https://github.com/antvis/g-device-api/actions/workflows/build.yml/badge.svg)](https://github.com/antvis/g-device-api/actions/workflows/build.yml)\n[![Coverage Status](https://coveralls.io/repos/github/antvis/g-device-api/badge.svg)](https://coveralls.io/github/antvis/g-device-api?branch=master)\n[![npm Version](https://img.shields.io/npm/v/@antv/g-device-api.svg)](https://www.npmjs.com/package/@antv/g-device-api)\n[![npm Download](https://img.shields.io/npm/dm/@antv/g-device-api.svg)](https://www.npmjs.com/package/@antv/g-device-api)\n[![npm License](https://img.shields.io/npm/l/@antv/g-device-api.svg)](https://www.npmjs.com/package/@antv/g-device-api)\n\n-   [API](#api)\n-   [Shader Language](#shader-language)\n-   [Observable Examples](https://observablehq.com/@antv/g-device-api)\n    -   [Compute Toys](https://observablehq.com/d/0361c83b691a32b5)\n-   [Limitations](#limitations)\n\nNow we use it in the following projects:\n\n-   [g-webgl](https://github.com/antvis/G) \u0026 [g-webgpu](https://github.com/antvis/G) Used in G2 \u0026 G6 3D plots.\n-   [L7](https://github.com/antvis/L7) Large-scale WebGL-powered Geospatial Data Visualization analysis engine.\n-   [A8](https://github.com/antvis/A8) An audio visualizer.\n-   [renderer](https://github.com/xiaoiver/renderer) A toy renderer inspired by bevy.\n\n## Installing\n\n```bash\nnpm install @antv/g-device-api\n```\n\n## \u003ca id='api' /\u003eAPI Reference\n\n-   [Create a device](#createDevice)\n-   Resource Creation\n\n    -   [createBuffer](#createBuffer)\n    -   [createTexture](#createTexture)\n    -   [createSampler](#createSampler)\n    -   [createRenderTarget](#createRenderTarget)\n    -   [createRenderTargetFromTexture](#createRenderTargetFromTexture)\n    -   [createProgram](#createProgram)\n    -   [createBindings](#createBindings)\n    -   [createInputLayout](#createInputLayout)\n    -   [createRenderPipeline](#createRenderPipeline)\n    -   [createComputePipeline](#createComputePipeline)\n    -   [createReadback](#createReadback)\n    -   [createQueryPool](#createQueryPool)\n    -   [createRenderPass](#createRenderPass)\n    -   [createComputePass](#createComputePass)\n    -   [createRenderBundle](#createRenderBundle)\n\n-   Submit\n    -   [beignFrame](#beginFrame)\n    -   [submitPass](#submitPass)\n    -   [endFrame](#endFrame)\n    -   [copySubTexture2D](#copySubTexture2D)\n-   Query\n    -   [queryLimits](#queryLimits)\n    -   [queryTextureFormatSupported](#queryTextureFormatSupported)\n    -   [queryPlatformAvailable](#queryPlatformAvailable)\n    -   [queryVendorInfo](#queryVendorInfo)\n-   Debug\n\n    -   [setResourceName](#setResourceName)\n    -   [checkForLeaks](#checkForLeaks)\n    -   [pushDebugGroup](#pushDebugGroup)\n    -   [popDebugGroup](#popDebugGroup)\n\n-   GPU Resources\n    -   [Buffer](#buffer)\n        -   [setSubData](#setSubData)\n    -   [Texture](#texture)\n        -   [setImageData](#setImageData)\n    -   [Sampler](#sampler)\n    -   [RenderTarget](#renderTarget)\n    -   [RenderPass](#renderPass)\n        -   [setViewport](#setViewport)\n        -   [setScissorRect](#setScissorRect)\n        -   [setPipeline](#setPipeline)\n        -   [setBindings](#setBindings)\n        -   [setVertexInput](#setVertexInput)\n        -   [setStencilReference](#setStencilReference)\n        -   [draw](#draw)\n        -   [drawIndexed](#drawIndexed)\n        -   [drawIndirect](#drawIndirect)\n        -   [drawIndexedIndirect](#drawIndexedIndirect)\n        -   [beginOcclusionQuery](#beginOcclusionQuery)\n        -   [endOcclusionQuery](#endOcclusionQuery)\n        -   [beginBundle](#beginBundle)\n        -   [endBundle](#endBundle)\n        -   [executeBundles](#executeBundles)\n    -   [ComputePass](#computePass)\n        -   [setPipeline](#setPipeline)\n        -   [setBindings](#setBindings)\n        -   [dispatchWorkgroups](#dispatchWorkgroups)\n        -   [dispatchWorkgroupsIndirect](#dispatchWorkgroupsIndirect)\n    -   Program\n        -   [setUniformsLegacy](#setUniformsLegacy)\n    -   QueryPool\n        -   queryResultOcclusion\n    -   [Readback](#readback)\n        -   [readTexture](#readTexture)\n        -   [readTextureSync](#readTextureSync)\n        -   [readBuffer](#readBuffer)\n\n### \u003ca id='createDevice' /\u003eCreate Device\n\nA device is the logical instantiation of GPU.\n\n```js\nimport {\n    Device,\n    BufferUsage,\n    WebGLDeviceContribution,\n    WebGPUDeviceContribution,\n} from '@antv/g-device-api';\n\n// Create a WebGL based device contribution.\nconst deviceContribution = new WebGLDeviceContribution({\n    targets: ['webgl2', 'webgl1'],\n});\n// Or create a WebGPU based device contribution.\nconst deviceContribution = new WebGPUDeviceContribution({\n    shaderCompilerPath: '/glsl_wgsl_compiler_bg.wasm',\n    // shaderCompilerPath:\n    //   'https://unpkg.com/@antv/g-device-api@1.4.9/rust/pkg/glsl_wgsl_compiler_bg.wasm',\n});\n\nconst swapChain = await deviceContribution.createSwapChain($canvas);\nswapChain.configureSwapChain(width, height);\nconst device = swapChain.getDevice();\n```\n\n### \u003ca id=\"createBuffer\" /\u003ecreateBuffer\n\nA [Buffer](#buffer) represents a block of memory that can be used in GPU operations. Data is stored in linear layout.\n\nWe references the [WebGPU design](https://www.w3.org/TR/webgpu/#dom-gpudevice-createbuffer):\n\n```ts\ncreateBuffer: (descriptor: BufferDescriptor) =\u003e Buffer;\n```\n\nThe parameters are as follows, references the [WebGPU design](https://www.w3.org/TR/webgpu/#GPUBufferDescriptor):\n\n-   viewOrSize `required` Set buffer data directly or allocate fixed length(in bytes).\n-   usage `required` The allowed usage for this buffer.\n-   hint `optional` Known as hint when calling [bufferData](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/bufferData#usage) in WebGL.\n\n```ts\ninterface BufferDescriptor {\n    viewOrSize: ArrayBufferView | number;\n    usage: BufferUsage;\n    hint?: BufferFrequencyHint;\n}\n```\n\nWe can set buffer data directly, or allocate fixed length for later use e.g. calling [setSubData](#setSubData):\n\n```ts\nconst buffer = device.createBuffer({\n    viewOrSize: new Float32Array([1, 2, 3, 4]),\n    usage: BufferUsage.VERTEX,\n});\n\n// or\nconst buffer = device.createBuffer({\n    viewOrSize: 4 * Float32Array.BYTES_PER_ELEMENT, // in bytes\n    usage: BufferUsage.VERTEX,\n});\nbuffer.setSubData(0, new Uint8Array(new Float32Array([1, 2, 3, 4]).buffer));\n```\n\nThe allowed [usage](https://www.w3.org/TR/webgpu/#dom-gpubuffer-usage) for buffer.\nThey can also be composited like `BufferUsage.VERTEX | BufferUsage.STORAGE`.\n\n```ts\nenum BufferUsage {\n    MAP_READ = 0x0001,\n    MAP_WRITE = 0x0002,\n    COPY_SRC = 0x0004,\n    COPY_DST = 0x0008,\n    INDEX = 0x0010,\n    VERTEX = 0x0020,\n    UNIFORM = 0x0040,\n    STORAGE = 0x0080,\n    INDIRECT = 0x0100,\n    QUERY_RESOLVE = 0x0200,\n}\n```\n\nThis param is called [usage](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/bufferData#usage) in WebGL. We change its name to `hint` avoiding duplicate naming.\n\n```ts\nenum BufferFrequencyHint {\n    Static = 0x01,\n    Dynamic = 0x02,\n}\n```\n\n### \u003ca id=\"createTexture\" /\u003ecreateTexture\n\nThis method references the [WebGPU design](https://developer.mozilla.org/en-US/docs/Web/API/GPUDevice/createTexture) to create a [Texture](#texture):\n\n```ts\ncreateTexture: (descriptor: TextureDescriptor) =\u003e Texture;\n```\n\nThe parameters are as follows, references the [WebGPU design](https://www.w3.org/TR/webgpu/#GPUBufferDescriptor):\n\n```ts\ninterface TextureDescriptor {\n    usage: TextureUsage;\n    format: Format;\n    width: number;\n    height: number;\n    depthOrArrayLayers?: number;\n    dimension?: TextureDimension;\n    mipLevelCount?: number;\n    pixelStore?: Partial\u003c{\n        packAlignment: number;\n        unpackAlignment: number;\n        unpackFlipY: boolean;\n    }\u003e;\n}\n```\n\n-   usage `required` The allowed usages for this GPUTexture.\n-   format `required` The format of this GPUTexture.\n-   width `required` The width of this GPUTexture.\n-   height `required` The height of this GPUTexture.\n-   depthOrArrayLayers `optional` The depth or layer count of this GPUTexture. Defaulting to `1`.\n-   dimension `optional` The dimension of the set of texel for each of this GPUTexture's subresources. Defaulting to `TextureDimension.TEXTURE_2D`\n-   mipLevelCount `optional` The number of mip levels of this GPUTexture. Defaulting to `1`.\n-   pixelStore `optional` Specifies the [pixel storage modes](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/pixelStorei) in WebGL.\n    -   packAlignment Packing of pixel data into memory. `gl.PACK_ALIGNMENT`\n    -   unpackAlignment Unpacking of pixel data from memory. `gl.UNPACK_ALIGNMENT`\n    -   unpackFlipY Flips the source data along its vertical axis if true. `gl.UNPACK_FLIP_Y_WEBGL`\n\nThe `TextureUsage` enum is as follows:\n\n```ts\nenum TextureUsage {\n    SAMPLED,\n    RENDER_TARGET, // When rendering to texture, choose this usage.\n}\n```\n\nThe `TextureDimension` enum is as follows:\n\n```ts\nenum TextureDimension {\n    TEXTURE_2D,\n    TEXTURE_2D_ARRAY,\n    TEXTURE_3D,\n    TEXTURE_CUBE_MAP,\n}\n```\n\n### \u003ca id=\"createSampler\" /\u003ecreateSampler\n\n[Samplers](#sampler) are created via `createSampler()`.\n\n```ts\ncreateSampler: (descriptor: SamplerDescriptor) =\u003e Sampler;\n```\n\nThe params reference [GPUSamplerDescriptor](https://www.w3.org/TR/webgpu/#dictdef-gpusamplerdescriptor).\n\n```ts\ninterface SamplerDescriptor {\n    addressModeU: AddressMode;\n    addressModeV: AddressMode;\n    addressModeW?: AddressMode;\n    minFilter: FilterMode;\n    magFilter: FilterMode;\n    mipmapFilter: MipmapFilterMode;\n    lodMinClamp?: number;\n    lodMaxClamp?: number;\n    maxAnisotropy?: number;\n    compareFunction?: CompareFunction;\n}\n```\n\n`AddressMode` describes the behavior of the sampler if the sample footprint extends beyond the bounds of the sampled texture.\n\n```ts\nenum AddressMode {\n    CLAMP_TO_EDGE,\n    REPEAT,\n    MIRRORED_REPEAT,\n}\n```\n\n`FilterMode` and `MipmapFilterMode` describe the behavior of the sampler if the sample footprint does not exactly match one texel.\n\n```ts\nenum FilterMode {\n    POINT,\n    BILINEAR,\n}\nenum MipmapFilterMode {\n    NO_MIP,\n    NEAREST,\n    LINEAR,\n}\n```\n\n`CompareFunction` specifies the behavior of a comparison sampler. If a comparison sampler is used in a shader, an input value is compared to the sampled texture value, and the result of this comparison test (0.0f for pass, or 1.0f for fail) is used in the filtering operation.\n\n```ts\nenum CompareFunction {\n    NEVER = GL.NEVER,\n    LESS = GL.LESS,\n    EQUAL = GL.EQUAL,\n    LEQUAL = GL.LEQUAL,\n    GREATER = GL.GREATER,\n    NOTEQUAL = GL.NOTEQUAL,\n    GEQUAL = GL.GEQUAL,\n    ALWAYS = GL.ALWAYS,\n}\n```\n\n### \u003ca id=\"createRenderTarget\" /\u003ecreateRenderTarget\n\n```ts\ncreateRenderTarget: (descriptor: RenderTargetDescriptor) =\u003e RenderTarget;\n```\n\n```ts\ninterface RenderTargetDescriptor {\n    format: Format;\n    width: number;\n    height: number;\n    sampleCount: number;\n    texture?: Texture;\n}\n```\n\n### \u003ca id=\"createRenderTargetFromTexture\" /\u003ecreateRenderTargetFromTexture\n\n```ts\ncreateRenderTargetFromTexture: (texture: Texture) =\u003e RenderTarget;\n```\n\n### \u003ca id=\"createProgram\" /\u003ecreateProgram\n\n```ts\ncreateProgram: (program: ProgramDescriptor) =\u003e Program;\n```\n\n`wgsl` will be used directly in WebGPU while `glsl` will be compiled internally.\nSince WebGL doesn't support compute shader, `compute` is only available in WebGPU.\n\n```ts\ninterface ProgramDescriptor {\n    vertex?: {\n        glsl?: string;\n        wgsl?: string;\n    };\n    fragment?: {\n        glsl?: string;\n        wgsl?: string;\n    };\n    compute?: {\n        wgsl: string;\n    };\n}\n```\n\n### \u003ca id=\"createBindings\" /\u003ecreateBindings\n\n```ts\ncreateBindings: (bindingsDescriptor: BindingsDescriptor) =\u003e Bindings;\n```\n\n```ts\ninterface BindingsDescriptor {\n    bindingLayout: BindingLayoutDescriptor;\n    pipeline?: RenderPipeline | ComputePipeline;\n    uniformBufferBindings?: BufferBinding[];\n    samplerBindings?: SamplerBinding[];\n    storageBufferBindings?: BufferBinding[];\n    storageTextureBindings?: TextureBinding[];\n}\n```\n\n`BufferBinding` has the following properties:\n\n-   binding `required` Should match the `binding` in shader.\n-   buffer `required`\n-   offset `optional` The offset, in bytes, from the beginning of buffer to the beginning of the range exposed to the shader by the buffer binding. Defaulting to `0`.\n-   size `optional` The size, in bytes, of the buffer binding. If not provided, specifies the range starting at offset and ending at the end of buffer.\n\n```ts\ninterface BufferBinding {\n    binding: number;\n    buffer: Buffer;\n    offset?: number;\n    size?: number;\n}\n```\n\n### \u003ca id=\"createInputLayout\" /\u003ecreateInputLayout\n\n`InputLayout` defines the layout of vertex attribute data in a vertex buffer used by pipeline.\n\n```ts\ncreateInputLayout: (inputLayoutDescriptor: InputLayoutDescriptor) =\u003e\n    InputLayout;\n```\n\nA vertex buffer is, conceptually, a view into buffer memory as an array of structures. `arrayStride` is the stride, in bytes, between elements of that array. Each element of a vertex buffer is like a structure with a memory layout defined by its attributes, which describe the members of the structure.\n\n```ts\ninterface InputLayoutDescriptor {\n    vertexBufferDescriptors: (InputLayoutBufferDescriptor | null)[];\n    indexBufferFormat: Format | null;\n    program: Program;\n}\n\ninterface InputLayoutBufferDescriptor {\n    arrayStride: number; // in bytes\n    stepMode: VertexStepMode; // per vertex or instance\n    attributes: VertexAttributeDescriptor[];\n}\n\ninterface VertexAttributeDescriptor {\n    shaderLocation: number;\n    format: Format;\n    offset: number;\n    divisor?: number;\n}\n```\n\n-   shaderLocation `required` The numeric location associated with this attribute, which will correspond with a \"@location\" attribute declared in the vertex.module.\n-   format `required` The VertexFormat of the attribute.\n-   offset `required` The offset, in bytes, from the beginning of the element to the data for the attribute.\n-   divisor `optional`\n\n### \u003ca id=\"createReadback\" /\u003ecreateReadback\n\nCreate a Readback to read GPU resouce's data from CPU side:\n\n```ts\ncreateReadback: () =\u003e Readback;\n```\n\n```ts\nreadBuffer: (\n    b: Buffer,\n    srcByteOffset?: number,\n    dst?: ArrayBufferView,\n    dstOffset?: number,\n    length?: number,\n) =\u003e Promise\u003cArrayBufferView\u003e;\n```\n\n```ts\nconst readback = device.createReadback();\nreadback.readBuffer(buffer);\n```\n\n### \u003ca id=\"createQueryPool\" /\u003ecreateQueryPool\n\nOnly WebGL 2 \u0026 WebGPU support:\n\n```ts\ncreateQueryPool: (type: QueryPoolType, elemCount: number) =\u003e QueryPool;\n```\n\n```ts\nqueryResultOcclusion(dstOffs: number): boolean | null\n```\n\n### \u003ca id=\"createRenderPipeline\" /\u003ecreateRenderPipeline\n\nA `RenderPipeline` is a kind of pipeline that controls the vertex and fragment shader stages.\n\n```ts\ncreateRenderPipeline: (descriptor: RenderPipelineDescriptor) =\u003e RenderPipeline;\n```\n\nThe descriptor is as follows:\n\n-   colorAttachmentFormats `required` The formats of color attachment.\n-   topology `optional` The type of primitive to be constructed from the vertex inputs. Defaulting to `TRIANGLES`:\n-   megaStateDescriptor `optional`\n-   depthStencilAttachmentFormat `optional` The format of depth \u0026 stencil attachment.\n-   sampleCount `optional` Used in MSAA, defaulting to `1`.\n\n```ts\ninterface RenderPipelineDescriptor extends PipelineDescriptor {\n    topology?: PrimitiveTopology;\n    megaStateDescriptor?: MegaStateDescriptor;\n    colorAttachmentFormats: (Format | null)[];\n    depthStencilAttachmentFormat?: Format | null;\n    sampleCount?: number;\n}\n```\n\n```ts\nenum PrimitiveTopology {\n    POINTS,\n    TRIANGLES,\n    TRIANGLE_STRIP,\n    LINES,\n    LINE_STRIP,\n}\n```\n\n```ts\ninterface MegaStateDescriptor {\n    attachmentsState: AttachmentState[];\n    blendConstant?: Color;\n    depthCompare?: CompareFunction;\n    depthWrite?: boolean;\n    stencilFront?: Partial\u003cStencilFaceState\u003e;\n    stencilBack?: Partial\u003cStencilFaceState\u003e;\n    stencilWrite?: boolean;\n    cullMode?: CullMode;\n    frontFace?: FrontFace;\n    polygonOffset?: boolean;\n    polygonOffsetFactor?: number;\n    polygonOffsetUnits?: number;\n}\n```\n\n### \u003ca id=\"createComputePipeline\" /\u003ecreateComputePipeline\n\n```ts\ncreateComputePipeline: (descriptor: ComputePipelineDescriptor) =\u003e\n    ComputePipeline;\n```\n\n```ts\ntype ComputePipelineDescriptor = PipelineDescriptor;\ninterface PipelineDescriptor {\n    bindingLayouts: BindingLayoutDescriptor[];\n    inputLayout: InputLayout | null;\n    program: Program;\n}\n```\n\n### \u003ca id=\"createRenderPass\" /\u003ecreateRenderPass\n\nA RenderPass is usually created at the beginning of each frame.\n\n```ts\ncreateRenderPass: (renderPassDescriptor: RenderPassDescriptor) =\u003e RenderPass;\n```\n\n```ts\nexport interface RenderPassDescriptor {\n    colorAttachment: (RenderTarget | null)[];\n    colorAttachmentLevel?: number[];\n    colorClearColor?: (Color | 'load')[];\n    colorResolveTo: (Texture | null)[];\n    colorResolveToLevel?: number[];\n    colorStore?: boolean[];\n    depthStencilAttachment?: RenderTarget | null;\n    depthStencilResolveTo?: Texture | null;\n    depthStencilStore?: boolean;\n    depthClearValue?: number | 'load';\n    stencilClearValue?: number | 'load';\n    occlusionQueryPool?: QueryPool | null;\n}\n```\n\n### \u003ca id=\"createComputePass\" /\u003ecreateComputePass\n\n⚠️Only WebGPU support.\n\n```ts\ncreateComputePass: () =\u003e ComputePass;\n```\n\n### \u003ca id=\"createRenderBundle\" /\u003ecreateRenderBundle\n\nRenderBundle can record the draw calls during one frame and replay this recording for all subsequent frames.\n\n```ts\nconst renderBundle = device.createRenderBundle();\n\n// On each frame.\nif (frameCount === 0) {\n    renderPass.beginBundle(renderBundle);\n    // Omit other renderpass commands\n    renderPass.endBundle();\n} else {\n    renderPass.executeBundles([renderBundle]);\n}\n```\n\n### \u003ca id=\"beginFrame\" /\u003ebeginFrame\n\nShould call this method at the beginning of each frame.\n\n```ts\ndevice.beginFrame();\nconst renderPass = device.createRenderPass({});\n// Omit other commands.\nrenderPass.draw();\ndevice.submitPass(renderPass);\ndevice.endFrame();\n```\n\n### \u003ca id=\"submitPass\" /\u003esubmitPass\n\nSchedules the execution of the command buffers by the GPU on this queue.\n\n```ts\nsubmitPass(o: RenderPass | ComputePass): void;\n```\n\n### \u003ca id=\"endFrame\" /\u003eendFrame\n\nShould call this method at the end of each frame.\n\n### \u003ca id=\"copySubTexture2D\" /\u003ecopySubTexture2D\n\n```ts\ncopySubTexture2D: (\n  dst: Texture,\n  dstX: number,\n  dstY: number,\n  src: Texture,\n  srcX: number,\n  srcY: number,\n  depthOrArrayLayers?: number,\n) =\u003e void;\n```\n\n-   ⚠️WebGL 1 not supported\n-   WebGL 2 uses [blitFramebuffer](https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/blitFramebuffer)\n-   WebGPU uses [copyTextureToTexture](https://developer.mozilla.org/en-US/docs/Web/API/GPUCommandEncoder/copyTextureToTexture)\n\n### \u003ca id=\"queryLimits\" /\u003equeryLimits\n\n```ts\n// @see https://www.w3.org/TR/webgpu/#gpusupportedlimits\nqueryLimits: () =\u003e DeviceLimits;\n```\n\n```ts\ninterface DeviceLimits {\n    uniformBufferWordAlignment: number;\n    uniformBufferMaxPageWordSize: number;\n    supportedSampleCounts: number[];\n    occlusionQueriesRecommended: boolean;\n    computeShadersSupported: boolean;\n}\n```\n\n### \u003ca id=\"queryPlatformAvailable\" /\u003equeryPlatformAvailable\n\nQuery whether device's context is already lost:\n\n```ts\nqueryPlatformAvailable(): boolean\n```\n\nWebGL / WebGPU will trigger Lost event:\n\n```ts\ndevice.queryPlatformAvailable(); // false\n```\n\n### \u003ca id=\"queryTextureFormatSupported\" /\u003equeryTextureFormatSupported\n\n```ts\nqueryTextureFormatSupported(format: Format, width: number, height: number): boolean;\n```\n\n```ts\nconst shadowsSupported = device.queryTextureFormatSupported(\n    Format.U16_RG_NORM,\n    0,\n    0,\n);\n```\n\n### \u003ca id=\"queryVendorInfo\" /\u003equeryVendorInfo\n\nWebGL 1/2 \u0026 WebGPU use different origin:\n\n```ts\nqueryVendorInfo: () =\u003e VendorInfo;\n```\n\n```ts\ninterface VendorInfo {\n    readonly platformString: string;\n    readonly glslVersion: string;\n    readonly explicitBindingLocations: boolean;\n    readonly separateSamplerTextures: boolean;\n    readonly viewportOrigin: ViewportOrigin;\n    readonly clipSpaceNearZ: ClipSpaceNearZ;\n    readonly supportMRT: boolean;\n}\n```\n\n### \u003ca id=\"setResourceName\" /\u003esetResourceName\n\nWhen using Spector.js to debug our application, we can set a name to relative GPU resource.\n\n```ts\nsetResourceName: (o: Resource, s: string) =\u003e void;\n```\n\nFor instance, we add a label for RT and Spector.js will show us the metadata:\n\n```ts\ndevice.setResourceName(renderTarget, 'Main Render Target');\n```\n\n\u003cimg width=\"1130\" alt=\"spector.js metadata\" src=\"https://github.com/antvis/G/assets/3608471/b4c5b519-27c3-4bea-8f76-624169d3f130\"\u003e\n\nOn WebGPU devtools we can also see the label:\n\u003cimg width=\"761\" alt=\"webgpu devtools label\" src=\"https://github.com/antvis/G/assets/3608471/7e4a4513-a1e0-4f98-ab06-468b794d66b8\"\u003e\n\n### \u003ca id=\"checkForLeaks\" /\u003echeckForLeaks\n\nChecks if there is currently a leaking GPU resource. We keep track of every GPU resource object created, and calling this method prints the currently undestroyed object and the stack information where the resource was created on the console, making it easy to troubleshoot memory leaks.\n\nIt is recommended to call this when destroying the scene to determine if there are resources that have not been destroyed correctly. For example, in the image below, there is a WebGL Buffer that has not been destroyed:\n\n\u003cimg width=\"879\" alt=\"check for leaks\" src=\"https://github.com/antvis/G/assets/3608471/8a0b3c2f-f267-4e72-a8a1-758cd0728dcb\"\u003e\n\nWe should call `buffer.destroy()` at this time to avoid OOM.\n\n### \u003ca id=\"pushDebugGroup\" /\u003epushDebugGroup\n\n\u003chttps://developer.mozilla.org/en-US/docs/Web/API/GPUCommandEncoder/pushDebugGroup\u003e\n\n```ts\npushDebugGroup(debugGroup: DebugGroup): void;\n```\n\n```ts\ninterface DebugGroup {\n    name: string;\n    drawCallCount: number;\n    textureBindCount: number;\n    bufferUploadCount: number;\n    triangleCount: number;\n}\n```\n\n### \u003ca id=\"popDebugGroup\" /\u003epopDebugGroup\n\n\u003chttps://developer.mozilla.org/en-US/docs/Web/API/GPUCommandEncoder/popDebugGroup\u003e\n\n## \u003ca id=\"buffer\" /\u003eBuffer\n\nA Buffer represents a block of memory that can be used in GPU operations. Data is stored in linear layout.\n\n### \u003ca id=\"setSubData\" /\u003esetSubData\n\nWe can set data in buffer with this method:\n\n-   dstByteOffset `required` Offset of dest buffer in bytes.\n-   src `required` Source buffer data, must use Uint8Array.\n-   srcByteOffset `optional` Offset of src buffer in bytes. Defaulting to `0`.\n-   byteLength `optional` Defaulting to the whole length of the src buffer.\n\n```ts\nsetSubData: (\n  dstByteOffset: number,\n  src: Uint8Array,\n  srcByteOffset?: number,\n  byteLength?: number,\n) =\u003e void;\n```\n\n## \u003ca id=\"texture\" /\u003eTexture\n\nOne texture consists of one or more texture subresources, each uniquely identified by a mipmap level and, for 2d textures only, array layer and aspect.\n\n### \u003ca id=\"setImageData\" /\u003esetImageData\n\nWe can set data in buffer with this method:\n\n-   data `required` Array of TexImageSource or ArrayBufferView.\n-   lod `optional` Lod. Defaulting to `0`.\n\n```ts\nsetImageData: (\n  data: (TexImageSource | ArrayBufferView)[],\n  lod?: number,\n) =\u003e void;\n```\n\nCreate a cubemap texture:\n\n```ts\n// The order of the array layers is [+X, -X, +Y, -Y, +Z, -Z]\nconst imageBitmaps = await Promise.all(\n    [\n        '/images/posx.jpg',\n        '/images/negx.jpg',\n        '/images/posy.jpg',\n        '/images/negy.jpg',\n        '/images/posz.jpg',\n        '/images/negz.jpg',\n    ].map(async (src) =\u003e loadImage(src)),\n);\nconst texture = device.createTexture({\n    format: Format.U8_RGBA_NORM,\n    width: imageBitmaps[0].width,\n    height: imageBitmaps[0].height,\n    depthOrArrayLayers: 6,\n    dimension: TextureDimension.TEXTURE_CUBE_MAP,\n    usage: TextureUsage.SAMPLED,\n});\ntexture.setImageData(imageBitmaps);\n```\n\n## \u003ca id=\"sampler\" /\u003eSampler\n\nA GPUSampler encodes transformations and filtering information that can be used in a shader to interpret texture resource data.\n\n## \u003ca id=\"renderPass\" /\u003eRenderPass\n\nThe RenderPass has several methods which affect how draw commands.\n\n### \u003ca id=\"setViewport\" /\u003esetViewport\n\nSets the viewport used during the rasterization stage to linearly map from normalized device coordinates to viewport coordinates.\n\n-   x `required` Minimum X value of the viewport in pixels.\n-   y `required` Minimum Y value of the viewport in pixels.\n-   w `required` Width of the viewport in pixels.\n-   h `required` Height of the viewport in pixels.\n-   minDepth `optional` Minimum depth value of the viewport.\n-   maxDepth `optional` Minimum depth value of the viewport.\n\n```ts\nsetViewport: (\n  x: number,\n  y: number,\n  w: number,\n  h: number,\n  minDepth?: number, // WebGPU only\n  maxDepth?: number, // WebGPU only\n) =\u003e void;\n```\n\n### \u003ca id=\"setScissorRect\" /\u003esetScissorRect\n\nSets the scissor rectangle used during the rasterization stage. After transformation into viewport coordinates any fragments which fall outside the scissor rectangle will be discarded.\n\n-   x `required` Minimum X value of the scissor rectangle in pixels.\n-   y `required` Minimum Y value of the scissor rectangle in pixels.\n-   w `required` Width of the scissor rectangle in pixels.\n-   h `required` Height of the scissor rectangle in pixels.\n\n```ts\nsetScissorRect: (x: number, y: number, w: number, h: number) =\u003e void;\n```\n\n### \u003ca id=\"setPipeline\" /\u003esetPipeline\n\nSets the current RenderPipeline.\n\n```ts\nsetPipeline(pipeline: RenderPipeline)\n```\n\n### \u003ca id=\"setBindings\" /\u003esetBindings\n\nBindings defines the interface between a set of resources bound and their accessibility in shader stages.\n\n```ts\nsetBindings: (bindings: Bindings) =\u003e void;\n```\n\n### \u003ca id=\"setVertexInput\" /\u003esetVertexInput\n\n```ts\nsetVertexInput: (\n  inputLayout: InputLayout | null,\n  buffers: (VertexBufferDescriptor | null)[] | null,\n  indexBuffer: IndexBufferDescriptor | null,\n) =\u003e void;\n```\n\nBind vertex \u0026 index buffer(s) like this:\n\n```ts\ninterface VertexBufferDescriptor {\n    buffer: Buffer;\n    offset?: number; // in bytes\n}\ntype IndexBufferDescriptor = VertexBufferDescriptor;\n```\n\n### \u003ca id=\"setStencilReference\" /\u003esetStencilReference\n\nSets the stencilReference value used during stencil tests with the \"replace\" GPUStencilOperation.\n\n```ts\nsetStencilReference: (value: number) =\u003e void;\n```\n\n### \u003ca id=\"draw\" /\u003edraw\n\nDraws primitives.\n\n-   vertexCount `required` The number of vertices to draw.\n-   instanceCount `optional` The number of instances to draw.\n-   firstVertex `optional` Offset into the vertex buffers, in vertices, to begin drawing from.\n-   firstInstance `optional` First instance to draw.\n\n```ts\ndraw: (\n  vertexCount: number,\n  instanceCount?: number,\n  firstVertex?: number,\n  firstInstance?: number,\n) =\u003e void;\n```\n\n### \u003ca id=\"drawIndexed\" /\u003edrawIndexed\n\nDraws indexed primitives.\n\n-   indexCount `required` The number of indices to draw.\n-   instanceCount `optional` The number of instances to draw.\n-   firstIndex `optional` Offset into the index buffer, in indices, begin drawing from.\n-   baseVertex `optional` Added to each index value before indexing into the vertex buffers.\n-   firstInstance `optional` First instance to draw.\n\n```ts\ndrawIndexed: (\n  indexCount: number,\n  instanceCount?: number,\n  firstIndex?: number,\n  baseVertex?: number,\n  firstInstance?: number,\n) =\u003e void;\n```\n\n### \u003ca id=\"drawIndirect\" /\u003edrawIndirect\n\n⚠️ WebGPU only.\n\nDraws primitives using parameters read from a GPUBuffer.\n\n```ts\ndrawIndirect: (indirectBuffer: Buffer, indirectOffset: number) =\u003e void;\n```\n\n```ts\n// Create drawIndirect values\nconst uint32 = new Uint32Array(4);\nuint32[0] = 3;\nuint32[1] = 1;\nuint32[2] = 0;\nuint32[3] = 0;\n\n// Create a GPUBuffer and write the draw values into it\nconst drawValues = device.createBuffer({\n    viewOrSize: uint32,\n    usage: BufferUsage.INDIRECT,\n});\n\n// Draw the vertices\nrenderPass.drawIndirect(drawValues, 0);\n```\n\n### \u003ca id=\"drawIndexedIndirect\" /\u003edrawIndexedIndirect\n\n⚠️ WebGPU only.\n\nDraws indexed primitives using parameters read from a GPUBuffer.\n\n```ts\ndrawIndexedIndirect: (indirectBuffer: Buffer, indirectOffset: number) =\u003e void;\n```\n\n```ts\n// Create drawIndirect values\nconst uint32 = new Uint32Array(5);\nuint32[0] = 6; // The indexCount value\nuint32[1] = 1; // The instanceCount value\nuint32[2] = 0; // The firstIndex value\nuint32[3] = 0; // The baseVertex value\nuint32[4] = 0; // The firstInstance value\n// Create a GPUBuffer and write the draw values into it\nconst drawValues = device.createBuffer({\n    viewOrSize: uint32,\n    usage: BufferUsage.INDIRECT,\n});\n\n// Draw the vertices\nrenderPass.drawIndirect(drawValues, 0);\n```\n\n### \u003ca id=\"beginOcclusionQuery\" /\u003ebeginOcclusionQuery\n\n⚠️ WebGL2 \u0026 WebGPU only.\n\nOcclusion query is only available on render passes, to query the number of fragment samples that pass all the per-fragment tests for a set of drawing commands, including scissor, sample mask, alpha to coverage, stencil, and depth tests. Any non-zero result value for the query indicates that at least one sample passed the tests and reached the output merging stage of the render pipeline, 0 indicates that no samples passed the tests.\n\nWhen beginning a render pass, `occlusionQuerySet` must be set to be able to use occlusion queries during the pass. An occlusion query is begun and ended by calling `beginOcclusionQuery()` and `endOcclusionQuery()` in pairs that cannot be nested.\n\n```ts\nbeginOcclusionQuery: (queryIndex: number) =\u003e void;\n```\n\n### \u003ca id=\"endOcclusionQuery\" /\u003eendOcclusionQuery\n\n⚠️ WebGL2 \u0026 WebGPU only.\n\n```ts\nendOcclusionQuery: () =\u003e void;\n```\n\n### \u003ca id=\"beginBundle\" /\u003ebeginBundle\n\nStart recording draw calls in render bundle.\n\n```ts\nbeginBundle: (renderBundle: RenderBundle) =\u003e void;\n```\n\n### \u003ca id=\"endBundle\" /\u003eendBundle\n\nStop recording.\n\n```ts\nendBundle: () =\u003e void;\n```\n\n### \u003ca id=\"executeBundles\" /\u003eexecuteBundles\n\nReplay the commands recorded in render bundles.\n\n```ts\nexecuteBundles: (renderBundles: RenderBundle[]) =\u003e void;\n```\n\n## \u003ca id=\"computePass\" /\u003eComputePass\n\n⚠️ WebGPU only.\n\nComputing operations provide direct access to GPU’s programmable hardware. Compute shaders do not have shader stage inputs or outputs, their results are side effects from writing data into storage bindings.\n\n### \u003ca id=\"dispatchWorkgroups\" /\u003edispatchWorkgroups\n\nDispatch work to be performed with the current ComputePipeline.\n\nX/Y/Z dimension of the grid of workgroups to dispatch.\n\n```ts\ndispatchWorkgroups: (\n  workgroupCountX: number,\n  workgroupCountY?: number,\n  workgroupCountZ?: number,\n) =\u003e void;\n```\n\n### \u003ca id=\"dispatchWorkgroupsIndirect\" /\u003edispatchWorkgroupsIndirect\n\nDispatch work to be performed with the current GPUComputePipeline using parameters read from a GPUBuffer.\n\n```ts\ndispatchWorkgroupsIndirect: (\n  indirectBuffer: Buffer,\n  indirectOffset: number,\n) =\u003e void;\n```\n\n## Program\n\n### \u003ca id=\"setUniformsLegacy\" /\u003esetUniformsLegacy\n\n⚠️ Only WebGL1 need this method.\n\n```ts\nsetUniformsLegacy: (uniforms: Record\u003cstring, any\u003e) =\u003e void;\n```\n\n```ts\nprogram.setUniformsLegacy({\n    u_ModelViewProjectionMatrix: modelViewProjectionMatrix,\n    u_Texture: texture,\n});\n```\n\n## \u003ca id='readback' /\u003eReadback\n\nReadback can read data from [Texture](#texture) or [Buffer](#buffer).\n\n### \u003ca id='readTexture' /\u003ereadTexture\n\nRead pixels from texture.\n\n-   t `required` Texture.\n-   x `required` X coordinate.\n-   y `required` Y coordinate.\n-   width `required` Width of dimension.\n-   height `required` Height of dimension.\n-   dst `required` Dst buffer view.\n-   length `optional`\n\n```ts\nreadTexture: (\n    t: Texture,\n    x: number,\n    y: number,\n    width: number,\n    height: number,\n    dst: ArrayBufferView,\n    dstOffset?: number,\n    length?: number,\n) =\u003e Promise\u003cArrayBufferView\u003e;\n```\n\nFor instance, if we want to read pixels from a texture:\n\n```ts\nconst texture = device.createTexture({\n    format: Format.U8_RGBA_NORM,\n    width: 1,\n    height: 1,\n    usage: TextureUsage.SAMPLED,\n});\ntexture.setImageData([new Uint8Array([1, 2, 3, 4])]);\n\nconst readback = device.createReadback();\n\nlet output = new Uint8Array(4);\n// x/y 0/0\nawait readback.readTexture(texture, 0, 0, 1, 1, output);\nexpect(output[0]).toBe(1);\nexpect(output[1]).toBe(2);\nexpect(output[2]).toBe(3);\nexpect(output[3]).toBe(4);\n```\n\n### \u003ca id='readTextureSync' /\u003ereadTextureSync\n\n⚠️ WebGL1 \u0026 WebGL2 only.\n\n```ts\nreadTextureSync: (\n    t: Texture,\n    x: number,\n    y: number,\n    width: number,\n    height: number,\n    dst: ArrayBufferView,\n    dstOffset?: number,\n    length?: number,\n) =\u003e ArrayBufferView;\n```\n\n### \u003ca id='readBuffer' /\u003ereadBuffer\n\n⚠️ WebGL2 \u0026 WebGPU only.\n\nRead buffer data.\n\n-   src `required` Source buffer.\n-   srcOffset `required` Offset in bytes of src buffer. Defaulting to `0`.\n-   dst `required` Dest buffer view.\n-   dstOffset `optional` Offset in bytes of dst buffer. Defaulting to `0`.\n-   length `optional` Length in bytes of dst buffer. Defaulting to its whole size.\n\n```ts\nreadBuffer: (\n    src: Buffer,\n    srcOffset: number,\n    dst: ArrayBufferView,\n    dstOffset?: number,\n    length?: number,\n) =\u003e Promise\u003cArrayBufferView\u003e;\n```\n\n`BufferUsage.COPY_SRC` must be used if this buffer will be read later:\n\n```ts\nconst vertexBuffer = device.createBuffer({\n    viewOrSize: new Float32Array([0, 0.5, -0.5, -0.5, 0.5, -0.5]),\n    usage: BufferUsage.VERTEX | BufferUsage.COPY_SRC,\n    hint: BufferFrequencyHint.DYNAMIC,\n});\nconst data = await readback.readBuffer(vertexBuffer, 0, new Float32Array(6));\n```\n\n## \u003ca id='shader-language' /\u003eShader Language\n\nSince WebGL 1/2 \u0026 WebGPU use different shader languages, we do a lot of transpiling work at runtime.\n\nWe use a syntax very closed to GLSL 300, and for different devices:\n\n-   WebGL1. Downgrade to GLSL 100.\n-   WebGL2. Almost keep the same which means GLSL 300.\n-   WebGPU. Transpile to GLSL 440 and then use [gfx-naga]() WASM to generate WGSL.\n\nSyntax as follows:\n\n-   [Attribute](#attribute)\n-   [Varying](#varying)\n-   [Sampler](#sampler)\n-   [Uniform](#uniform)\n-   [gl_Position](#gl_Position)\n-   [gl_FragColor](#gl_FragColor)\n-   [Define](#define)\n\n### \u003ca id='attribute' /\u003eAttribute\n\n```glsl\n// raw\nlayout(location = 0) in vec4 a_Position;\n\n// compiled GLSL 100\nattribute vec4 a_Position;\n\n// compiled GLSL 300\nlayout(location = 0) in vec4 a_Position;\n\n// compiled GLSL 440\nlayout(location = 0) in vec4 a_Position;\n\n// compiled WGSL\nvar\u003cprivate\u003e a_Position_1: vec4\u003cf32\u003e;\n@vertex\nfn main(@location(0) a_Position: vec4\u003cf32\u003e) -\u003e VertexOutput {\n    a_Position_1 = a_Position;\n}\n```\n\n### \u003ca id='varying' /\u003eVarying\n\n```glsl\n// raw\nout vec4 a_Position;\n\n// compiled GLSL 100\nvarying vec4 a_Position;\n\n// compiled GLSL 300\nout vec4 a_Position;\n\n// compiled GLSL 440\nlayout(location = 0) out vec4 a_Position;\n\n// compiled WGSL\nstruct VertexOutput {\n    @location(0) v_Position: vec4\u003cf32\u003e,\n}\n```\n\n### \u003ca id='sampler' /\u003eSampler\n\nWe need to use `SAMPLER_2D / SAMPLER_Cube` wrapping our texture.\n\n```glsl\n// raw\nuniform sampler2D u_Texture;\noutputColor = texture(SAMPLER_2D(u_Texture), v_Uv);\n\n// compiled GLSL 100\nuniform sampler2D u_Texture;\noutputColor = texture2D(u_Texture, v_TexCoord);\n\n// compiled GLSL 300\nuniform sampler2D u_Texture;\noutputColor = texture(u_Texture, v_Uv);\n\n// compiled GLSL 440\nlayout(set = 1, binding = 0) uniform texture2D T_u_Texture;\nlayout(set = 1, binding = 1) uniform sampler S_u_Texture;\noutputColor = texture(sampler2D(T_u_Texture, S_u_Texture), v_Uv);\n\n// compiled WGSL\n@group(1) @binding(0)\nvar T_u_Texture: texture_2d\u003cf32\u003e;\n@group(1) @binding(1)\nvar S_u_Texture: sampler;\noutputColor = textureSample(T_u_Texture, S_u_Texture, _e5);\n```\n\n### \u003ca id='uniform' /\u003eUniform\n\nWebGL2 uses Uniform Buffer Object.\n\n```glsl\n// raw\nlayout(std140) uniform Uniforms {\n  mat4 u_ModelViewProjectionMatrix;\n};\n\n// compiled GLSL 100\nuniform mat4 u_ModelViewProjectionMatrix;\n\n// compiled GLSL 300\nlayout(std140) uniform Uniforms {\n  mat4 u_ModelViewProjectionMatrix;\n};\n\n// compiled GLSL 440\nlayout(std140, set = 0, binding = 0) uniform  Uniforms {\n  mat4 u_ModelViewProjectionMatrix;\n};\n\n// compiled WGSL\nstruct Uniforms {\n  u_ModelViewProjectionMatrix: mat4x4\u003cf32\u003e,\n}\n@group(0) @binding(0)\nvar\u003cuniform\u003e global: Uniforms;\n```\n\n⚠️ We don't allow `instance_name` for now:\n\n```glsl\n// wrong\nlayout(std140) uniform Uniforms {\n  mat4 projection;\n  mat4 modelview;\n} matrices;\n```\n\n### \u003ca id='gl_Position' /\u003egl_Position\n\nWe still use `gl_Position` to represent the output of vertex shader:\n\n```glsl\n// raw\ngl_Position = vec4(1.0);\n\n// compiled GLSL 100\ngl_Position = vec4(1.0);\n\n// compiled GLSL 300\ngl_Position = vec4(1.0);\n\n// compiled GLSL 440\ngl_Position = vec4(1.0);\n\n// compiled WGSL\nstruct VertexOutput {\n    @builtin(position) member: vec4\u003cf32\u003e,\n}\n```\n\n### \u003ca id='gl_FragColor' /\u003egl_FragColor\n\n```glsl\n// raw\nout vec4 outputColor;\noutputColor = vec4(1.0);\n\n// compiled GLSL 100\nvec4 outputColor;\noutputColor = vec4(1.0);\ngl_FragColor = vec4(outputColor);\n\n// compiled GLSL 300\nout vec4 outputColor;\noutputColor = vec4(1.0);\n\n// compiled GLSL 440\nlayout(location = 0) out vec4 outputColor;\noutputColor = vec4(1.0);\n\n// compiled WGSL\nstruct FragmentOutput {\n    @location(0) outputColor: vec4\u003cf32\u003e,\n}\n```\n\n### \u003ca id='define' /\u003eDefine\n\nIt is worth mentioning that since WGSL is not natively supported, naga does conditional compilation during the GLSL 440 -\u003e WGSL translation process.\n\n`#define KEY VAR`\n\n```glsl\n#define PI 3.14\n```\n\n## \u003ca id='limitations' /\u003e Limitations\n\n`@group(x)` in WGSL should obey the following order:\n\n-   `group(0)` Uniform eg. `var\u003cuniform\u003e time : Time;`\n-   `group(1)` Texture \u0026 Sampler pair\n-   `group(2)` StorageBuffer eg. `var\u003cstorage, read_write\u003e atomic_storage : array\u003catomic\u003ci32\u003e\u003e;`\n-   `group(3)` StorageTexture eg. `var screen : texture_storage_2d\u003crgba16float, write\u003e;`\n\nFor example:\n\n```wgsl\n@group(1) @binding(0) var myTexture : texture_2d\u003cf32\u003e;\n@group(1) @binding(1) var mySampler : sampler;\n```\n\n```wgsl\n@group(1) @binding(0) var myTexture : texture_2d\u003cf32\u003e;\n@group(1) @binding(1) var mySampler : sampler;\n@group(2) @binding(0) var\u003cstorage, read_write\u003e input : array\u003ci32\u003e;\n```\n\nUniform and storage buffer can be assigned binding number:\n\n```ts\ndevice.createBindings({\n    pipeline: computePipeline,\n    uniformBufferBindings: [\n        {\n            binding: 0,\n            buffer: uniformBuffer,\n        },\n    ],\n    storageBufferBindings: [\n        {\n            binding: 1,\n            buffer: storageBuffer,\n        },\n    ],\n});\n```\n\n```wgsl\n@group(0) @binding(0) var\u003cuniform\u003e params : SimParams;\n@group(0) @binding(1) var\u003cstorage, read_write\u003e input : array\u003ci32\u003e;\n\n@group(1) @binding(0) var myTexture : texture_2d\u003cf32\u003e;\n@group(1) @binding(1) var mySampler : sampler;\n```\n\nCurrently we don't support `dynamicOffsets` when setting bindgroup.\n\n```ts\n// Won't support for now.\npassEncoder.setBindGroup(1, dynamicBindGroup, dynamicOffsets);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantvis%2Fg-device-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fantvis%2Fg-device-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantvis%2Fg-device-api/lists"}