UNPKG

typegpu

Version:

A thin layer between JS and WebGPU/WGSL that improves development experience and allows for faster iteration.

247 lines (246 loc) 8.37 kB
import { $internal, $repr } from "../shared/symbols.js"; import { f32 } from "./numeric.js"; export function textureDescriptorToSchema(desc) { if ('multisampled' in desc) { if (desc.multisampled) { if (desc.dimension === '2d') { return textureMultisampled2d(desc.sampleType); } throw new Error(`Multisampled textures only support '2d' dimension, got '${desc.dimension}'`); } switch (desc.dimension) { case '1d': return texture1d(desc.sampleType); case '2d': return texture2d(desc.sampleType); case '2d-array': return texture2dArray(desc.sampleType); case '3d': return texture3d(desc.sampleType); case 'cube': return textureCube(desc.sampleType); case 'cube-array': return textureCubeArray(desc.sampleType); default: throw new Error( // @ts-expect-error `Unsupported texture dimension: '${desc.dimension}'`); } } if (!('access' in desc)) { throw new Error('Descriptor is neither a sampled nor a storage texture'); } switch (desc.dimension) { case '1d': return textureStorage1d(desc.format, desc.access); case '2d': return textureStorage2d(desc.format, desc.access); case '2d-array': return textureStorage2dArray(desc.format, desc.access); case '3d': return textureStorage3d(desc.format, desc.access); default: throw new Error( // @ts-expect-error `Unsupported storage texture dimension: '${desc.dimension}'`); } } function createTexture(type, props) { const isDepth = type.startsWith('texture_depth'); const sampleTypes = isDepth ? ['depth', 'float', 'unfilterable-float'] : props.sampleType.type === 'i32' ? ['sint'] : props.sampleType.type === 'u32' ? ['uint'] : ['float', 'unfilterable-float']; return { [$internal]: {}, [$repr]: undefined, type, bindingSampleType: sampleTypes, ...props, }; } function createStorageTexture(type, props) { return { [$internal]: {}, [$repr]: undefined, type, ...props, }; } const textureCache = new Map(); export const accessModeMap = { 'write-only': 'write', 'read-only': 'read', 'read-write': 'read_write', }; function getOrCreate(key, factory) { let cached = textureCache.get(key); if (!cached) { cached = factory(); textureCache.set(key, cached); } return cached; } export function texture1d(sampleType) { const actualSampleType = (sampleType || f32); const key = `texture_1d<${actualSampleType.type}>`; return getOrCreate(key, () => createTexture('texture_1d', { dimension: '1d', sampleType: actualSampleType, multisampled: false, })); } export function texture2d(sampleType) { const actualSampleType = (sampleType || f32); const key = `texture_2d<${actualSampleType.type}>`; return getOrCreate(key, () => createTexture('texture_2d', { dimension: '2d', sampleType: actualSampleType, multisampled: false, })); } export function textureMultisampled2d(sampleType) { const actualSampleType = (sampleType || f32); const key = `texture_multisampled_2d<${actualSampleType.type}>`; return getOrCreate(key, () => createTexture('texture_multisampled_2d', { dimension: '2d', sampleType: actualSampleType, multisampled: true, })); } export function texture2dArray(sampleType) { const actualSampleType = (sampleType || f32); const key = `texture_2d_array<${actualSampleType.type}>`; return getOrCreate(key, () => createTexture('texture_2d_array', { dimension: '2d-array', sampleType: actualSampleType, multisampled: false, })); } export function textureCube(sampleType) { const actualSampleType = (sampleType || f32); const key = `texture_cube<${actualSampleType.type}>`; return getOrCreate(key, () => createTexture('texture_cube', { dimension: 'cube', sampleType: actualSampleType, multisampled: false, })); } export function textureCubeArray(sampleType) { const actualSampleType = (sampleType || f32); const key = `texture_cube_array<${actualSampleType.type}>`; return getOrCreate(key, () => createTexture('texture_cube_array', { dimension: 'cube-array', sampleType: actualSampleType, multisampled: false, })); } export function texture3d(sampleType) { const actualSampleType = (sampleType || f32); const key = `texture_3d<${actualSampleType.type}>`; return getOrCreate(key, () => createTexture('texture_3d', { dimension: '3d', sampleType: actualSampleType, multisampled: false, })); } export function textureStorage1d(format, access) { const actualAccess = (access || 'write-only'); const key = `texture_storage_1d<${format}, ${accessModeMap[actualAccess]}>`; return getOrCreate(key, () => createStorageTexture('texture_storage_1d', { dimension: '1d', format, access: actualAccess, })); } export function textureStorage2d(format, access) { const actualAccess = (access || 'write-only'); const key = `texture_storage_2d<${format}, ${accessModeMap[actualAccess]}>`; return getOrCreate(key, () => createStorageTexture('texture_storage_2d', { dimension: '2d', format, access: actualAccess, })); } export function textureStorage2dArray(format, access) { const actualAccess = (access || 'write-only'); const key = `texture_storage_2d_array<${format}, ${accessModeMap[actualAccess]}>`; return getOrCreate(key, () => createStorageTexture('texture_storage_2d_array', { dimension: '2d-array', format, access: actualAccess, })); } export function textureStorage3d(format, access) { const actualAccess = (access || 'write-only'); const key = `texture_storage_3d<${format}, ${accessModeMap[actualAccess]}>`; return getOrCreate(key, () => createStorageTexture('texture_storage_3d', { dimension: '3d', format, access: actualAccess, })); } export function textureDepth2d() { const key = 'texture_depth_2d'; return getOrCreate(key, () => createTexture('texture_depth_2d', { dimension: '2d', sampleType: f32, multisampled: false, })); } export function textureDepthMultisampled2d() { const key = 'texture_depth_multisampled_2d'; return getOrCreate(key, () => createTexture('texture_depth_multisampled_2d', { dimension: '2d', sampleType: f32, multisampled: true, })); } export function textureDepth2dArray() { const key = 'texture_depth_2d_array'; return getOrCreate(key, () => createTexture('texture_depth_2d_array', { dimension: '2d-array', sampleType: f32, multisampled: false, })); } export function textureDepthCube() { const key = 'texture_depth_cube'; return getOrCreate(key, () => createTexture('texture_depth_cube', { dimension: 'cube', sampleType: f32, multisampled: false, })); } export function textureDepthCubeArray() { const key = 'texture_depth_cube_array'; return getOrCreate(key, () => createTexture('texture_depth_cube_array', { dimension: 'cube-array', sampleType: f32, multisampled: false, })); } export function textureExternal() { const key = 'texture_external'; return getOrCreate(key, () => ({ [$internal]: {}, [$repr]: undefined, type: 'texture_external', dimension: '2d', })); } export function isWgslTexture(value) { return (!!value[$internal] && typeof value.multisampled === 'boolean'); } export function isWgslStorageTexture(value) { return (!!value[$internal] && typeof value.format === 'string' && typeof value.access === 'string'); } export function isWgslExternalTexture(value) { return (!!value[$internal] && value.type === 'texture_external'); }