| // MAINTENANCE_TODO: The generated Typedoc for this file is hard to navigate because it's |
| // alphabetized. Consider using namespaces or renames to fix this? |
| |
| /* eslint-disable no-sparse-arrays */ |
| |
| import { keysOf, makeTable, numericKeysOf, valueof } from '../common/util/data_tables.js'; |
| import { assertTypeTrue, TypeEqual } from '../common/util/types.js'; |
| import { assert, unreachable } from '../common/util/util.js'; |
| |
| import { GPUConst, kMaxUnsignedLongValue, kMaxUnsignedLongLongValue } from './constants.js'; |
| import { ImageCopyType } from './util/texture/layout.js'; |
| |
| // Base device limits can be found in constants.ts. |
| |
| // Queries |
| |
| /** Maximum number of queries in GPUQuerySet, by spec. */ |
| export const kMaxQueryCount = 4096; |
| /** Per-GPUQueryType info. */ |
| export type QueryTypeInfo = { |
| /** Optional feature required to use this GPUQueryType. */ |
| readonly feature: GPUFeatureName | undefined; |
| // Add fields as needed |
| }; |
| export const kQueryTypeInfo: { |
| readonly [k in GPUQueryType]: QueryTypeInfo; |
| } = /* prettier-ignore */ { |
| // Occlusion query does not require any features. |
| 'occlusion': { feature: undefined }, |
| 'timestamp': { feature: 'timestamp-query' }, |
| }; |
| /** List of all GPUQueryType values. */ |
| export const kQueryTypes = keysOf(kQueryTypeInfo); |
| |
| // Buffers |
| |
| /** Required alignment of a GPUBuffer size, by spec. */ |
| export const kBufferSizeAlignment = 4; |
| |
| /** Per-GPUBufferUsage copy info. */ |
| export const kBufferUsageCopyInfo: { |
| readonly [name: string]: GPUBufferUsageFlags; |
| } = /* prettier-ignore */ { |
| 'COPY_NONE': 0, |
| 'COPY_SRC': GPUConst.BufferUsage.COPY_SRC, |
| 'COPY_DST': GPUConst.BufferUsage.COPY_DST, |
| 'COPY_SRC_DST': GPUConst.BufferUsage.COPY_SRC | GPUConst.BufferUsage.COPY_DST, |
| }; |
| /** List of all GPUBufferUsage copy values. */ |
| export const kBufferUsageCopy = keysOf(kBufferUsageCopyInfo); |
| |
| /** Per-GPUBufferUsage keys and info. */ |
| type BufferUsageKey = keyof typeof GPUConst.BufferUsage; |
| export const kBufferUsageKeys = keysOf(GPUConst.BufferUsage); |
| export const kBufferUsageInfo: { |
| readonly [k in BufferUsageKey]: GPUBufferUsageFlags; |
| } = { |
| ...GPUConst.BufferUsage, |
| }; |
| |
| /** List of all GPUBufferUsage values. */ |
| export const kBufferUsages = Object.values(GPUConst.BufferUsage); |
| export const kAllBufferUsageBits = kBufferUsages.reduce( |
| (previousSet, currentUsage) => previousSet | currentUsage, |
| 0 |
| ); |
| |
| // Errors |
| |
| /** Per-GPUErrorFilter info. */ |
| export const kErrorScopeFilterInfo: { |
| readonly [k in GPUErrorFilter]: {}; |
| } = /* prettier-ignore */ { |
| 'out-of-memory': {}, |
| 'validation': {}, |
| 'internal': {}, |
| }; |
| /** List of all GPUErrorFilter values. */ |
| export const kErrorScopeFilters = keysOf(kErrorScopeFilterInfo); |
| export const kGeneratableErrorScopeFilters = kErrorScopeFilters.filter(e => e !== 'internal'); |
| |
| // Textures |
| |
| // Definitions for use locally. To access the table entries, use `kTextureFormatInfo`. |
| |
| // Note that we repeat the header multiple times in order to make it easier to read. |
| const kRegularTextureFormatInfo = /* prettier-ignore */ makeTable( |
| ['renderable', 'multisample', 'resolve', 'color', 'depth', 'stencil', 'storage', 'copySrc', 'copyDst', 'sampleType', 'bytesPerBlock', 'blockWidth', 'blockHeight', 'renderTargetPixelByteCost', 'renderTargetComponentAlignment', 'feature', 'baseFormat'] as const, |
| [ , , , true, false, false, , true, true, , , 1, 1, undefined, undefined, , undefined] as const, { |
| // 8-bit formats |
| 'r8unorm': [ true, true, true, , , , false, , , 'float', 1, , , 1, 1], |
| 'r8snorm': [ false, false, false, , , , false, , , 'float', 1], |
| 'r8uint': [ true, true, false, , , , false, , , 'uint', 1, , , 1, 1], |
| 'r8sint': [ true, true, false, , , , false, , , 'sint', 1, , , 1, 1], |
| // 16-bit formats |
| 'r16uint': [ true, true, false, , , , false, , , 'uint', 2, , , 2, 2], |
| 'r16sint': [ true, true, false, , , , false, , , 'sint', 2, , , 2, 2], |
| 'r16float': [ true, true, true, , , , false, , , 'float', 2, , , 2, 2], |
| 'rg8unorm': [ true, true, true, , , , false, , , 'float', 2, , , 2, 1], |
| 'rg8snorm': [ false, false, false, , , , false, , , 'float', 2], |
| 'rg8uint': [ true, true, false, , , , false, , , 'uint', 2, , , 2, 1], |
| 'rg8sint': [ true, true, false, , , , false, , , 'sint', 2, , , 2, 1], |
| // 32-bit formats |
| 'r32uint': [ true, false, false, , , , true, , , 'uint', 4, , , 4, 4], |
| 'r32sint': [ true, false, false, , , , true, , , 'sint', 4, , , 4, 4], |
| 'r32float': [ true, true, false, , , , true, , , 'unfilterable-float', 4, , , 4, 4], |
| 'rg16uint': [ true, true, false, , , , false, , , 'uint', 4, , , 4, 2], |
| 'rg16sint': [ true, true, false, , , , false, , , 'sint', 4, , , 4, 2], |
| 'rg16float': [ true, true, true, , , , false, , , 'float', 4, , , 4, 2], |
| 'rgba8unorm': [ true, true, true, , , , true, , , 'float', 4, , , 8, 1, , 'rgba8unorm'], |
| 'rgba8unorm-srgb': [ true, true, true, , , , false, , , 'float', 4, , , 8, 1, , 'rgba8unorm'], |
| 'rgba8snorm': [ false, false, false, , , , true, , , 'float', 4], |
| 'rgba8uint': [ true, true, false, , , , true, , , 'uint', 4, , , 4, 1], |
| 'rgba8sint': [ true, true, false, , , , true, , , 'sint', 4, , , 4, 1], |
| 'bgra8unorm': [ true, true, true, , , , true, , , 'float', 4, , , 8, 1, , 'bgra8unorm'], |
| 'bgra8unorm-srgb': [ true, true, true, , , , false, , , 'float', 4, , , 8, 1, , 'bgra8unorm'], |
| // Packed 32-bit formats |
| 'rgb10a2unorm': [ true, true, true, , , , false, , , 'float', 4, , , 8, 4], |
| 'rg11b10ufloat': [ false, false, false, , , , false, , , 'float', 4, , , 8, 4], |
| 'rgb9e5ufloat': [ false, false, false, , , , false, , , 'float', 4], |
| // 64-bit formats |
| 'rg32uint': [ true, false, false, , , , true, , , 'uint', 8, , , 8, 4], |
| 'rg32sint': [ true, false, false, , , , true, , , 'sint', 8, , , 8, 4], |
| 'rg32float': [ true, false, false, , , , true, , , 'unfilterable-float', 8, , , 8, 4], |
| 'rgba16uint': [ true, true, false, , , , true, , , 'uint', 8, , , 8, 2], |
| 'rgba16sint': [ true, true, false, , , , true, , , 'sint', 8, , , 8, 2], |
| 'rgba16float': [ true, true, true, , , , true, , , 'float', 8, , , 8, 2], |
| // 128-bit formats |
| 'rgba32uint': [ true, false, false, , , , true, , , 'uint', 16, , , 16, 4], |
| 'rgba32sint': [ true, false, false, , , , true, , , 'sint', 16, , , 16, 4], |
| 'rgba32float': [ true, false, false, , , , true, , , 'unfilterable-float', 16, , , 16, 4], |
| } as const); |
| /* prettier-ignore */ |
| const kTexFmtInfoHeader = ['renderable', 'multisample', 'resolve', 'color', 'depth', 'stencil', 'storage', 'copySrc', 'copyDst', 'sampleType', 'bytesPerBlock', 'blockWidth', 'blockHeight', 'renderTargetPixelByteCost', 'renderTargetComponentAlignment', 'feature', 'baseFormat'] as const; |
| const kSizedDepthStencilFormatInfo = /* prettier-ignore */ makeTable(kTexFmtInfoHeader, |
| [ true, true, false, false, , , false, , , , , 1, 1, undefined, undefined, , undefined] as const, { |
| 'depth32float': [ , , , , true, false, , true, false, 'depth', 4], |
| 'depth16unorm': [ , , , , true, false, , true, true, 'depth', 2], |
| 'stencil8': [ , , , , false, true, , true, true, 'uint', 1], |
| } as const); |
| |
| // Multi aspect sample type are now set to their first aspect |
| const kUnsizedDepthStencilFormatInfo = /* prettier-ignore */ makeTable(kTexFmtInfoHeader, |
| [ true, true, false, false, , , false, false, false, , undefined, 1, 1, , , , undefined] as const, { |
| 'depth24plus': [ , , , , true, false, , , , 'depth'], |
| 'depth24plus-stencil8': [ , , , , true, true, , , , 'depth'], |
| // MAINTENANCE_TODO: These should really be sized formats; see below MAINTENANCE_TODO about multi-aspect formats. |
| 'depth32float-stencil8': [ , , , , true, true, , , , 'depth', , , , , , 'depth32float-stencil8'], |
| } as const); |
| |
| // Separated compressed formats by type |
| const kBCTextureFormatInfo = /* prettier-ignore */ makeTable(kTexFmtInfoHeader, |
| [ false, false, false, true, false, false, false, true, true, , , 4, 4, , , , undefined] as const, { |
| // Block Compression (BC) formats |
| 'bc1-rgba-unorm': [ , , , , , , , , , 'float', 8, 4, 4, , , 'texture-compression-bc', 'bc1-rgba-unorm'], |
| 'bc1-rgba-unorm-srgb': [ , , , , , , , , , 'float', 8, 4, 4, , , 'texture-compression-bc', 'bc1-rgba-unorm'], |
| 'bc2-rgba-unorm': [ , , , , , , , , , 'float', 16, 4, 4, , , 'texture-compression-bc', 'bc2-rgba-unorm'], |
| 'bc2-rgba-unorm-srgb': [ , , , , , , , , , 'float', 16, 4, 4, , , 'texture-compression-bc', 'bc2-rgba-unorm'], |
| 'bc3-rgba-unorm': [ , , , , , , , , , 'float', 16, 4, 4, , , 'texture-compression-bc', 'bc3-rgba-unorm'], |
| 'bc3-rgba-unorm-srgb': [ , , , , , , , , , 'float', 16, 4, 4, , , 'texture-compression-bc', 'bc3-rgba-unorm'], |
| 'bc4-r-unorm': [ , , , , , , , , , 'float', 8, 4, 4, , , 'texture-compression-bc'], |
| 'bc4-r-snorm': [ , , , , , , , , , 'float', 8, 4, 4, , , 'texture-compression-bc'], |
| 'bc5-rg-unorm': [ , , , , , , , , , 'float', 16, 4, 4, , , 'texture-compression-bc'], |
| 'bc5-rg-snorm': [ , , , , , , , , , 'float', 16, 4, 4, , , 'texture-compression-bc'], |
| 'bc6h-rgb-ufloat': [ , , , , , , , , , 'float', 16, 4, 4, , , 'texture-compression-bc'], |
| 'bc6h-rgb-float': [ , , , , , , , , , 'float', 16, 4, 4, , , 'texture-compression-bc'], |
| 'bc7-rgba-unorm': [ , , , , , , , , , 'float', 16, 4, 4, , , 'texture-compression-bc', 'bc7-rgba-unorm'], |
| 'bc7-rgba-unorm-srgb': [ , , , , , , , , , 'float', 16, 4, 4, , , 'texture-compression-bc', 'bc7-rgba-unorm'], |
| } as const); |
| const kETC2TextureFormatInfo = /* prettier-ignore */ makeTable(kTexFmtInfoHeader, |
| [ false, false, false, true, false, false, false, true, true, , , 4, 4, , , , undefined] as const, { |
| // Ericsson Compression (ETC2) formats |
| 'etc2-rgb8unorm': [ , , , , , , , , , 'float', 8, 4, 4, , , 'texture-compression-etc2', 'etc2-rgb8unorm'], |
| 'etc2-rgb8unorm-srgb': [ , , , , , , , , , 'float', 8, 4, 4, , , 'texture-compression-etc2', 'etc2-rgb8unorm'], |
| 'etc2-rgb8a1unorm': [ , , , , , , , , , 'float', 8, 4, 4, , , 'texture-compression-etc2', 'etc2-rgb8a1unorm'], |
| 'etc2-rgb8a1unorm-srgb': [ , , , , , , , , , 'float', 8, 4, 4, , , 'texture-compression-etc2', 'etc2-rgb8a1unorm'], |
| 'etc2-rgba8unorm': [ , , , , , , , , , 'float', 16, 4, 4, , , 'texture-compression-etc2', 'etc2-rgba8unorm'], |
| 'etc2-rgba8unorm-srgb': [ , , , , , , , , , 'float', 16, 4, 4, , , 'texture-compression-etc2', 'etc2-rgba8unorm'], |
| 'eac-r11unorm': [ , , , , , , , , , 'float', 8, 4, 4, , , 'texture-compression-etc2'], |
| 'eac-r11snorm': [ , , , , , , , , , 'float', 8, 4, 4, , , 'texture-compression-etc2'], |
| 'eac-rg11unorm': [ , , , , , , , , , 'float', 16, 4, 4, , , 'texture-compression-etc2'], |
| 'eac-rg11snorm': [ , , , , , , , , , 'float', 16, 4, 4, , , 'texture-compression-etc2'], |
| } as const); |
| const kASTCTextureFormatInfo = /* prettier-ignore */ makeTable(kTexFmtInfoHeader, |
| [ false, false, false, true, false, false, false, true, true, , , , , , , , undefined] as const, { |
| // Adaptable Scalable Compression (ASTC) formats |
| 'astc-4x4-unorm': [ , , , , , , , , , 'float', 16, 4, 4, , , 'texture-compression-astc', 'astc-4x4-unorm'], |
| 'astc-4x4-unorm-srgb': [ , , , , , , , , , 'float', 16, 4, 4, , , 'texture-compression-astc', 'astc-4x4-unorm'], |
| 'astc-5x4-unorm': [ , , , , , , , , , 'float', 16, 5, 4, , , 'texture-compression-astc', 'astc-5x4-unorm'], |
| 'astc-5x4-unorm-srgb': [ , , , , , , , , , 'float', 16, 5, 4, , , 'texture-compression-astc', 'astc-5x4-unorm'], |
| 'astc-5x5-unorm': [ , , , , , , , , , 'float', 16, 5, 5, , , 'texture-compression-astc', 'astc-5x5-unorm'], |
| 'astc-5x5-unorm-srgb': [ , , , , , , , , , 'float', 16, 5, 5, , , 'texture-compression-astc', 'astc-5x5-unorm'], |
| 'astc-6x5-unorm': [ , , , , , , , , , 'float', 16, 6, 5, , , 'texture-compression-astc', 'astc-6x5-unorm'], |
| 'astc-6x5-unorm-srgb': [ , , , , , , , , , 'float', 16, 6, 5, , , 'texture-compression-astc', 'astc-6x5-unorm'], |
| 'astc-6x6-unorm': [ , , , , , , , , , 'float', 16, 6, 6, , , 'texture-compression-astc', 'astc-6x6-unorm'], |
| 'astc-6x6-unorm-srgb': [ , , , , , , , , , 'float', 16, 6, 6, , , 'texture-compression-astc', 'astc-6x6-unorm'], |
| 'astc-8x5-unorm': [ , , , , , , , , , 'float', 16, 8, 5, , , 'texture-compression-astc', 'astc-8x5-unorm'], |
| 'astc-8x5-unorm-srgb': [ , , , , , , , , , 'float', 16, 8, 5, , , 'texture-compression-astc', 'astc-8x5-unorm'], |
| 'astc-8x6-unorm': [ , , , , , , , , , 'float', 16, 8, 6, , , 'texture-compression-astc', 'astc-8x6-unorm'], |
| 'astc-8x6-unorm-srgb': [ , , , , , , , , , 'float', 16, 8, 6, , , 'texture-compression-astc', 'astc-8x6-unorm'], |
| 'astc-8x8-unorm': [ , , , , , , , , , 'float', 16, 8, 8, , , 'texture-compression-astc', 'astc-8x8-unorm'], |
| 'astc-8x8-unorm-srgb': [ , , , , , , , , , 'float', 16, 8, 8, , , 'texture-compression-astc', 'astc-8x8-unorm'], |
| 'astc-10x5-unorm': [ , , , , , , , , , 'float', 16, 10, 5, , , 'texture-compression-astc', 'astc-10x5-unorm'], |
| 'astc-10x5-unorm-srgb': [ , , , , , , , , , 'float', 16, 10, 5, , , 'texture-compression-astc', 'astc-10x5-unorm'], |
| 'astc-10x6-unorm': [ , , , , , , , , , 'float', 16, 10, 6, , , 'texture-compression-astc', 'astc-10x6-unorm'], |
| 'astc-10x6-unorm-srgb': [ , , , , , , , , , 'float', 16, 10, 6, , , 'texture-compression-astc', 'astc-10x6-unorm'], |
| 'astc-10x8-unorm': [ , , , , , , , , , 'float', 16, 10, 8, , , 'texture-compression-astc', 'astc-10x8-unorm'], |
| 'astc-10x8-unorm-srgb': [ , , , , , , , , , 'float', 16, 10, 8, , , 'texture-compression-astc', 'astc-10x8-unorm'], |
| 'astc-10x10-unorm': [ , , , , , , , , , 'float', 16, 10, 10, , , 'texture-compression-astc', 'astc-10x10-unorm'], |
| 'astc-10x10-unorm-srgb': [ , , , , , , , , , 'float', 16, 10, 10, , , 'texture-compression-astc', 'astc-10x10-unorm'], |
| 'astc-12x10-unorm': [ , , , , , , , , , 'float', 16, 12, 10, , , 'texture-compression-astc', 'astc-12x10-unorm'], |
| 'astc-12x10-unorm-srgb': [ , , , , , , , , , 'float', 16, 12, 10, , , 'texture-compression-astc', 'astc-12x10-unorm'], |
| 'astc-12x12-unorm': [ , , , , , , , , , 'float', 16, 12, 12, , , 'texture-compression-astc', 'astc-12x12-unorm'], |
| 'astc-12x12-unorm-srgb': [ , , , , , , , , , 'float', 16, 12, 12, , , 'texture-compression-astc', 'astc-12x12-unorm'], |
| } as const); |
| |
| // Definitions for use locally. To access the table entries, use `kTextureFormatInfo`. |
| |
| // MAINTENANCE_TODO: Consider generating the exports below programmatically by filtering the big list, instead |
| // of using these local constants? Requires some type magic though. |
| /* prettier-ignore */ const kCompressedTextureFormatInfo = { ...kBCTextureFormatInfo, ...kETC2TextureFormatInfo, ...kASTCTextureFormatInfo } as const; |
| /* prettier-ignore */ const kColorTextureFormatInfo = { ...kRegularTextureFormatInfo, ...kCompressedTextureFormatInfo } as const; |
| /* prettier-ignore */ const kEncodableTextureFormatInfo = { ...kRegularTextureFormatInfo, ...kSizedDepthStencilFormatInfo } as const; |
| /* prettier-ignore */ const kSizedTextureFormatInfo = { ...kRegularTextureFormatInfo, ...kSizedDepthStencilFormatInfo, ...kCompressedTextureFormatInfo } as const; |
| /* prettier-ignore */ const kDepthStencilFormatInfo = { ...kSizedDepthStencilFormatInfo, ...kUnsizedDepthStencilFormatInfo } as const; |
| /* prettier-ignore */ const kUncompressedTextureFormatInfo = { ...kRegularTextureFormatInfo, ...kSizedDepthStencilFormatInfo, ...kUnsizedDepthStencilFormatInfo } as const; |
| /* prettier-ignore */ const kAllTextureFormatInfo = { ...kUncompressedTextureFormatInfo, ...kCompressedTextureFormatInfo } as const; |
| |
| /** A "regular" texture format (uncompressed, sized, single-plane color formats). */ |
| /* prettier-ignore */ export type RegularTextureFormat = keyof typeof kRegularTextureFormatInfo; |
| /** A sized depth/stencil texture format. */ |
| /* prettier-ignore */ export type SizedDepthStencilFormat = keyof typeof kSizedDepthStencilFormatInfo; |
| /** An unsized depth/stencil texture format. */ |
| /* prettier-ignore */ export type UnsizedDepthStencilFormat = keyof typeof kUnsizedDepthStencilFormatInfo; |
| /** A compressed (block) texture format. */ |
| /* prettier-ignore */ export type CompressedTextureFormat = keyof typeof kCompressedTextureFormatInfo; |
| |
| /** A color texture format (regular | compressed). */ |
| /* prettier-ignore */ export type ColorTextureFormat = keyof typeof kColorTextureFormatInfo; |
| /** An encodable texture format (regular | sized depth/stencil). */ |
| /* prettier-ignore */ export type EncodableTextureFormat = keyof typeof kEncodableTextureFormatInfo; |
| /** A sized texture format (regular | sized depth/stencil | compressed). */ |
| /* prettier-ignore */ export type SizedTextureFormat = keyof typeof kSizedTextureFormatInfo; |
| /** A depth/stencil format (sized | unsized). */ |
| /* prettier-ignore */ export type DepthStencilFormat = keyof typeof kDepthStencilFormatInfo; |
| /** An uncompressed (block size 1x1) format (regular | depth/stencil). */ |
| /* prettier-ignore */ export type UncompressedTextureFormat = keyof typeof kUncompressedTextureFormatInfo; |
| |
| /* prettier-ignore */ export const kRegularTextureFormats: readonly RegularTextureFormat[] = keysOf( kRegularTextureFormatInfo); |
| /* prettier-ignore */ export const kSizedDepthStencilFormats: readonly SizedDepthStencilFormat[] = keysOf( kSizedDepthStencilFormatInfo); |
| /* prettier-ignore */ export const kUnsizedDepthStencilFormats: readonly UnsizedDepthStencilFormat[] = keysOf(kUnsizedDepthStencilFormatInfo); |
| /* prettier-ignore */ export const kCompressedTextureFormats: readonly CompressedTextureFormat[] = keysOf( kCompressedTextureFormatInfo); |
| |
| /* prettier-ignore */ export const kColorTextureFormats: readonly ColorTextureFormat[] = keysOf( kColorTextureFormatInfo); |
| /* prettier-ignore */ export const kEncodableTextureFormats: readonly EncodableTextureFormat[] = keysOf( kEncodableTextureFormatInfo); |
| /* prettier-ignore */ export const kSizedTextureFormats: readonly SizedTextureFormat[] = keysOf( kSizedTextureFormatInfo); |
| /* prettier-ignore */ export const kDepthStencilFormats: readonly DepthStencilFormat[] = keysOf( kDepthStencilFormatInfo); |
| /* prettier-ignore */ export const kUncompressedTextureFormats: readonly UncompressedTextureFormat[] = keysOf(kUncompressedTextureFormatInfo); |
| /* prettier-ignore */ export const kAllTextureFormats: readonly GPUTextureFormat[] = keysOf( kAllTextureFormatInfo); |
| |
| // CompressedTextureFormat are unrenderable so filter from RegularTextureFormats for color targets is enough |
| export const kRenderableColorTextureFormats = kRegularTextureFormats.filter( |
| v => kColorTextureFormatInfo[v].renderable |
| ); |
| assert( |
| kRenderableColorTextureFormats.every( |
| f => |
| kAllTextureFormatInfo[f].renderTargetComponentAlignment !== undefined && |
| kAllTextureFormatInfo[f].renderTargetPixelByteCost !== undefined |
| ) |
| ); |
| |
| // The formats of GPUTextureFormat for canvas context. |
| export const kCanvasTextureFormats = ['bgra8unorm', 'rgba8unorm', 'rgba16float'] as const; |
| |
| // The alpha mode for canvas context. |
| export const kCanvasAlphaModesInfo: { |
| readonly [k in GPUCanvasAlphaMode]: {}; |
| } = /* prettier-ignore */ { |
| 'opaque': {}, |
| 'premultiplied': {}, |
| }; |
| export const kCanvasAlphaModes = keysOf(kCanvasAlphaModesInfo); |
| |
| // The color spaces for canvas context |
| export const kCanvasColorSpacesInfo: { |
| readonly [k in PredefinedColorSpace]: {}; |
| } = /* prettier-ignore */ { |
| 'srgb': {}, |
| 'display-p3': {}, |
| }; |
| export const kCanvasColorSpaces = keysOf(kCanvasColorSpacesInfo); |
| |
| /** Per-GPUTextureFormat info. */ |
| // Exists just for documentation. Otherwise could be inferred by `makeTable`. |
| // MAINTENANCE_TODO: Refactor this to separate per-aspect data for multi-aspect formats. In particular: |
| // - bytesPerBlock only makes sense on a per-aspect basis. But this table can't express that. |
| // So we put depth32float-stencil8 to be an unsized format for now. |
| export type TextureFormatInfo = { |
| /** Whether the format can be used as `RENDER_ATTACHMENT`. */ |
| renderable: boolean; |
| /** Whether the format can be used in a multisample texture. */ |
| multisample: boolean; |
| /** Whether the texture with the format can be used as a resolve target. */ |
| resolve: boolean; |
| /** Whether the format has a color aspect. */ |
| color: boolean; |
| /** Whether the format has a depth aspect. */ |
| depth: boolean; |
| /** Whether the format has a stencil aspect. */ |
| stencil: boolean; |
| /** Whether the format can be used as `STORAGE`. */ |
| storage: boolean; |
| /** Whether the format can be used as `COPY_SRC`. */ |
| copySrc: boolean; |
| /** Whether the format can be used as `COPY_DST`. */ |
| copyDst: boolean; |
| /** Byte size of one texel block, or `undefined` if the format is unsized. */ |
| bytesPerBlock: number | undefined; |
| /** Width, in texels, of one texel block. */ |
| blockWidth: number; |
| /** Height, in texels, of one texel block. */ |
| blockHeight: number; |
| /** The raw, unaligned, byte cost towards the color attachment bytes per sample. |
| * (See https://www.w3.org/TR/webgpu/#abstract-opdef-calculating-color-attachment-bytes-per-sample). */ |
| renderTargetPixelByteCost: number | undefined; |
| /** The alignment used for the format when computing the color attachment bytes per sample. */ |
| renderTargetComponentAlignment: number | undefined; |
| /** Optional feature required to use this format, or `undefined` if none. */ |
| feature: GPUFeatureName | undefined; |
| // Add fields as needed |
| }; |
| /** Per-GPUTextureFormat info. */ |
| export const kTextureFormatInfo: { |
| readonly [k in GPUTextureFormat]: TextureFormatInfo & |
| // TextureFormatInfo exists just for documentation (and verification of the table data types). |
| // The next line constrains the types so that accessing kTextureFormatInfo with |
| // a subtype of GPUTextureFormat actually returns nicely a constrained info type |
| // (e.g. with `bytesPerBlock: number` instead of `bytesPerBlock: number | undefined`). |
| typeof kAllTextureFormatInfo[k]; |
| } = kAllTextureFormatInfo; |
| /** List of all GPUTextureFormat values. */ |
| /* prettier-ignore */ export const kTextureFormats: readonly GPUTextureFormat[] = keysOf(kAllTextureFormatInfo); |
| |
| /** Valid GPUTextureFormats for `copyExternalImageToTexture`, by spec. */ |
| export const kValidTextureFormatsForCopyE2T = [ |
| 'r8unorm', |
| 'r16float', |
| 'r32float', |
| 'rg8unorm', |
| 'rg16float', |
| 'rg32float', |
| 'rgba8unorm', |
| 'rgba8unorm-srgb', |
| 'bgra8unorm', |
| 'bgra8unorm-srgb', |
| 'rgb10a2unorm', |
| 'rgba16float', |
| 'rgba32float', |
| ] as const; |
| |
| /** Per-GPUTextureDimension info. */ |
| export const kTextureDimensionInfo: { |
| readonly [k in GPUTextureDimension]: {}; |
| } = /* prettier-ignore */ { |
| '1d': {}, |
| '2d': {}, |
| '3d': {}, |
| }; |
| /** List of all GPUTextureDimension values. */ |
| export const kTextureDimensions = keysOf(kTextureDimensionInfo); |
| |
| /** Per-GPUTextureAspect info. */ |
| export const kTextureAspectInfo: { |
| readonly [k in GPUTextureAspect]: {}; |
| } = /* prettier-ignore */ { |
| 'all': {}, |
| 'depth-only': {}, |
| 'stencil-only': {}, |
| }; |
| /** List of all GPUTextureAspect values. */ |
| export const kTextureAspects = keysOf(kTextureAspectInfo); |
| |
| /** Per-GPUCompareFunction info. */ |
| export const kCompareFunctionInfo: { |
| readonly [k in GPUCompareFunction]: {}; |
| } = /* prettier-ignore */ { |
| 'never': {}, |
| 'less': {}, |
| 'equal': {}, |
| 'less-equal': {}, |
| 'greater': {}, |
| 'not-equal': {}, |
| 'greater-equal': {}, |
| 'always': {}, |
| }; |
| /** List of all GPUCompareFunction values. */ |
| export const kCompareFunctions = keysOf(kCompareFunctionInfo); |
| |
| /** Per-GPUStencilOperation info. */ |
| export const kStencilOperationInfo: { |
| readonly [k in GPUStencilOperation]: {}; |
| } = /* prettier-ignore */ { |
| 'keep': {}, |
| 'zero': {}, |
| 'replace': {}, |
| 'invert': {}, |
| 'increment-clamp': {}, |
| 'decrement-clamp': {}, |
| 'increment-wrap': {}, |
| 'decrement-wrap': {}, |
| }; |
| /** List of all GPUStencilOperation values. */ |
| export const kStencilOperations = keysOf(kStencilOperationInfo); |
| |
| const kDepthStencilFormatCapabilityInBufferTextureCopy = { |
| // kUnsizedDepthStencilFormats |
| depth24plus: { |
| CopyB2T: [], |
| CopyT2B: [], |
| texelAspectSize: { 'depth-only': -1, 'stencil-only': -1 }, |
| }, |
| 'depth24plus-stencil8': { |
| CopyB2T: ['stencil-only'], |
| CopyT2B: ['stencil-only'], |
| texelAspectSize: { 'depth-only': -1, 'stencil-only': 1 }, |
| }, |
| |
| // kSizedDepthStencilFormats |
| depth16unorm: { |
| CopyB2T: ['all', 'depth-only'], |
| CopyT2B: ['all', 'depth-only'], |
| texelAspectSize: { 'depth-only': 2, 'stencil-only': -1 }, |
| }, |
| depth32float: { |
| CopyB2T: [], |
| CopyT2B: ['all', 'depth-only'], |
| texelAspectSize: { 'depth-only': 4, 'stencil-only': -1 }, |
| }, |
| 'depth32float-stencil8': { |
| CopyB2T: ['stencil-only'], |
| CopyT2B: ['depth-only', 'stencil-only'], |
| texelAspectSize: { 'depth-only': 4, 'stencil-only': 1 }, |
| }, |
| stencil8: { |
| CopyB2T: ['all', 'stencil-only'], |
| CopyT2B: ['all', 'stencil-only'], |
| texelAspectSize: { 'depth-only': -1, 'stencil-only': 1 }, |
| }, |
| } as const; |
| |
| /** `kDepthStencilFormatResolvedAspect[format][aspect]` returns the aspect-specific format for a |
| * depth-stencil format, or `undefined` if the format doesn't have the aspect. |
| */ |
| export const kDepthStencilFormatResolvedAspect: { |
| readonly [k in DepthStencilFormat]: { |
| readonly [a in GPUTextureAspect]: DepthStencilFormat | undefined; |
| }; |
| } = { |
| // kUnsizedDepthStencilFormats |
| depth24plus: { |
| all: 'depth24plus', |
| 'depth-only': 'depth24plus', |
| 'stencil-only': undefined, |
| }, |
| 'depth24plus-stencil8': { |
| all: 'depth24plus-stencil8', |
| 'depth-only': 'depth24plus', |
| 'stencil-only': 'stencil8', |
| }, |
| |
| // kSizedDepthStencilFormats |
| depth16unorm: { |
| all: 'depth16unorm', |
| 'depth-only': 'depth16unorm', |
| 'stencil-only': undefined, |
| }, |
| depth32float: { |
| all: 'depth32float', |
| 'depth-only': 'depth32float', |
| 'stencil-only': undefined, |
| }, |
| 'depth32float-stencil8': { |
| all: 'depth32float-stencil8', |
| 'depth-only': 'depth32float', |
| 'stencil-only': 'stencil8', |
| }, |
| stencil8: { |
| all: 'stencil8', |
| 'depth-only': undefined, |
| 'stencil-only': 'stencil8', |
| }, |
| } as const; |
| |
| /** |
| * @returns the GPUTextureFormat corresponding to the @param aspect of @param format. |
| * This allows choosing the correct format for depth-stencil aspects when creating pipelines that |
| * will have to match the resolved format of views, or to get per-aspect information like the |
| * `blockByteSize`. |
| * |
| * Many helpers use an `undefined` `aspect` to means `'all'` so this is also the default for this |
| * function. |
| */ |
| export function resolvePerAspectFormat( |
| format: GPUTextureFormat, |
| aspect?: GPUTextureAspect |
| ): GPUTextureFormat { |
| if (aspect === 'all' || aspect === undefined) { |
| return format; |
| } |
| assert(kTextureFormatInfo[format].depth || kTextureFormatInfo[format].stencil); |
| const resolved = kDepthStencilFormatResolvedAspect[format as DepthStencilFormat][aspect ?? 'all']; |
| assert(resolved !== undefined); |
| return resolved; |
| } |
| |
| /** |
| * Gets all copyable aspects for copies between texture and buffer for specified depth/stencil format and copy type, by spec. |
| */ |
| export function depthStencilFormatCopyableAspects( |
| type: ImageCopyType, |
| format: DepthStencilFormat |
| ): readonly GPUTextureAspect[] { |
| const appliedType = type === 'WriteTexture' ? 'CopyB2T' : type; |
| return kDepthStencilFormatCapabilityInBufferTextureCopy[format][appliedType]; |
| } |
| |
| /** |
| * Computes whether a copy between a depth/stencil texture aspect and a buffer is supported, by spec. |
| */ |
| export function depthStencilBufferTextureCopySupported( |
| type: ImageCopyType, |
| format: DepthStencilFormat, |
| aspect: GPUTextureAspect |
| ): boolean { |
| const supportedAspects: readonly GPUTextureAspect[] = depthStencilFormatCopyableAspects( |
| type, |
| format |
| ); |
| return supportedAspects.includes(aspect); |
| } |
| |
| /** |
| * Returns the byte size of the depth or stencil aspect of the specified depth/stencil format, |
| * or -1 if none. |
| */ |
| export function depthStencilFormatAspectSize( |
| format: DepthStencilFormat, |
| aspect: 'depth-only' | 'stencil-only' |
| ) { |
| const texelAspectSize = |
| kDepthStencilFormatCapabilityInBufferTextureCopy[format].texelAspectSize[aspect]; |
| assert(texelAspectSize > 0); |
| return texelAspectSize; |
| } |
| |
| /** |
| * Returns true iff a texture can be created with the provided GPUTextureDimension |
| * (defaulting to 2d) and GPUTextureFormat, by spec. |
| */ |
| export function textureDimensionAndFormatCompatible( |
| dimension: undefined | GPUTextureDimension, |
| format: GPUTextureFormat |
| ): boolean { |
| const info = kAllTextureFormatInfo[format]; |
| return !( |
| (dimension === '1d' || dimension === '3d') && |
| (info.blockWidth > 1 || info.depth || info.stencil) |
| ); |
| } |
| |
| /** Per-GPUTextureUsage type info. */ |
| export const kTextureUsageTypeInfo: { |
| readonly [name: string]: number; |
| } = /* prettier-ignore */ { |
| 'texture': Number(GPUConst.TextureUsage.TEXTURE_BINDING), |
| 'storage': Number(GPUConst.TextureUsage.STORAGE_BINDING), |
| 'render': Number(GPUConst.TextureUsage.RENDER_ATTACHMENT), |
| }; |
| /** List of all GPUTextureUsage type values. */ |
| export const kTextureUsageType = keysOf(kTextureUsageTypeInfo); |
| |
| /** Per-GPUTextureUsage copy info. */ |
| export const kTextureUsageCopyInfo: { |
| readonly [name: string]: number; |
| } = /* prettier-ignore */ { |
| 'none': 0, |
| 'src': Number(GPUConst.TextureUsage.COPY_SRC), |
| 'dst': Number(GPUConst.TextureUsage.COPY_DST), |
| 'src-dest': Number(GPUConst.TextureUsage.COPY_SRC) | Number(GPUConst.TextureUsage.COPY_DST), |
| }; |
| /** List of all GPUTextureUsage copy values. */ |
| export const kTextureUsageCopy = keysOf(kTextureUsageCopyInfo); |
| |
| /** Per-GPUTextureUsage info. */ |
| export const kTextureUsageInfo: { |
| readonly [k in valueof<typeof GPUConst.TextureUsage>]: {}; |
| } = { |
| [GPUConst.TextureUsage.COPY_SRC]: {}, |
| [GPUConst.TextureUsage.COPY_DST]: {}, |
| [GPUConst.TextureUsage.TEXTURE_BINDING]: {}, |
| [GPUConst.TextureUsage.STORAGE_BINDING]: {}, |
| [GPUConst.TextureUsage.RENDER_ATTACHMENT]: {}, |
| }; |
| /** List of all GPUTextureUsage values. */ |
| export const kTextureUsages = numericKeysOf<GPUTextureUsageFlags>(kTextureUsageInfo); |
| |
| // Texture View |
| |
| /** Per-GPUTextureViewDimension info. */ |
| export type TextureViewDimensionInfo = { |
| /** Whether a storage texture view can have this view dimension. */ |
| readonly storage: boolean; |
| // Add fields as needed |
| }; |
| /** Per-GPUTextureViewDimension info. */ |
| export const kTextureViewDimensionInfo: { |
| readonly [k in GPUTextureViewDimension]: TextureViewDimensionInfo; |
| } = /* prettier-ignore */ { |
| '1d': { storage: true }, |
| '2d': { storage: true }, |
| '2d-array': { storage: true }, |
| 'cube': { storage: false }, |
| 'cube-array': { storage: false }, |
| '3d': { storage: true }, |
| }; |
| /** List of all GPUTextureDimension values. */ |
| export const kTextureViewDimensions = keysOf(kTextureViewDimensionInfo); |
| |
| // Vertex formats |
| |
| /** Per-GPUVertexFormat info. */ |
| // Exists just for documentation. Otherwise could be inferred by `makeTable`. |
| export type VertexFormatInfo = { |
| /** Number of bytes in each component. */ |
| readonly bytesPerComponent: 1 | 2 | 4; |
| /** The data encoding (float, normalized, or integer) for each component. */ |
| readonly type: 'float' | 'unorm' | 'snorm' | 'uint' | 'sint'; |
| /** Number of components. */ |
| readonly componentCount: 1 | 2 | 3 | 4; |
| /** The completely matching WGSL type for vertex format */ |
| readonly wgslType: |
| | 'f32' |
| | 'vec2<f32>' |
| | 'vec3<f32>' |
| | 'vec4<f32>' |
| | 'u32' |
| | 'vec2<u32>' |
| | 'vec3<u32>' |
| | 'vec4<u32>' |
| | 'i32' |
| | 'vec2<i32>' |
| | 'vec3<i32>' |
| | 'vec4<i32>'; |
| // Add fields as needed |
| }; |
| /** Per-GPUVertexFormat info. */ |
| export const kVertexFormatInfo: { |
| readonly [k in GPUVertexFormat]: VertexFormatInfo; |
| } = /* prettier-ignore */ makeTable( |
| ['bytesPerComponent', 'type', 'componentCount', 'wgslType'] as const, |
| [ , , , ] as const, { |
| // 8 bit components |
| 'uint8x2': [ 1, 'uint', 2, 'vec2<u32>'], |
| 'uint8x4': [ 1, 'uint', 4, 'vec4<u32>'], |
| 'sint8x2': [ 1, 'sint', 2, 'vec2<i32>'], |
| 'sint8x4': [ 1, 'sint', 4, 'vec4<i32>'], |
| 'unorm8x2': [ 1, 'unorm', 2, 'vec2<f32>'], |
| 'unorm8x4': [ 1, 'unorm', 4, 'vec4<f32>'], |
| 'snorm8x2': [ 1, 'snorm', 2, 'vec2<f32>'], |
| 'snorm8x4': [ 1, 'snorm', 4, 'vec4<f32>'], |
| // 16 bit components |
| 'uint16x2': [ 2, 'uint', 2, 'vec2<u32>'], |
| 'uint16x4': [ 2, 'uint', 4, 'vec4<u32>'], |
| 'sint16x2': [ 2, 'sint', 2, 'vec2<i32>'], |
| 'sint16x4': [ 2, 'sint', 4, 'vec4<i32>'], |
| 'unorm16x2': [ 2, 'unorm', 2, 'vec2<f32>'], |
| 'unorm16x4': [ 2, 'unorm', 4, 'vec4<f32>'], |
| 'snorm16x2': [ 2, 'snorm', 2, 'vec2<f32>'], |
| 'snorm16x4': [ 2, 'snorm', 4, 'vec4<f32>'], |
| 'float16x2': [ 2, 'float', 2, 'vec2<f32>'], |
| 'float16x4': [ 2, 'float', 4, 'vec4<f32>'], |
| // 32 bit components |
| 'float32': [ 4, 'float', 1, 'f32'], |
| 'float32x2': [ 4, 'float', 2, 'vec2<f32>'], |
| 'float32x3': [ 4, 'float', 3, 'vec3<f32>'], |
| 'float32x4': [ 4, 'float', 4, 'vec4<f32>'], |
| 'uint32': [ 4, 'uint', 1, 'u32'], |
| 'uint32x2': [ 4, 'uint', 2, 'vec2<u32>'], |
| 'uint32x3': [ 4, 'uint', 3, 'vec3<u32>'], |
| 'uint32x4': [ 4, 'uint', 4, 'vec4<u32>'], |
| 'sint32': [ 4, 'sint', 1, 'i32'], |
| 'sint32x2': [ 4, 'sint', 2, 'vec2<i32>'], |
| 'sint32x3': [ 4, 'sint', 3, 'vec3<i32>'], |
| 'sint32x4': [ 4, 'sint', 4, 'vec4<i32>'] |
| } as const); |
| /** List of all GPUVertexFormat values. */ |
| export const kVertexFormats = keysOf(kVertexFormatInfo); |
| |
| // Typedefs for bindings |
| |
| /** |
| * Classes of `PerShaderStage` binding limits. Two bindings with the same class |
| * count toward the same `PerShaderStage` limit(s) in the spec (if any). |
| */ |
| export type PerStageBindingLimitClass = |
| | 'uniformBuf' |
| | 'storageBuf' |
| | 'sampler' |
| | 'sampledTex' |
| | 'storageTex'; |
| /** |
| * Classes of `PerPipelineLayout` binding limits. Two bindings with the same class |
| * count toward the same `PerPipelineLayout` limit(s) in the spec (if any). |
| */ |
| export type PerPipelineBindingLimitClass = PerStageBindingLimitClass; |
| |
| export type ValidBindableResource = |
| | 'uniformBuf' |
| | 'storageBuf' |
| | 'filtSamp' |
| | 'nonFiltSamp' |
| | 'compareSamp' |
| | 'sampledTex' |
| | 'sampledTexMS' |
| | 'storageTex'; |
| type ErrorBindableResource = 'errorBuf' | 'errorSamp' | 'errorTex'; |
| |
| /** |
| * Types of resource binding which have distinct binding rules, by spec |
| * (e.g. filtering vs non-filtering sampler, multisample vs non-multisample texture). |
| */ |
| export type BindableResource = ValidBindableResource | ErrorBindableResource; |
| export const kBindableResources = [ |
| 'uniformBuf', |
| 'storageBuf', |
| 'filtSamp', |
| 'nonFiltSamp', |
| 'compareSamp', |
| 'sampledTex', |
| 'sampledTexMS', |
| 'storageTex', |
| 'errorBuf', |
| 'errorSamp', |
| 'errorTex', |
| ] as const; |
| assertTypeTrue<TypeEqual<BindableResource, typeof kBindableResources[number]>>(); |
| |
| // Bindings |
| |
| /** Dynamic buffer offsets require offset to be divisible by 256, by spec. */ |
| export const kMinDynamicBufferOffsetAlignment = 256; |
| |
| /** Default `PerShaderStage` binding limits, by spec. */ |
| export const kPerStageBindingLimits: { |
| readonly [k in PerStageBindingLimitClass]: { |
| /** Which `PerShaderStage` binding limit class. */ |
| readonly class: k; |
| /** Maximum number of allowed bindings in that class. */ |
| readonly max: number; |
| // Add fields as needed |
| }; |
| } = /* prettier-ignore */ { |
| 'uniformBuf': { class: 'uniformBuf', max: 12, }, |
| 'storageBuf': { class: 'storageBuf', max: 8, }, |
| 'sampler': { class: 'sampler', max: 16, }, |
| 'sampledTex': { class: 'sampledTex', max: 16, }, |
| 'storageTex': { class: 'storageTex', max: 4, }, |
| }; |
| |
| /** |
| * Default `PerPipelineLayout` binding limits, by spec. |
| */ |
| export const kPerPipelineBindingLimits: { |
| readonly [k in PerPipelineBindingLimitClass]: { |
| /** Which `PerPipelineLayout` binding limit class. */ |
| readonly class: k; |
| /** Maximum number of allowed bindings with `hasDynamicOffset: true` in that class. */ |
| readonly maxDynamic: number; |
| // Add fields as needed |
| }; |
| } = /* prettier-ignore */ { |
| 'uniformBuf': { class: 'uniformBuf', maxDynamic: 8, }, |
| 'storageBuf': { class: 'storageBuf', maxDynamic: 4, }, |
| 'sampler': { class: 'sampler', maxDynamic: 0, }, |
| 'sampledTex': { class: 'sampledTex', maxDynamic: 0, }, |
| 'storageTex': { class: 'storageTex', maxDynamic: 0, }, |
| }; |
| |
| interface BindingKindInfo { |
| readonly resource: ValidBindableResource; |
| readonly perStageLimitClass: typeof kPerStageBindingLimits[PerStageBindingLimitClass]; |
| readonly perPipelineLimitClass: typeof kPerPipelineBindingLimits[PerPipelineBindingLimitClass]; |
| // Add fields as needed |
| } |
| |
| const kBindingKind: { |
| readonly [k in ValidBindableResource]: BindingKindInfo; |
| } = /* prettier-ignore */ { |
| uniformBuf: { resource: 'uniformBuf', perStageLimitClass: kPerStageBindingLimits.uniformBuf, perPipelineLimitClass: kPerPipelineBindingLimits.uniformBuf, }, |
| storageBuf: { resource: 'storageBuf', perStageLimitClass: kPerStageBindingLimits.storageBuf, perPipelineLimitClass: kPerPipelineBindingLimits.storageBuf, }, |
| filtSamp: { resource: 'filtSamp', perStageLimitClass: kPerStageBindingLimits.sampler, perPipelineLimitClass: kPerPipelineBindingLimits.sampler, }, |
| nonFiltSamp: { resource: 'nonFiltSamp', perStageLimitClass: kPerStageBindingLimits.sampler, perPipelineLimitClass: kPerPipelineBindingLimits.sampler, }, |
| compareSamp: { resource: 'compareSamp', perStageLimitClass: kPerStageBindingLimits.sampler, perPipelineLimitClass: kPerPipelineBindingLimits.sampler, }, |
| sampledTex: { resource: 'sampledTex', perStageLimitClass: kPerStageBindingLimits.sampledTex, perPipelineLimitClass: kPerPipelineBindingLimits.sampledTex, }, |
| sampledTexMS: { resource: 'sampledTexMS', perStageLimitClass: kPerStageBindingLimits.sampledTex, perPipelineLimitClass: kPerPipelineBindingLimits.sampledTex, }, |
| storageTex: { resource: 'storageTex', perStageLimitClass: kPerStageBindingLimits.storageTex, perPipelineLimitClass: kPerPipelineBindingLimits.storageTex, }, |
| }; |
| |
| // Binding type info |
| |
| const kValidStagesAll = { |
| validStages: |
| GPUConst.ShaderStage.VERTEX | GPUConst.ShaderStage.FRAGMENT | GPUConst.ShaderStage.COMPUTE, |
| } as const; |
| const kValidStagesStorageWrite = { |
| validStages: GPUConst.ShaderStage.FRAGMENT | GPUConst.ShaderStage.COMPUTE, |
| } as const; |
| |
| /** Binding type info (including class limits) for the specified GPUBufferBindingLayout. */ |
| export function bufferBindingTypeInfo(d: GPUBufferBindingLayout) { |
| /* prettier-ignore */ |
| switch (d.type ?? 'uniform') { |
| case 'uniform': return { usage: GPUConst.BufferUsage.UNIFORM, ...kBindingKind.uniformBuf, ...kValidStagesAll, }; |
| case 'storage': return { usage: GPUConst.BufferUsage.STORAGE, ...kBindingKind.storageBuf, ...kValidStagesStorageWrite, }; |
| case 'read-only-storage': return { usage: GPUConst.BufferUsage.STORAGE, ...kBindingKind.storageBuf, ...kValidStagesAll, }; |
| } |
| } |
| /** List of all GPUBufferBindingType values. */ |
| export const kBufferBindingTypes = ['uniform', 'storage', 'read-only-storage'] as const; |
| assertTypeTrue<TypeEqual<GPUBufferBindingType, typeof kBufferBindingTypes[number]>>(); |
| |
| /** Binding type info (including class limits) for the specified GPUSamplerBindingLayout. */ |
| export function samplerBindingTypeInfo(d: GPUSamplerBindingLayout) { |
| /* prettier-ignore */ |
| switch (d.type ?? 'filtering') { |
| case 'filtering': return { ...kBindingKind.filtSamp, ...kValidStagesAll, }; |
| case 'non-filtering': return { ...kBindingKind.nonFiltSamp, ...kValidStagesAll, }; |
| case 'comparison': return { ...kBindingKind.compareSamp, ...kValidStagesAll, }; |
| } |
| } |
| /** List of all GPUSamplerBindingType values. */ |
| export const kSamplerBindingTypes = ['filtering', 'non-filtering', 'comparison'] as const; |
| assertTypeTrue<TypeEqual<GPUSamplerBindingType, typeof kSamplerBindingTypes[number]>>(); |
| |
| /** Binding type info (including class limits) for the specified GPUTextureBindingLayout. */ |
| export function sampledTextureBindingTypeInfo(d: GPUTextureBindingLayout) { |
| /* prettier-ignore */ |
| if (d.multisampled) { |
| return { usage: GPUConst.TextureUsage.TEXTURE_BINDING, ...kBindingKind.sampledTexMS, ...kValidStagesAll, }; |
| } else { |
| return { usage: GPUConst.TextureUsage.TEXTURE_BINDING, ...kBindingKind.sampledTex, ...kValidStagesAll, }; |
| } |
| } |
| /** List of all GPUTextureSampleType values. */ |
| export const kTextureSampleTypes = [ |
| 'float', |
| 'unfilterable-float', |
| 'depth', |
| 'sint', |
| 'uint', |
| ] as const; |
| assertTypeTrue<TypeEqual<GPUTextureSampleType, typeof kTextureSampleTypes[number]>>(); |
| |
| /** Binding type info (including class limits) for the specified GPUStorageTextureBindingLayout. */ |
| export function storageTextureBindingTypeInfo(d: GPUStorageTextureBindingLayout) { |
| return { |
| usage: GPUConst.TextureUsage.STORAGE_BINDING, |
| ...kBindingKind.storageTex, |
| ...kValidStagesStorageWrite, |
| }; |
| } |
| /** List of all GPUStorageTextureAccess values. */ |
| export const kStorageTextureAccessValues = ['write-only'] as const; |
| assertTypeTrue<TypeEqual<GPUStorageTextureAccess, typeof kStorageTextureAccessValues[number]>>(); |
| |
| /** GPUBindGroupLayoutEntry, but only the "union" fields, not the common fields. */ |
| export type BGLEntry = Omit<GPUBindGroupLayoutEntry, 'binding' | 'visibility'>; |
| /** Binding type info (including class limits) for the specified BGLEntry. */ |
| export function texBindingTypeInfo(e: BGLEntry) { |
| if (e.texture !== undefined) return sampledTextureBindingTypeInfo(e.texture); |
| if (e.storageTexture !== undefined) return storageTextureBindingTypeInfo(e.storageTexture); |
| unreachable(); |
| } |
| /** BindingTypeInfo (including class limits) for the specified BGLEntry. */ |
| export function bindingTypeInfo(e: BGLEntry) { |
| if (e.buffer !== undefined) return bufferBindingTypeInfo(e.buffer); |
| if (e.texture !== undefined) return sampledTextureBindingTypeInfo(e.texture); |
| if (e.sampler !== undefined) return samplerBindingTypeInfo(e.sampler); |
| if (e.storageTexture !== undefined) return storageTextureBindingTypeInfo(e.storageTexture); |
| unreachable('GPUBindGroupLayoutEntry has no BindingLayout'); |
| } |
| |
| /** |
| * Generate a list of possible buffer-typed BGLEntry values. |
| * |
| * Note: Generates different `type` options, but not `hasDynamicOffset` options. |
| */ |
| export function bufferBindingEntries(includeUndefined: boolean): readonly BGLEntry[] { |
| return [ |
| ...(includeUndefined ? [{ buffer: { type: undefined } }] : []), |
| { buffer: { type: 'uniform' } }, |
| { buffer: { type: 'storage' } }, |
| { buffer: { type: 'read-only-storage' } }, |
| ] as const; |
| } |
| /** Generate a list of possible sampler-typed BGLEntry values. */ |
| export function samplerBindingEntries(includeUndefined: boolean): readonly BGLEntry[] { |
| return [ |
| ...(includeUndefined ? [{ sampler: { type: undefined } }] : []), |
| { sampler: { type: 'comparison' } }, |
| { sampler: { type: 'filtering' } }, |
| { sampler: { type: 'non-filtering' } }, |
| ] as const; |
| } |
| /** |
| * Generate a list of possible texture-typed BGLEntry values. |
| * |
| * Note: Generates different `multisampled` options, but not `sampleType` or `viewDimension` options. |
| */ |
| export function textureBindingEntries(includeUndefined: boolean): readonly BGLEntry[] { |
| return [ |
| ...(includeUndefined ? [{ texture: { multisampled: undefined } }] : []), |
| { texture: { multisampled: false } }, |
| { texture: { multisampled: true } }, |
| ] as const; |
| } |
| /** |
| * Generate a list of possible storageTexture-typed BGLEntry values. |
| * |
| * Note: Generates different `access` options, but not `format` or `viewDimension` options. |
| */ |
| export function storageTextureBindingEntries(format: GPUTextureFormat): readonly BGLEntry[] { |
| return [{ storageTexture: { access: 'write-only', format } }] as const; |
| } |
| /** Generate a list of possible texture-or-storageTexture-typed BGLEntry values. */ |
| export function sampledAndStorageBindingEntries( |
| includeUndefined: boolean, |
| storageTextureFormat: GPUTextureFormat = 'rgba8unorm' |
| ): readonly BGLEntry[] { |
| return [ |
| ...textureBindingEntries(includeUndefined), |
| ...storageTextureBindingEntries(storageTextureFormat), |
| ] as const; |
| } |
| /** |
| * Generate a list of possible BGLEntry values of every type, but not variants with different: |
| * - buffer.hasDynamicOffset |
| * - texture.sampleType |
| * - texture.viewDimension |
| * - storageTexture.viewDimension |
| */ |
| export function allBindingEntries( |
| includeUndefined: boolean, |
| storageTextureFormat: GPUTextureFormat = 'rgba8unorm' |
| ): readonly BGLEntry[] { |
| return [ |
| ...bufferBindingEntries(includeUndefined), |
| ...samplerBindingEntries(includeUndefined), |
| ...sampledAndStorageBindingEntries(includeUndefined, storageTextureFormat), |
| ] as const; |
| } |
| |
| // Shader stages |
| |
| /** List of all GPUShaderStage values. */ |
| export type ShaderStageKey = keyof typeof GPUConst.ShaderStage; |
| export const kShaderStageKeys = Object.keys(GPUConst.ShaderStage) as ShaderStageKey[]; |
| export const kShaderStages: readonly GPUShaderStageFlags[] = [ |
| GPUConst.ShaderStage.VERTEX, |
| GPUConst.ShaderStage.FRAGMENT, |
| GPUConst.ShaderStage.COMPUTE, |
| ]; |
| /** List of all possible combinations of GPUShaderStage values. */ |
| export const kShaderStageCombinations: readonly GPUShaderStageFlags[] = [0, 1, 2, 3, 4, 5, 6, 7]; |
| |
| /** |
| * List of all possible texture sampleCount values. |
| * |
| * MAINTENANCE_TODO: Switch existing tests to use kTextureSampleCounts |
| */ |
| export const kTextureSampleCounts = [1, 4] as const; |
| |
| // Blend factors and Blend components |
| |
| /** List of all GPUBlendFactor values. */ |
| export const kBlendFactors: readonly GPUBlendFactor[] = [ |
| 'zero', |
| 'one', |
| 'src', |
| 'one-minus-src', |
| 'src-alpha', |
| 'one-minus-src-alpha', |
| 'dst', |
| 'one-minus-dst', |
| 'dst-alpha', |
| 'one-minus-dst-alpha', |
| 'src-alpha-saturated', |
| 'constant', |
| 'one-minus-constant', |
| ]; |
| |
| /** List of all GPUBlendOperation values. */ |
| export const kBlendOperations: readonly GPUBlendOperation[] = [ |
| 'add', // |
| 'subtract', |
| 'reverse-subtract', |
| 'min', |
| 'max', |
| ]; |
| |
| // Primitive topologies |
| export const kPrimitiveTopology: readonly GPUPrimitiveTopology[] = [ |
| 'point-list', |
| 'line-list', |
| 'line-strip', |
| 'triangle-list', |
| 'triangle-strip', |
| ]; |
| assertTypeTrue<TypeEqual<GPUPrimitiveTopology, typeof kPrimitiveTopology[number]>>(); |
| |
| export const kIndexFormat: readonly GPUIndexFormat[] = ['uint16', 'uint32']; |
| assertTypeTrue<TypeEqual<GPUIndexFormat, typeof kIndexFormat[number]>>(); |
| |
| /** Info for each entry of GPUSupportedLimits */ |
| export const kLimitInfo = /* prettier-ignore */ makeTable( |
| [ 'class', 'default', 'maximumValue'] as const, |
| [ 'maximum', , kMaxUnsignedLongValue] as const, { |
| 'maxTextureDimension1D': [ , 8192, ], |
| 'maxTextureDimension2D': [ , 8192, ], |
| 'maxTextureDimension3D': [ , 2048, ], |
| 'maxTextureArrayLayers': [ , 256, ], |
| |
| 'maxBindGroups': [ , 4, ], |
| 'maxBindingsPerBindGroup': [ , 640, ], |
| 'maxDynamicUniformBuffersPerPipelineLayout': [ , 8, ], |
| 'maxDynamicStorageBuffersPerPipelineLayout': [ , 4, ], |
| 'maxSampledTexturesPerShaderStage': [ , 16, ], |
| 'maxSamplersPerShaderStage': [ , 16, ], |
| 'maxStorageBuffersPerShaderStage': [ , 8, ], |
| 'maxStorageTexturesPerShaderStage': [ , 4, ], |
| 'maxUniformBuffersPerShaderStage': [ , 12, ], |
| |
| 'maxUniformBufferBindingSize': [ , 65536, kMaxUnsignedLongLongValue], |
| 'maxStorageBufferBindingSize': [ , 134217728, kMaxUnsignedLongLongValue], |
| 'minUniformBufferOffsetAlignment': ['alignment', 256, ], |
| 'minStorageBufferOffsetAlignment': ['alignment', 256, ], |
| |
| 'maxVertexBuffers': [ , 8, ], |
| 'maxBufferSize': [ , 268435456, kMaxUnsignedLongLongValue], |
| 'maxVertexAttributes': [ , 16, ], |
| 'maxVertexBufferArrayStride': [ , 2048, ], |
| 'maxInterStageShaderComponents': [ , 60, ], |
| |
| 'maxColorAttachments': [ , 8, ], |
| 'maxColorAttachmentBytesPerSample': [ , 32, ], |
| |
| 'maxComputeWorkgroupStorageSize': [ , 16384, ], |
| 'maxComputeInvocationsPerWorkgroup': [ , 256, ], |
| 'maxComputeWorkgroupSizeX': [ , 256, ], |
| 'maxComputeWorkgroupSizeY': [ , 256, ], |
| 'maxComputeWorkgroupSizeZ': [ , 64, ], |
| 'maxComputeWorkgroupsPerDimension': [ , 65535, ], |
| } as const); |
| |
| /** List of all entries of GPUSupportedLimits. */ |
| export const kLimits = keysOf(kLimitInfo); |
| |
| // Pipeline limits |
| |
| /** Maximum number of color attachments to a render pass, by spec. */ |
| export const kMaxColorAttachments = kLimitInfo.maxColorAttachments.default; |
| /** `maxVertexBuffers` per GPURenderPipeline, by spec. */ |
| export const kMaxVertexBuffers = kLimitInfo.maxVertexBuffers.default; |
| /** `maxVertexAttributes` per GPURenderPipeline, by spec. */ |
| export const kMaxVertexAttributes = kLimitInfo.maxVertexAttributes.default; |
| /** `maxVertexBufferArrayStride` in a vertex buffer in a GPURenderPipeline, by spec. */ |
| export const kMaxVertexBufferArrayStride = kLimitInfo.maxVertexBufferArrayStride.default; |
| |
| /** The size of indirect draw parameters in the indirectBuffer of drawIndirect */ |
| export const kDrawIndirectParametersSize = 4; |
| /** The size of indirect drawIndexed parameters in the indirectBuffer of drawIndexedIndirect */ |
| export const kDrawIndexedIndirectParametersSize = 5; |
| |
| /** Per-GPUFeatureName info. */ |
| export const kFeatureNameInfo: { |
| readonly [k in GPUFeatureName]: {}; |
| } = /* prettier-ignore */ { |
| 'depth-clip-control': {}, |
| 'depth32float-stencil8': {}, |
| 'texture-compression-bc': {}, |
| 'texture-compression-etc2': {}, |
| 'texture-compression-astc': {}, |
| 'timestamp-query': {}, |
| 'indirect-first-instance': {}, |
| 'shader-f16': {}, |
| 'rg11b10ufloat-renderable': {}, |
| }; |
| /** List of all GPUFeatureName values. */ |
| export const kFeatureNames = keysOf(kFeatureNameInfo); |
| |
| /** |
| * Check if two formats are view format compatible. |
| * |
| * This function may need to be generalized to use `baseFormat` from `kTextureFormatInfo`. |
| */ |
| export function viewCompatible(a: GPUTextureFormat, b: GPUTextureFormat): boolean { |
| return a === b || a + '-srgb' === b || b + '-srgb' === a; |
| } |
| |
| export function getFeaturesForFormats<T>( |
| formats: readonly (T & (GPUTextureFormat | undefined))[] |
| ): readonly (GPUFeatureName | undefined)[] { |
| return Array.from(new Set(formats.map(f => (f ? kTextureFormatInfo[f].feature : undefined)))); |
| } |
| |
| export function filterFormatsByFeature<T>( |
| feature: GPUFeatureName | undefined, |
| formats: readonly (T & (GPUTextureFormat | undefined))[] |
| ): readonly (T & (GPUTextureFormat | undefined))[] { |
| return formats.filter(f => f === undefined || kTextureFormatInfo[f].feature === feature); |
| } |
| |
| export const kFeaturesForFormats = getFeaturesForFormats(kTextureFormats); |