From 24947bcfc59912e40e1f20a3150207e14cf2066c Mon Sep 17 00:00:00 2001 From: Ib Green Date: Fri, 13 Sep 2024 22:22:47 +0200 Subject: [PATCH] chore: refactor shader types (#2250) (#2250) --- docs/README.mdx | 14 +- examples/api/animation/app.ts | 4 +- examples/showcase/persistence/app.ts | 8 +- examples/tutorials/hello-cube/app.ts | 4 +- modules/constants/src/index.ts | 1 - modules/constants/src/webgl-types.ts | 5 +- .../get-attribute-from-layouts.ts | 29 +-- modules/core/src/adapter/canvas-context.ts | 2 +- modules/core/src/adapter/device.ts | 16 +- .../core/src/adapter/resources/framebuffer.ts | 2 +- .../src/adapter/resources/render-pipeline.ts | 2 +- .../src/adapter/resources/texture-view.ts | 2 +- modules/core/src/adapter/resources/texture.ts | 2 +- modules/core/src/adapter/types/attachments.ts | 2 +- .../core/src/adapter/types/buffer-layout.ts | 2 +- modules/core/src/adapter/types/parameters.ts | 2 +- .../core/src/adapter/types/shader-layout.ts | 10 +- .../gpu-type-utils/decode-attribute-type.ts | 96 --------- .../src/gpu-type-utils/decode-data-type.ts | 66 ------ .../src/gpu-type-utils/decode-shader-types.ts | 49 ----- .../gpu-type-utils/decode-vertex-format.ts | 53 ----- .../core/src/gpu-type-utils/shader-types.ts | 78 ------- .../src/gpu-type-utils/texture-features.ts | 23 -- .../texture-format-capabilities.ts | 53 ----- .../src/gpu-type-utils/texture-format-info.ts | 42 ---- .../vertex-format-from-attribute.ts | 114 ---------- modules/core/src/gpu-type-utils/wgsl-utils.ts | 22 -- modules/core/src/index.ts | 45 ++-- modules/core/src/portable/uniform-block.ts | 4 +- .../src/portable/uniform-buffer-layout.ts | 12 +- modules/core/src/portable/uniform-store.ts | 4 +- modules/core/src/shadertypes/data-types.ts | 42 ++++ modules/core/src/shadertypes/shader-types.ts | 87 ++++++++ .../texture-formats.ts | 76 +++++++ .../shadertypes/utils/decode-data-types.ts | 113 ++++++++++ .../shadertypes/utils/decode-shader-types.ts | 204 ++++++++++++++++++ .../utils}/decode-texture-format.ts | 57 ++++- .../shadertypes/utils/decode-vertex-format.ts | 119 ++++++++++ .../utils}/texture-format-table.ts | 5 +- .../vertex-formats.ts | 53 ++--- .../get-attribute-from-layout.spec.ts | 21 +- .../adapter/resources/command-encoder.spec.ts | 4 +- .../test/adapter/resources/texture.spec.ts | 6 +- .../decode-attribute-type.spec.ts | 40 ---- .../decode-vertex-format.spec.ts | 38 ---- .../get-texture-format-capabilities.spec.ts | 32 --- modules/core/test/index.ts | 9 +- .../shadertypes/decode-attribute-type.spec.ts | 43 ++++ .../decode-texture-format.spec.ts | 35 ++- .../shadertypes/decode-vertex-format.spec.ts | 61 ++++++ .../vertex-format-from-attribute.spec.ts | 0 .../engine/src/debug/copy-texture-to-image.ts | 54 ++++- modules/engine/src/shader-inputs.ts | 2 +- modules/engine/test/index.ts | 1 + .../utils/split-uniforms-and-bindings.spec.ts | 2 +- .../src/lib/wgsl/get-shader-layout-wgsl.ts | 4 +- modules/shadertools/test/index.ts | 2 +- .../src/adapter/converters/shader-formats.ts | 74 ++++--- .../adapter/converters/webgl-shadertypes.ts | 149 +++++++++++++ .../adapter/converters/webgl-texture-table.ts | 10 +- ...tex-formats.ts => webgl-vertex-formats.ts} | 6 +- .../src/adapter/helpers/decode-webgl-types.ts | 134 ------------ ...yout.ts => get-shader-layout-from-glsl.ts} | 70 ++---- .../webgl/src/adapter/helpers/set-uniform.ts | 4 +- .../src/adapter/helpers/typed-array-utils.ts | 129 ----------- .../adapter/helpers/webgl-texture-utils.ts | 14 +- .../resources/webgl-render-pipeline.ts | 18 +- .../adapter/resources/webgl-texture-view.ts | 2 +- .../adapter/resources/webgl-vertex-array.ts | 2 +- modules/webgl/src/index.ts | 2 +- .../src/utils/split-uniforms-and-bindings.ts | 31 --- .../helpers/get-vertex-buffer-layout.ts | 8 +- package.json | 2 +- website/package.json | 4 +- .../webgl => wip}/wip/constants-to-keys.ts | 0 .../webgl => wip}/wip/deprecated/accessor.ts | 0 .../wip/webgl-renderbuffer.spec.ts | 0 .../webgl => wip}/wip/webgl-renderbuffer.ts | 0 {modules/webgl => wip}/wip/webgl-resource.ts | 0 .../wip/webgl-vertex-array-object.spec.ts | 0 80 files changed, 1263 insertions(+), 1274 deletions(-) delete mode 100644 modules/core/src/gpu-type-utils/decode-attribute-type.ts delete mode 100644 modules/core/src/gpu-type-utils/decode-data-type.ts delete mode 100644 modules/core/src/gpu-type-utils/decode-shader-types.ts delete mode 100644 modules/core/src/gpu-type-utils/decode-vertex-format.ts delete mode 100644 modules/core/src/gpu-type-utils/shader-types.ts delete mode 100644 modules/core/src/gpu-type-utils/texture-features.ts delete mode 100644 modules/core/src/gpu-type-utils/texture-format-capabilities.ts delete mode 100644 modules/core/src/gpu-type-utils/texture-format-info.ts delete mode 100644 modules/core/src/gpu-type-utils/vertex-format-from-attribute.ts delete mode 100644 modules/core/src/gpu-type-utils/wgsl-utils.ts create mode 100644 modules/core/src/shadertypes/data-types.ts create mode 100644 modules/core/src/shadertypes/shader-types.ts rename modules/core/src/{gpu-type-utils => shadertypes}/texture-formats.ts (58%) create mode 100644 modules/core/src/shadertypes/utils/decode-data-types.ts create mode 100644 modules/core/src/shadertypes/utils/decode-shader-types.ts rename modules/core/src/{gpu-type-utils => shadertypes/utils}/decode-texture-format.ts (82%) create mode 100644 modules/core/src/shadertypes/utils/decode-vertex-format.ts rename modules/core/src/{gpu-type-utils => shadertypes/utils}/texture-format-table.ts (98%) rename modules/core/src/{gpu-type-utils => shadertypes}/vertex-formats.ts (60%) delete mode 100644 modules/core/test/gpu-type-utils/decode-attribute-type.spec.ts delete mode 100644 modules/core/test/gpu-type-utils/decode-vertex-format.spec.ts delete mode 100644 modules/core/test/gpu-type-utils/get-texture-format-capabilities.spec.ts create mode 100644 modules/core/test/shadertypes/decode-attribute-type.spec.ts rename modules/core/test/{gpu-type-utils => shadertypes}/decode-texture-format.spec.ts (65%) create mode 100644 modules/core/test/shadertypes/decode-vertex-format.spec.ts rename modules/core/test/{gpu-type-utils => shadertypes}/vertex-format-from-attribute.spec.ts (100%) rename modules/{webgl => engine}/test/utils/split-uniforms-and-bindings.spec.ts (90%) create mode 100644 modules/webgl/src/adapter/converters/webgl-shadertypes.ts rename modules/webgl/src/adapter/converters/{vertex-formats.ts => webgl-vertex-formats.ts} (95%) delete mode 100644 modules/webgl/src/adapter/helpers/decode-webgl-types.ts rename modules/webgl/src/adapter/helpers/{get-shader-layout.ts => get-shader-layout-from-glsl.ts} (84%) delete mode 100644 modules/webgl/src/adapter/helpers/typed-array-utils.ts delete mode 100644 modules/webgl/src/utils/split-uniforms-and-bindings.ts rename {modules/webgl => wip}/wip/constants-to-keys.ts (100%) rename {modules/webgl => wip}/wip/deprecated/accessor.ts (100%) rename {modules/webgl => wip}/wip/webgl-renderbuffer.spec.ts (100%) rename {modules/webgl => wip}/wip/webgl-renderbuffer.ts (100%) rename {modules/webgl => wip}/wip/webgl-resource.ts (100%) rename {modules/webgl => wip}/wip/webgl-vertex-array-object.spec.ts (100%) diff --git a/docs/README.mdx b/docs/README.mdx index e658c4b125..1288b25336 100644 --- a/docs/README.mdx +++ b/docs/README.mdx @@ -52,20 +52,20 @@ Docs for older versions are available on github: luma.gl is a modern GPU toolkit for the Web, created to facilitate processing and visualization of big data. -- **Portable GPU API** - for working with GPUs in JavaScript. -- **TypeScript** - All APIs are rigorously typed. -- **Pluggable backends** - for WebGPU and WebGL . +- **Rendering and Compute** - for computing and rendering with GPUs in JavaScript. +- **WebGPU and WebGL2** - support one or both via luma's pluggable backends. - **Engine-level classes** - `Model`, `Transform` and `AnimationLoop`, as well as scenegraph support. -- **glTF** support. -- **Shader management system** - supports shader modules, dependencies, injection etc. +- **glTF and PBR** support for glTF models and physically based rendering. +- **Shader management system** - supports shader modules, dependencies, injection, transpilation etc. - **Shader module library** - Pre-optimized moduls for compute, visual effects and post processing. +- **TypeScript** - All APIs are rigorously typed. -For 3D math and data loading, luma.gl uses companion framworks: +luma.gl offers extensive support for 3D math and data loading through companion vis.gl framworks: - [**loaders.gl**](https://loaders.gl) - wide range of 3D and geospatial data format standards. - [**math.gl**](https://uber-web.github.io/math.gl/docs) - a variety of high precision geospatial and 3D math logic. -luma.gl is intended to be a foundation on top of which to build higher-level GPU frameworks. The primary example is +luma.gl is a great foundation for building higher-level GPU frameworks. The primary example is - [**deck.gl**](https://deck.gl) - geospatial GPU visualization and compute via a high-performance functional programming API. diff --git a/examples/api/animation/app.ts b/examples/api/animation/app.ts index 1354ab4b97..8335ad3fc9 100644 --- a/examples/api/animation/app.ts +++ b/examples/api/animation/app.ts @@ -1,4 +1,4 @@ -import {UniformStore, ShaderUniformType} from '@luma.gl/core'; +import {UniformStore, VariableShaderType} from '@luma.gl/core'; import { AnimationLoopTemplate, AnimationProps, @@ -24,7 +24,7 @@ type AppUniforms = { uProjection: number[]; }; -const app: {uniformTypes: Record} = { +const app: {uniformTypes: Record} = { uniformTypes: { uColor: 'vec3', uModel: 'mat4x4', diff --git a/examples/showcase/persistence/app.ts b/examples/showcase/persistence/app.ts index a5f64a2a2b..c010c6cb37 100644 --- a/examples/showcase/persistence/app.ts +++ b/examples/showcase/persistence/app.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors -import type {NumberArray, ShaderUniformType} from '@luma.gl/core'; +import type {NumberArray, VariableShaderType} from '@luma.gl/core'; import {UniformStore, Framebuffer} from '@luma.gl/core'; import type {AnimationProps} from '@luma.gl/engine'; import { @@ -26,7 +26,7 @@ type SphereUniforms = { projectionMatrix: NumberArray; }; -const sphere: {uniformTypes: Record} = { +const sphere: {uniformTypes: Record} = { uniformTypes: { // TODO make sure order doesn't matter color: 'vec3', @@ -133,7 +133,7 @@ type ScreenQuadUniforms = { resolution: NumberArray; }; -const screenQuad: {uniformTypes: Record} = { +const screenQuad: {uniformTypes: Record} = { uniformTypes: { resolution: 'vec2' } @@ -216,7 +216,7 @@ type PersistenceQuadUniforms = { resolution: NumberArray; }; -const persistenceQuad: {uniformTypes: Record} = { +const persistenceQuad: {uniformTypes: Record} = { uniformTypes: { resolution: 'vec2' } diff --git a/examples/tutorials/hello-cube/app.ts b/examples/tutorials/hello-cube/app.ts index 263dc99c76..611e3fc0ba 100644 --- a/examples/tutorials/hello-cube/app.ts +++ b/examples/tutorials/hello-cube/app.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors -import type {NumberArray, ShaderUniformType} from '@luma.gl/core'; +import type {NumberArray, VariableShaderType} from '@luma.gl/core'; import {Texture, UniformStore} from '@luma.gl/core'; import type {AnimationProps} from '@luma.gl/engine'; import {AnimationLoopTemplate, Model, CubeGeometry, loadImageBitmap, AsyncTexture} from '@luma.gl/engine'; @@ -97,7 +97,7 @@ type AppUniforms = { mvpMatrix: NumberArray; }; -const app: {uniformTypes: Record} = { +const app: {uniformTypes: Record} = { uniformTypes: { mvpMatrix: 'mat4x4' } diff --git a/modules/constants/src/index.ts b/modules/constants/src/index.ts index 5acb92f436..9fb32a92f4 100644 --- a/modules/constants/src/index.ts +++ b/modules/constants/src/index.ts @@ -16,7 +16,6 @@ export type { GLPixelType, GLUniformType, GLSamplerType, - GLCompositeType, GLFunction, GLBlendEquation, GLBlendFunction, diff --git a/modules/constants/src/webgl-types.ts b/modules/constants/src/webgl-types.ts index 6c375102b4..b156d33ed2 100644 --- a/modules/constants/src/webgl-types.ts +++ b/modules/constants/src/webgl-types.ts @@ -98,9 +98,6 @@ export type GLPixelType = | GL.UNSIGNED_INT_24_8 | GL.FLOAT_32_UNSIGNED_INT_24_8_REV; -/** Uniform Type */ -export type GLUniformType = GLSamplerType | GLCompositeType; - /** * Sampler uniform type * @note These are all the valid sampler types used with `gl.uniform1i((location, value)` @@ -127,7 +124,7 @@ export type GLSamplerType = * @note These are all the valid non-sampler uniform types, * Different `gl.uniformXXX(location, value)` functions must be used depending on which composite type is being set. */ -export type GLCompositeType = +export type GLUniformType = | GL.FLOAT | GL.FLOAT_VEC2 | GL.FLOAT_VEC3 diff --git a/modules/core/src/adapter-utils/get-attribute-from-layouts.ts b/modules/core/src/adapter-utils/get-attribute-from-layouts.ts index 6ebf16af9f..816c837fb0 100644 --- a/modules/core/src/adapter-utils/get-attribute-from-layouts.ts +++ b/modules/core/src/adapter-utils/get-attribute-from-layouts.ts @@ -3,12 +3,16 @@ // Copyright (c) vis.gl contributors import {log} from '../utils/log'; +import type {PrimitiveDataType, NormalizedDataType} from '../shadertypes/data-types'; +import type {AttributeShaderType} from '../shadertypes/shader-types'; +import type {VertexFormat} from '../shadertypes/vertex-formats'; +import {getAttributeShaderTypeInfo} from '../shadertypes/utils/decode-shader-types'; +import { + getVertexFormatInfo, + getCompatibleVertexFormat +} from '../shadertypes/utils/decode-vertex-format'; import type {ShaderLayout, AttributeDeclaration} from '../adapter/types/shader-layout'; import type {BufferLayout} from '../adapter/types/buffer-layout'; -import type {ShaderDataType, ShaderAttributeType} from '../gpu-type-utils/shader-types'; -import {decodeShaderAttributeType} from '../gpu-type-utils/decode-attribute-type'; -import type {VertexFormat, VertexType} from '../gpu-type-utils/vertex-formats'; -import {decodeVertexFormat} from '../gpu-type-utils/decode-vertex-format'; /** Resolved info for a buffer / attribute combination to help backend configure it correctly */ export type AttributeInfo = { @@ -17,9 +21,9 @@ export type AttributeInfo = { /** Location in shader */ location: number; /** Type / precision used in shader (buffer values may be converted) */ - shaderType: ShaderAttributeType; + shaderType: AttributeShaderType; /** Calculations are done in this type in the shader's attribute declaration */ - shaderDataType: ShaderDataType; + primitiveType: PrimitiveDataType; /** Components refer to the number of components in the shader's attribute declaration */ shaderComponents: 1 | 2 | 3 | 4; /** It is the shader attribute declaration that determines whether GPU will process as integer or float */ @@ -30,7 +34,7 @@ export type AttributeInfo = { /** Format of buffer data */ vertexFormat: VertexFormat; /** Memory data type refers to the data type in the buffer */ - bufferDataType: VertexType; + bufferDataType: NormalizedDataType; /** Components refer to the number of components in the buffer's vertex format */ bufferComponents: 1 | 2 | 3 | 4; /** Normalization is encoded in the buffer layout's vertex format... */ @@ -108,16 +112,17 @@ function getAttributeInfoFromLayouts( return null; } - const attributeTypeInfo = decodeShaderAttributeType(shaderDeclaration.type); - const vertexFormat = bufferMapping?.vertexFormat || attributeTypeInfo.defaultVertexFormat; - const vertexFormatInfo = decodeVertexFormat(vertexFormat); + const attributeTypeInfo = getAttributeShaderTypeInfo(shaderDeclaration.type); + const defaultVertexFormat = getCompatibleVertexFormat(attributeTypeInfo); + const vertexFormat = bufferMapping?.vertexFormat || defaultVertexFormat; + const vertexFormatInfo = getVertexFormatInfo(vertexFormat); return { attributeName: bufferMapping?.attributeName || shaderDeclaration.name, bufferName: bufferMapping?.bufferName || shaderDeclaration.name, location: shaderDeclaration.location, shaderType: shaderDeclaration.type, - shaderDataType: attributeTypeInfo.dataType, + primitiveType: attributeTypeInfo.primitiveType, shaderComponents: attributeTypeInfo.components, vertexFormat, bufferDataType: vertexFormatInfo.type, @@ -212,7 +217,7 @@ function getAttributeFromAttributesList( // Calculate a default byte stride if not provided if (typeof bufferLayout.byteStride !== 'number') { for (const attributeMapping of bufferLayout.attributes || []) { - const info = decodeVertexFormat(attributeMapping.format); + const info = getVertexFormatInfo(attributeMapping.format); // @ts-ignore byteStride += info.byteLength; } diff --git a/modules/core/src/adapter/canvas-context.ts b/modules/core/src/adapter/canvas-context.ts index dfb2f94269..d56c0a55f4 100644 --- a/modules/core/src/adapter/canvas-context.ts +++ b/modules/core/src/adapter/canvas-context.ts @@ -7,7 +7,7 @@ import type {Device} from './device'; import type {Framebuffer} from './resources/framebuffer'; import {log} from '../utils/log'; import {uid} from '../utils/uid'; -import type {DepthStencilTextureFormat} from '../gpu-type-utils/texture-formats'; +import type {DepthStencilTextureFormat} from '../shadertypes/texture-formats'; /** Properties for a CanvasContext */ export type CanvasContextProps = { diff --git a/modules/core/src/adapter/device.ts b/modules/core/src/adapter/device.ts index 6eee7ae666..aadda02e1e 100644 --- a/modules/core/src/adapter/device.ts +++ b/modules/core/src/adapter/device.ts @@ -5,7 +5,7 @@ import {StatsManager, lumaStats} from '../utils/stats-manager'; import {log} from '../utils/log'; import {uid} from '../utils/uid'; -import type {TextureFormat} from '../gpu-type-utils/texture-formats'; +import type {TextureFormat, TextureFormatInfo} from '../shadertypes/texture-formats'; import type {CanvasContext, CanvasContextProps} from './canvas-context'; import type {BufferProps} from './resources/buffer'; import {Buffer} from './resources/buffer'; @@ -23,14 +23,14 @@ import type {VertexArray, VertexArrayProps} from './resources/vertex-array'; import type {TransformFeedback, TransformFeedbackProps} from './resources/transform-feedback'; import type {QuerySet, QuerySetProps} from './resources/query-set'; -import type {ExternalImage} from '../image-utils/image-types'; -import {isExternalImage, getExternalImageSize} from '../image-utils/image-types'; import { isTextureFormatCompressed, - decodeTextureFormat -} from '../gpu-type-utils/decode-texture-format'; -import {getTextureFormatCapabilities} from '../gpu-type-utils/texture-format-capabilities'; -import type {TextureFormatInfo} from '../gpu-type-utils/texture-format-info'; + getTextureFormatInfo, + getTextureFormatCapabilities +} from '../shadertypes/utils/decode-texture-format'; + +import type {ExternalImage} from '../image-utils/image-types'; +import {isExternalImage, getExternalImageSize} from '../image-utils/image-types'; /** * Identifies the GPU vendor and driver. @@ -395,7 +395,7 @@ export abstract class Device { /** Returns information about a texture format, such as data type, channels, bits per channel, compression etc */ getTextureFormatInfo(format: TextureFormat): TextureFormatInfo { - return decodeTextureFormat(format); + return getTextureFormatInfo(format); } /** Determines what operations are supported on a texture format on this particular device (checks against supported device features) */ diff --git a/modules/core/src/adapter/resources/framebuffer.ts b/modules/core/src/adapter/resources/framebuffer.ts index a45b88c804..6010c102db 100644 --- a/modules/core/src/adapter/resources/framebuffer.ts +++ b/modules/core/src/adapter/resources/framebuffer.ts @@ -6,7 +6,7 @@ import type { ColorTextureFormat, DepthStencilTextureFormat, TextureFormat -} from '../../gpu-type-utils/texture-formats'; +} from '../../shadertypes/texture-formats'; import type {Device} from '../device'; import {Resource, ResourceProps} from './resource'; import {Texture} from './texture'; diff --git a/modules/core/src/adapter/resources/render-pipeline.ts b/modules/core/src/adapter/resources/render-pipeline.ts index fb8bf10f45..fdb24c342e 100644 --- a/modules/core/src/adapter/resources/render-pipeline.ts +++ b/modules/core/src/adapter/resources/render-pipeline.ts @@ -10,7 +10,7 @@ import type {BufferLayout} from '../types/buffer-layout'; import type { ColorTextureFormat, DepthStencilTextureFormat -} from '@luma.gl/core/gpu-type-utils/texture-formats'; +} from '@luma.gl/core/shadertypes/texture-formats'; import type {Shader} from './shader'; import type {RenderPass} from './render-pass'; import {Resource, ResourceProps} from './resource'; diff --git a/modules/core/src/adapter/resources/texture-view.ts b/modules/core/src/adapter/resources/texture-view.ts index 9f6e4efa47..9e8157dc71 100644 --- a/modules/core/src/adapter/resources/texture-view.ts +++ b/modules/core/src/adapter/resources/texture-view.ts @@ -4,7 +4,7 @@ import type {Device} from '../device'; import type {Texture} from './texture'; -import type {TextureFormat} from '../../gpu-type-utils/texture-formats'; +import type {TextureFormat} from '../../shadertypes/texture-formats'; import {Resource, ResourceProps} from './resource'; /** Properties for initializing a texture view */ diff --git a/modules/core/src/adapter/resources/texture.ts b/modules/core/src/adapter/resources/texture.ts index 3b2e041ca1..374215a8bb 100644 --- a/modules/core/src/adapter/resources/texture.ts +++ b/modules/core/src/adapter/resources/texture.ts @@ -4,7 +4,7 @@ import {TypedArray} from '@math.gl/types'; import type {Device} from '../device'; -import type {TextureFormat} from '../../gpu-type-utils/texture-formats'; +import type {TextureFormat} from '../../shadertypes/texture-formats'; import type {TextureView, TextureViewProps} from './texture-view'; import {Resource, ResourceProps} from './resource'; import {Sampler, SamplerProps} from './sampler'; diff --git a/modules/core/src/adapter/types/attachments.ts b/modules/core/src/adapter/types/attachments.ts index 4d717ec15e..b3f8073410 100644 --- a/modules/core/src/adapter/types/attachments.ts +++ b/modules/core/src/adapter/types/attachments.ts @@ -6,7 +6,7 @@ import type { ColorTextureFormat, DepthStencilTextureFormat, TextureFormat -} from '../../gpu-type-utils/texture-formats'; +} from '../../shadertypes/texture-formats'; import type {Texture} from '../resources/texture'; // TextureView... import type {TextureView} from '../resources/texture-view'; // TextureView... diff --git a/modules/core/src/adapter/types/buffer-layout.ts b/modules/core/src/adapter/types/buffer-layout.ts index 58c619346e..069272cb87 100644 --- a/modules/core/src/adapter/types/buffer-layout.ts +++ b/modules/core/src/adapter/types/buffer-layout.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors -import type {VertexFormat} from '../../gpu-type-utils/vertex-formats'; +import type {VertexFormat} from '../../shadertypes/vertex-formats'; /** * Provides specific details about the memory layout of the actual buffers diff --git a/modules/core/src/adapter/types/parameters.ts b/modules/core/src/adapter/types/parameters.ts index 7fd5cb0c84..b41b88dc33 100644 --- a/modules/core/src/adapter/types/parameters.ts +++ b/modules/core/src/adapter/types/parameters.ts @@ -3,7 +3,7 @@ // Copyright (c) vis.gl contributors import {NumberArray4, NumberArray6} from '@math.gl/types'; -import {DepthStencilTextureFormat} from '../../gpu-type-utils/texture-formats'; +import {DepthStencilTextureFormat} from '../../shadertypes/texture-formats'; export type CompareFunction = | 'never' diff --git a/modules/core/src/adapter/types/shader-layout.ts b/modules/core/src/adapter/types/shader-layout.ts index fb802153f7..faa20dd4df 100644 --- a/modules/core/src/adapter/types/shader-layout.ts +++ b/modules/core/src/adapter/types/shader-layout.ts @@ -2,8 +2,8 @@ // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors -import type {TextureFormat} from '../../gpu-type-utils/texture-formats'; -import type {ShaderUniformType, ShaderAttributeType} from '../../gpu-type-utils/shader-types'; +import type {TextureFormat} from '../../shadertypes/texture-formats'; +import type {VariableShaderType, AttributeShaderType} from '../../shadertypes/shader-types'; import type {Buffer} from '../resources/buffer'; import type {Sampler} from '../resources/sampler'; import type {Texture} from '../resources/texture'; @@ -56,7 +56,7 @@ export type AttributeDeclaration = { /** The index into the GPU's vertex array buffer bank (usually between 0-15) */ location: number; /** WebGPU-style shader type. The declared format of the attribute in the shader code. Buffer's vertex format needs to map to this. */ - type: ShaderAttributeType; + type: AttributeShaderType; /** Inferred from attribute name. @note Technically not part of static structure of shader */ stepMode?: 'vertex' | 'instance'; }; @@ -89,7 +89,7 @@ export type UniformBufferBindingLayout = { export type UniformInfo = { name: string; - format: ShaderUniformType; + format: VariableShaderType; type?: string; arrayLength: number; byteOffset: number; @@ -172,7 +172,7 @@ export type Binding = export type VaryingBinding = { location: number; name: string; - type: number; // glType + type: AttributeShaderType; size: number; }; diff --git a/modules/core/src/gpu-type-utils/decode-attribute-type.ts b/modules/core/src/gpu-type-utils/decode-attribute-type.ts deleted file mode 100644 index 2ad4ba9568..0000000000 --- a/modules/core/src/gpu-type-utils/decode-attribute-type.ts +++ /dev/null @@ -1,96 +0,0 @@ -// luma.gl -// SPDX-License-Identifier: MIT -// Copyright (c) vis.gl contributors - -import {ShaderDataType, ShaderAttributeType} from './shader-types'; -import {VertexFormat, VertexType} from './vertex-formats'; - -/** Information extracted from a ShaderAttributeInfo constant */ -export type ShaderAttributeTypeInfo = { - /** WGSL-style primitive data type, f32, i32, u32 */ - dataType: ShaderDataType; - /** Whether this is a normalized integer (that must be used as float) */ - components: 1 | 2 | 3 | 4; - /** Length in bytes of the data for one vertex */ - byteLength?: number; - /** Whether this is for integer or float vert */ - integer: boolean; - /** Whether this data type is signed */ - signed: boolean; - /** The simplest vertex format that matches the shader attribute's data type */ - defaultVertexFormat: VertexFormat; -}; - -/** Decodes a vertex type, returning byte length and flags (integer, signed, normalized) */ -export function decodeShaderAttributeType( - attributeType: ShaderAttributeType -): ShaderAttributeTypeInfo { - const [dataType, components] = TYPE_INFO[attributeType]; - const integer: boolean = dataType === 'i32' || dataType === 'u32'; - const signed: boolean = dataType !== 'u32'; - - const byteLength = TYPE_SIZES[dataType] * components; - const defaultVertexFormat = getCompatibleVertexFormat(dataType, components); - return { - dataType, - components, - defaultVertexFormat, - byteLength, - integer, - signed - }; -} - -/** Get the "default" vertex format for a certain shader data type */ -function getCompatibleVertexFormat( - dataType: ShaderDataType, - components: 1 | 2 | 3 | 4 -): VertexFormat { - let vertexType: VertexType; - switch (dataType) { - case 'f32': - vertexType = 'float32'; - break; - case 'i32': - vertexType = 'sint32'; - break; - case 'u32': - vertexType = 'uint32'; - break; - case 'f16': - return components <= 2 ? 'float16x2' : 'float16x4'; - } - // TODO logic does not work for float16 - if (components === 1) { - return vertexType; - } - return `${vertexType}x${components}`; -} - -/** All valid shader attribute types. A table guarantees exhaustive list and fast execution */ -const TYPE_INFO: Record = { - f32: ['f32', 1], - 'vec2': ['f32', 2], - 'vec3': ['f32', 3], - 'vec4': ['f32', 4], - f16: ['f16', 1], - 'vec2': ['f16', 2], - 'vec3': ['f16', 3], - 'vec4': ['f16', 4], - i32: ['i32', 1], - 'vec2': ['i32', 2], - 'vec3': ['i32', 3], - 'vec4': ['i32', 4], - u32: ['u32', 1], - 'vec2': ['u32', 2], - 'vec3': ['u32', 3], - 'vec4': ['u32', 4] -}; - -const TYPE_SIZES: Record = { - f32: 4, - f16: 2, - i32: 4, - u32: 4 - // 'bool-webgl': 4, -}; diff --git a/modules/core/src/gpu-type-utils/decode-data-type.ts b/modules/core/src/gpu-type-utils/decode-data-type.ts deleted file mode 100644 index eab9b2fd65..0000000000 --- a/modules/core/src/gpu-type-utils/decode-data-type.ts +++ /dev/null @@ -1,66 +0,0 @@ -// luma.gl -// SPDX-License-Identifier: MIT -// Copyright (c) vis.gl contributors - -import {DataType, NormalizedDataType} from './vertex-formats'; - -export type DecodedVertexType = { - /** WebGPU data type */ - dataType: DataType; - /** Length in bytes of the data for one vertex */ - byteLength: number; - /** Whether this is for integer or float vert */ - integer: boolean; - /** Whether this data type is signed */ - signed: boolean; - /** Whether this is a normalized integer (that must be used as float) */ - normalized: boolean; -}; - -/** Decodes a vertex type, returning byte length and flags (integer, signed, normalized) */ -export function decodeVertexType(type: NormalizedDataType): DecodedVertexType { - const dataType = TYPE_MAP[type]; - const bytes = getDataTypeBytes(dataType); - const normalized: boolean = type.includes('norm'); - const integer: boolean = !normalized && !type.startsWith('float'); - const signed: boolean = type.startsWith('s'); - return { - dataType: TYPE_MAP[type], - byteLength: bytes, - integer, - signed, - normalized - }; -} - -function getDataTypeBytes(type: DataType): number { - const bytes = TYPE_SIZES[type]; - // assert(bytes); - return bytes; -} - -const TYPE_MAP: Record = { - uint8: 'uint8', - sint8: 'sint8', - unorm8: 'uint8', - snorm8: 'sint8', - uint16: 'uint16', - sint16: 'sint16', - unorm16: 'uint16', - snorm16: 'sint16', - float16: 'float16', - float32: 'float32', - uint32: 'uint32', - sint32: 'sint32' -}; - -const TYPE_SIZES: Record = { - uint8: 1, - sint8: 1, - uint16: 2, - sint16: 2, - float16: 2, - float32: 4, - uint32: 4, - sint32: 4 -}; diff --git a/modules/core/src/gpu-type-utils/decode-shader-types.ts b/modules/core/src/gpu-type-utils/decode-shader-types.ts deleted file mode 100644 index a9c48c73c0..0000000000 --- a/modules/core/src/gpu-type-utils/decode-shader-types.ts +++ /dev/null @@ -1,49 +0,0 @@ -// luma.gl -// SPDX-License-Identifier: MIT -// Copyright (c) vis.gl contributors - -import {ShaderUniformType, ShaderDataType} from './shader-types'; - -const UNIFORM_FORMATS: Record = { - f32: {type: 'f32', components: 1}, - i32: {type: 'i32', components: 1}, - u32: {type: 'u32', components: 1}, - // 'bool-webgl': {type: 'bool-webgl', components: 1}, - 'vec2': {type: 'f32', components: 2}, - 'vec3': {type: 'f32', components: 3}, - 'vec4': {type: 'f32', components: 4}, - 'vec2': {type: 'i32', components: 2}, - 'vec3': {type: 'i32', components: 3}, - 'vec4': {type: 'i32', components: 4}, - 'vec2': {type: 'u32', components: 2}, - 'vec3': {type: 'u32', components: 3}, - 'vec4': {type: 'u32', components: 4}, - 'mat2x2': {type: 'f32', components: 4}, - 'mat2x3': {type: 'f32', components: 6}, - 'mat2x4': {type: 'f32', components: 8}, - 'mat3x2': {type: 'f32', components: 6}, - 'mat3x3': {type: 'f32', components: 9}, - 'mat3x4': {type: 'f32', components: 12}, - 'mat4x2': {type: 'f32', components: 8}, - 'mat4x3': {type: 'f32', components: 12}, - 'mat4x4': {type: 'f32', components: 16} -}; - -/** Split a uniform type string into type and components */ -export function decodeShaderUniformType(format: ShaderUniformType): { - type: ShaderDataType; - components: number; -} { - const decoded = UNIFORM_FORMATS[format]; - return decoded; -} - -/** Align offset to 1, 2 or 4 elements (4, 8 or 16 bytes) */ -export function alignTo(size: number, count: number): number { - // prettier-ignore - switch (count) { - case 1: return size; // Pad upwards to even multiple of 2 - case 2: return size + (size % 2); // Pad upwards to even multiple of 2 - default: return size + ((4 - (size % 4)) % 4); // Pad upwards to even multiple of 4 - } -} diff --git a/modules/core/src/gpu-type-utils/decode-vertex-format.ts b/modules/core/src/gpu-type-utils/decode-vertex-format.ts deleted file mode 100644 index f6af83cb71..0000000000 --- a/modules/core/src/gpu-type-utils/decode-vertex-format.ts +++ /dev/null @@ -1,53 +0,0 @@ -// luma.gl -// SPDX-License-Identifier: MIT -// Copyright (c) vis.gl contributors - -import {VertexFormat, VertexType} from './vertex-formats'; -import {decodeVertexType} from './decode-data-type'; - -export type VertexFormatInfo = { - /** Length in bytes */ - byteLength: number; - /** Type of each component */ - type: VertexType; - /** Number of components per vertex / row */ - components: 1 | 2 | 3 | 4; - /** Is this an integer format (normalized integer formats are not integer) */ - integer: boolean; - /** Is this a signed format? */ - signed: boolean; - /** Is this a normalized format? */ - normalized: boolean; - /** Is this a webgl only format? */ - webglOnly?: boolean; -}; - -/** - * Decodes a vertex format, returning type, components, byte length and flags (integer, signed, normalized) - */ -export function decodeVertexFormat(format: VertexFormat): VertexFormatInfo { - // Strip the -webgl ending if present - let webglOnly: boolean | undefined; - if (format.endsWith('-webgl')) { - format.replace('-webgl', ''); - webglOnly = true; - } - // split components from type - const [type_, count] = format.split('x'); - const type = type_ as VertexType; - const components = (count ? parseInt(count) : 1) as 1 | 2 | 3 | 4; - // decode the type - const decodedType = decodeVertexType(type); - const result: VertexFormatInfo = { - type, - components, - byteLength: decodedType.byteLength * components, - integer: decodedType.integer, - signed: decodedType.signed, - normalized: decodedType.normalized - }; - if (webglOnly) { - result.webglOnly = true; - } - return result; -} diff --git a/modules/core/src/gpu-type-utils/shader-types.ts b/modules/core/src/gpu-type-utils/shader-types.ts deleted file mode 100644 index 0a024c39c7..0000000000 --- a/modules/core/src/gpu-type-utils/shader-types.ts +++ /dev/null @@ -1,78 +0,0 @@ -// luma.gl -// SPDX-License-Identifier: MIT -// Copyright (c) vis.gl contributors - -/** - * Primitive data types understood by shaders - * @note These types describe the type used in shader calculations, but for attribute inputs these can be populated from a different in-memory type. - * @note bindings (like textures, samplers, and uniform buffers) are considered "bindings", not types - * @note `f16` requires the `f16` extension - */ -export type ShaderDataType = 'u32' | 'i32' | 'f32' | 'f16'; - -/** - * Describes the type of an attribute as defined in the shader source code. - * @note Buffers with various `VertexFormat`s can be supplied for each type, and the GPU will convert them at runtime, - * but there are limitations, see documentation for details. - */ -export type ShaderAttributeType = - | 'f32' - | 'vec2' - | 'vec3' - | 'vec4' - | 'i32' - | 'vec2' - | 'vec3' - | 'vec4' - | 'u32' - | 'vec2' - | 'vec3' - | 'vec4' - // requires `f16` extension - | 'f16' - | 'vec2' - | 'vec3' - | 'vec4'; - -/** - * Describes the type of a uniform as described in the shader source code. - * Uniforms can be of a wider range of types than attributes. - */ -export type ShaderUniformType = - | 'f32' - | 'i32' - | 'u32' - | 'vec2' - | 'vec3' - | 'vec4' - | 'vec2' - | 'vec3' - | 'vec4' - | 'vec2' - | 'vec3' - | 'vec4' - | 'mat2x2' - | 'mat2x3' - | 'mat2x4' - | 'mat3x2' - | 'mat3x3' - | 'mat3x4' - | 'mat4x2' - | 'mat4x3' - | 'mat4x4'; - -/** Shorthand type aliases recognized by WGSL */ -export type ShaderTypeAlias = - | 'vec2i' - | 'vec3i' - | 'vec4i' - | 'vec2u' - | 'vec3u' - | 'vec4u' - | 'vec2f' - | 'vec3f' - | 'vec4f' - // Requires the f16 extension. - | 'vec2h' - | 'vec3h' - | 'vec4h'; diff --git a/modules/core/src/gpu-type-utils/texture-features.ts b/modules/core/src/gpu-type-utils/texture-features.ts deleted file mode 100644 index 249254785d..0000000000 --- a/modules/core/src/gpu-type-utils/texture-features.ts +++ /dev/null @@ -1,23 +0,0 @@ -// luma.gl -// SPDX-License-Identifier: MIT -// Copyright (c) vis.gl contributors - -/** - * Texture feature checks - * @note these must be a subset of DeviceFeatures. - */ -export type TextureFeature = - | 'texture-compression-bc' - | 'texture-compression-astc' - | 'texture-compression-etc2' - | 'texture-compression-etc1-webgl' - | 'texture-compression-pvrtc-webgl' - | 'texture-compression-atc-webgl' - | 'float32-renderable-webgl' - | 'float16-renderable-webgl' - | 'rgb9e5ufloat-renderable-webgl' - | 'snorm8-renderable-webgl' - | 'norm16-renderable-webgl' - | 'snorm16-renderable-webgl' - | 'float32-filterable' - | 'float16-filterable-webgl'; diff --git a/modules/core/src/gpu-type-utils/texture-format-capabilities.ts b/modules/core/src/gpu-type-utils/texture-format-capabilities.ts deleted file mode 100644 index d025a9ccf3..0000000000 --- a/modules/core/src/gpu-type-utils/texture-format-capabilities.ts +++ /dev/null @@ -1,53 +0,0 @@ -// luma.gl -// SPDX-License-Identifier: MIT -// Copyright (c) vis.gl contributors - -import type {TextureFormat} from './texture-formats'; -import type {TextureFeature} from './texture-features'; -import {decodeTextureFormat} from './decode-texture-format'; - -import {getTextureFormatDefinition} from './texture-format-table'; - -/** - * Texture format capabilities. - * @note Not directly usable. Can contain TextureFeature strings that need to be checked against a specific device. - */ -export type TextureFormatCapabilities = { - format: TextureFormat; - /** Can the format be created */ - create: TextureFeature | boolean; - /** If a feature string, the specified device feature determines if format is renderable. */ - render: TextureFeature | boolean; - /** If a feature string, the specified device feature determines if format is filterable. */ - filter: TextureFeature | boolean; - /** If a feature string, the specified device feature determines if format is blendable. */ - blend: TextureFeature | boolean; - /** If a feature string, the specified device feature determines if format is storeable. */ - store: TextureFeature | boolean; -}; - -export function getTextureFormatCapabilities(format: TextureFormat): TextureFormatCapabilities { - const info = getTextureFormatDefinition(format); - - const formatCapabilities: Required = { - format, - create: info.f ?? true, - render: info.render ?? true, - filter: info.filter ?? true, - blend: info.blend ?? true, - store: info.store ?? true - }; - - const formatInfo = decodeTextureFormat(format); - const isDepthStencil = format.startsWith('depth') || format.startsWith('stencil'); - const isSigned = formatInfo?.signed; - const isInteger = formatInfo?.integer; - const isWebGLSpecific = formatInfo?.webgl; - - // signed formats are not renderable - formatCapabilities.render &&= !isSigned; - // signed and integer formats are not filterable - formatCapabilities.filter &&= !isDepthStencil && !isSigned && !isInteger && !isWebGLSpecific; - - return formatCapabilities; -} diff --git a/modules/core/src/gpu-type-utils/texture-format-info.ts b/modules/core/src/gpu-type-utils/texture-format-info.ts deleted file mode 100644 index 1c4cae0bcb..0000000000 --- a/modules/core/src/gpu-type-utils/texture-format-info.ts +++ /dev/null @@ -1,42 +0,0 @@ -// luma.gl -// SPDX-License-Identifier: MIT -// Copyright (c) vis.gl contributors - -import {TextureFormat} from './texture-formats'; -import {VertexType} from './vertex-formats'; - -/** Information about the structure of a texture format */ -export type TextureFormatInfo = { - /** The format that is described */ - format: TextureFormat; - /** Color or depth stencil attachment formats */ - attachment?: 'color' | 'depth' | 'stencil' | 'depth-stencil'; - /** String describing which channels this texture has */ - channels: 'r' | 'rg' | 'rgb' | 'rgba' | 'bgra'; - /** Number of components (corresponds to channels string) */ - components: 1 | 2 | 3 | 4; - /** What is the data type of each component */ - dataType?: VertexType; - /** If this is a packed data type */ - packed?: boolean; - /** Number of bytes per pixel */ - bytesPerPixel?: number; - /** Number of bits per channel (may be unreliable for packed formats) */ - bitsPerChannel: [number, number, number, number]; - /** SRGB texture format? */ - srgb?: boolean; - /** WebGL specific texture format? */ - webgl?: boolean; - /** Is this an integer or floating point format? */ - integer: boolean; - /** Is this a signed or unsigned format? */ - signed: boolean; - /** Is this a normalized integer format? */ - normalized: boolean; - /** Is this a compressed texture format */ - compressed?: boolean; - /** Compressed formats only: Block size for ASTC formats (texture width must be a multiple of this value) */ - blockWidth?: number; - /** Compressed formats only: Block size for ASTC formats (texture height must be a multiple of this value) */ - blockHeight?: number; -}; diff --git a/modules/core/src/gpu-type-utils/vertex-format-from-attribute.ts b/modules/core/src/gpu-type-utils/vertex-format-from-attribute.ts deleted file mode 100644 index 138f0ea7d9..0000000000 --- a/modules/core/src/gpu-type-utils/vertex-format-from-attribute.ts +++ /dev/null @@ -1,114 +0,0 @@ -// luma.gl -// SPDX-License-Identifier: MIT -// Copyright (c) vis.gl contributors - -import {TypedArray, TypedArrayConstructor} from '../types'; -import {VertexFormat} from './vertex-formats'; - -// import {DataType} from '../types/vertex-formats'; -// type Omit unfortunately breaks Typescript inferance -type DataType = 'uint8' | 'sint8' | 'uint16' | 'sint16' | 'uint32' | 'sint32' | 'float32'; -type DataTypeNorm = 'unorm8' | 'snorm8' | 'unorm16' | 'snorm16'; - -export function getDataTypeFromTypedArray( - arrayOrType: TypedArray | TypedArrayConstructor -): DataType { - const type = ArrayBuffer.isView(arrayOrType) ? arrayOrType.constructor : arrayOrType; - switch (type) { - case Float32Array: - return 'float32'; - case Uint16Array: - return 'uint16'; - case Uint32Array: - return 'uint32'; - case Uint8Array: - case Uint8ClampedArray: - return 'uint8'; - case Int8Array: - return 'sint8'; - case Int16Array: - return 'sint16'; - case Int32Array: - return 'sint32'; - default: - // Failed to deduce data type from typed array - throw new Error(type.constructor.name); - } -} - -export function getTypedArrayFromDataType( - dataType: DataType | DataTypeNorm -): TypedArrayConstructor { - switch (dataType) { - case 'float32': - return Float32Array; - case 'uint32': - return Uint32Array; - case 'sint32': - return Int32Array; - case 'uint16': - case 'unorm16': - return Uint16Array; - case 'sint16': - case 'snorm16': - return Int16Array; - case 'uint8': - case 'unorm8': - return Uint8Array; - case 'sint8': - case 'snorm8': - return Int8Array; - default: - // Failed to deduce typed array from data type - throw new Error(dataType); - } -} - -/** Get the vertex format for an attribute with TypedArray and size */ -export function getVertexFormatFromAttribute( - typedArray: TypedArray, - size: number, - normalized?: boolean -): VertexFormat { - if (!size || size > 4) { - throw new Error(`size ${size}`); - } - - const components = size as 1 | 2 | 3 | 4; - let dataType: DataType | DataTypeNorm = getDataTypeFromTypedArray(typedArray); - - // TODO - Special cases for WebGL (not supported on WebGPU), overrides the check below - if (dataType === 'uint8' && normalized && components === 1) { - return 'unorm8-webgl'; - } - if (dataType === 'uint8' && normalized && components === 3) { - return 'unorm8x3-webgl'; - } - - if (dataType === 'uint8' || dataType === 'sint8') { - if (components === 1 || components === 3) { - // WebGPU 8 bit formats must be aligned to 16 bit boundaries'); - throw new Error(`size: ${size}`); - } - if (normalized) { - dataType = dataType.replace('int', 'norm') as 'unorm8' | 'snorm8'; - } - return `${dataType}x${components}`; - } - if (dataType === 'uint16' || dataType === 'sint16') { - if (components === 1 || components === 3) { - // WebGPU 16 bit formats must be aligned to 32 bit boundaries - throw new Error(`size: ${size}`); - } - if (normalized) { - dataType = dataType.replace('int', 'norm') as 'unorm16' | 'snorm16'; - } - return `${dataType}x${components}`; - } - - if (components === 1) { - return dataType; - } - - return `${dataType}x${components}`; -} diff --git a/modules/core/src/gpu-type-utils/wgsl-utils.ts b/modules/core/src/gpu-type-utils/wgsl-utils.ts deleted file mode 100644 index f363519a12..0000000000 --- a/modules/core/src/gpu-type-utils/wgsl-utils.ts +++ /dev/null @@ -1,22 +0,0 @@ -// luma.gl -// SPDX-License-Identifier: MIT -// Copyright (c) vis.gl contributors - -import {ShaderAttributeType} from './shader-types'; - -/** Predeclared aliases @see https://www.w3.org/TR/WGSL/#vector-types */ -export const WGSL_TYPE_ALIAS_MAP: Record = { - vec2i: 'vec2', - vec3i: 'vec3', - vec4i: 'vec4', - vec2u: 'vec2', - vec3u: 'vec3', - vec4u: 'vec4', - vec2f: 'vec2', - vec3f: 'vec3', - vec4f: 'vec4', - // Requires the f16 extension. - vec2h: 'vec2', - vec3h: 'vec3', - vec4h: 'vec4' -}; diff --git a/modules/core/src/index.ts b/modules/core/src/index.ts index 06c517b6c9..ca8d0a62a5 100644 --- a/modules/core/src/index.ts +++ b/modules/core/src/index.ts @@ -126,32 +126,37 @@ export type {UniformValue} from './adapter/types/uniforms'; // GPU TYPE UTILS - GPU MEMORY LAYOUT TYPES - EXTERNAL export type {NumberArray, TypedArray, TypedArrayConstructor} from './types'; -export type {VertexFormat, VertexType} from './gpu-type-utils/vertex-formats'; -export type { - ShaderDataType, - ShaderAttributeType, - ShaderUniformType -} from './gpu-type-utils/shader-types'; +export type {PrimitiveDataType, SignedDataType, NormalizedDataType} from './shadertypes/data-types'; +export type {AttributeShaderType, VariableShaderType} from './shadertypes/shader-types'; +export type {VertexFormat} from './shadertypes/vertex-formats'; export type { TextureFormat, ColorTextureFormat, DepthStencilTextureFormat, - TextureCompression -} from './gpu-type-utils/texture-formats'; -export type {TextureFormatInfo} from './gpu-type-utils/texture-format-info'; -export type {TextureFormatCapabilities} from './gpu-type-utils/texture-format-capabilities'; + TextureCompression, + TextureFormatInfo, + TextureFormatCapabilities +} from './shadertypes/texture-formats'; // GPU TYPE UTILS - GPU MEMORY LAYOUT HELPERS - CAN BE USED BY APPS BUT MOSTLY USED INTERNALLY -export {decodeVertexFormat} from './gpu-type-utils/decode-vertex-format'; -export {decodeShaderUniformType} from './gpu-type-utils/decode-shader-types'; -export {decodeShaderAttributeType} from './gpu-type-utils/decode-attribute-type'; -export {getDataTypeFromTypedArray} from './gpu-type-utils/vertex-format-from-attribute'; -export {getTypedArrayFromDataType} from './gpu-type-utils/vertex-format-from-attribute'; -export {getVertexFormatFromAttribute} from './gpu-type-utils/vertex-format-from-attribute'; - -export {decodeTextureFormat} from './gpu-type-utils/decode-texture-format'; -export {getTextureFormatCapabilities} from './gpu-type-utils/texture-format-capabilities'; +export { + getDataTypeInfo, + getDataTypeFromTypedArray, + getTypedArrayFromDataType +} from './shadertypes/utils/decode-data-types'; +export { + getVariableShaderTypeInfo, + getAttributeShaderTypeInfo +} from './shadertypes/utils/decode-shader-types'; +export { + getVertexFormatFromAttribute, + getVertexFormatInfo +} from './shadertypes/utils/decode-vertex-format'; +export { + getTextureFormatInfo, + getTextureFormatCapabilities +} from './shadertypes/utils/decode-texture-format'; // GENERAL EXPORTS - FOR APPLICATIONS @@ -177,4 +182,4 @@ export {getAttributeInfosFromLayouts} from './adapter-utils/get-attribute-from-l export { getTextureFormatDefinition as _getTextureFormatDefinition, getTextureFormatTable as _getTextureFormatTable -} from './gpu-type-utils/texture-format-table'; +} from './shadertypes/utils/texture-format-table'; diff --git a/modules/core/src/portable/uniform-block.ts b/modules/core/src/portable/uniform-block.ts index dbb0d8bd5c..26e76eca7e 100644 --- a/modules/core/src/portable/uniform-block.ts +++ b/modules/core/src/portable/uniform-block.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors -import type {ShaderUniformType} from '../gpu-type-utils/shader-types'; +import type {VariableShaderType} from '../shadertypes/shader-types'; import type {UniformValue} from '../adapter/types/uniforms'; import { ShaderLayout, @@ -30,7 +30,7 @@ export class UniformBlock< constructor(props?: { name?: string; shaderLayout?: ShaderLayout; - uniformTypes?: Record>; + uniformTypes?: Record>; }) { this.name = props?.name || 'unnamed'; diff --git a/modules/core/src/portable/uniform-buffer-layout.ts b/modules/core/src/portable/uniform-buffer-layout.ts index b6ceddf7e2..256839944e 100644 --- a/modules/core/src/portable/uniform-buffer-layout.ts +++ b/modules/core/src/portable/uniform-buffer-layout.ts @@ -2,8 +2,10 @@ // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors -import type {ShaderUniformType, ShaderDataType} from '../gpu-type-utils/shader-types'; -import {decodeShaderUniformType, alignTo} from '../gpu-type-utils/decode-shader-types'; +import type {PrimitiveDataType} from '../shadertypes/data-types'; +import type {VariableShaderType} from '../shadertypes/shader-types'; +import {alignTo} from '../shadertypes/utils/decode-data-types'; +import {getVariableShaderTypeInfo} from '../shadertypes/utils/decode-shader-types'; import type {UniformValue} from '../adapter/types/uniforms'; import {getScratchArrayBuffer} from '../utils/array-utils-flat'; @@ -21,19 +23,19 @@ const minBufferSize: number = 1024; * Supports manual listing of uniforms */ export class UniformBufferLayout { - readonly layout: Record = {}; + readonly layout: Record = {}; /** number of bytes needed for buffer allocation */ readonly byteLength: number; /** Create a new UniformBufferLayout given a map of attributes. */ - constructor(uniformTypes: Record) { + constructor(uniformTypes: Record) { /** number of 4 byte slots taken */ let size: number = 0; // Add layout (type, size and offset) definitions for each uniform in the layout for (const [key, uniformType] of Object.entries(uniformTypes)) { - const typeAndComponents = decodeShaderUniformType(uniformType); + const typeAndComponents = getVariableShaderTypeInfo(uniformType); const {type, components: count} = typeAndComponents; // First, align (bump) current offset to an even multiple of current object (1, 2, 4) size = alignTo(size, count); diff --git a/modules/core/src/portable/uniform-store.ts b/modules/core/src/portable/uniform-store.ts index 07c39a3122..aad7458e59 100644 --- a/modules/core/src/portable/uniform-store.ts +++ b/modules/core/src/portable/uniform-store.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors -import type {ShaderUniformType} from '../gpu-type-utils/shader-types'; +import type {VariableShaderType} from '../shadertypes/shader-types'; import type {UniformValue} from '../adapter/types/uniforms'; import type {Device} from '../adapter/device'; import {Buffer} from '../adapter/resources/buffer'; @@ -38,7 +38,7 @@ export class UniformStore< blocks: Record< keyof TPropGroups, { - uniformTypes?: Record; + uniformTypes?: Record; defaultProps?: Record; defaultUniforms?: Record; } diff --git a/modules/core/src/shadertypes/data-types.ts b/modules/core/src/shadertypes/data-types.ts new file mode 100644 index 0000000000..9817503363 --- /dev/null +++ b/modules/core/src/shadertypes/data-types.ts @@ -0,0 +1,42 @@ +// luma.gl +// SPDX-License-Identifier: MIT +// Copyright (c) vis.gl contributors + +/** + * Primitive data types that shaders can perform calculations in and declare variables with. + * @note attribute inputs and texture samples can be populated from a different in-memory types, see below. + * @note `f16` requires the `f16` extension + */ +export type PrimitiveDataType = 'u32' | 'i32' | 'f32' | 'f16'; + +/** + * Signed data types describe signed and unsigned integers as well as floats of varying sizes + * @note These formats describe physical memory layouts in vertex and pixel formats, they are not used inside shaders + */ +export type SignedDataType = + | 'uint8' + | 'sint8' + | 'uint16' + | 'sint16' + | 'uint32' + | 'sint32' + | 'float16' + | 'float32'; + +/** + * Normalized data types describe signed and unsigned integers as well as floats of varying sizes together with normalization behavior + * @note These formats describe physical memory layouts in vertex and pixel formats, they are not used inside shaders + * @note Normalization means that these formats are converted into floats on read (shader must use f32 to process them) + * @note WebGPU does not support normalized 32 bit integer attributes: 'unorm32' | 'snorm32' + */ +export type NormalizedDataType = SignedDataType | 'unorm8' | 'snorm8' | 'unorm16' | 'snorm16'; + +/** Returns information about a signed or normalized DataType */ +export type DataTypeInfo = { + signedType: SignedDataType; + primitiveType: PrimitiveDataType; + byteLength: 1 | 2 | 4; + normalized: boolean; + integer: boolean; + signed: boolean; +}; diff --git a/modules/core/src/shadertypes/shader-types.ts b/modules/core/src/shadertypes/shader-types.ts new file mode 100644 index 0000000000..c3c174cf3e --- /dev/null +++ b/modules/core/src/shadertypes/shader-types.ts @@ -0,0 +1,87 @@ +// luma.gl +// SPDX-License-Identifier: MIT +// Copyright (c) vis.gl contributors + +import type {PrimitiveDataType} from './data-types'; + +/** + * Describes the type of an attribute as defined in the shader source code. + * @note This is a subset of shader variable types + * @note Buffers with various `VertexFormat`s can be supplied for each type, GPU will convert them at runtime/ + */ +export type AttributeShaderType = + | PrimitiveDataType + | `vec2<${PrimitiveDataType}>` + | `vec3<${PrimitiveDataType}>` + | `vec4<${PrimitiveDataType}>`; + +/** + * Describes the type of a variable that can declared in shader source code. + * @note Uniforms can be declared using these types + * @note Uniforms can be of a wider range of types than attributes. + * @note to WebGL users: "bindings" (textures, samplers, and uniform buffers) are considered "bindings", not shader variables/uniforms + */ +export type VariableShaderType = + | PrimitiveDataType + | `vec2<${PrimitiveDataType}>` + | `vec3<${PrimitiveDataType}>` + | `vec4<${PrimitiveDataType}>` + | `mat2x2<${PrimitiveDataType}>` + | `mat2x3<${PrimitiveDataType}>` + | `mat2x4<${PrimitiveDataType}>` + | `mat3x2<${PrimitiveDataType}>` + | `mat3x3<${PrimitiveDataType}>` + | `mat3x4<${PrimitiveDataType}>` + | `mat4x2<${PrimitiveDataType}>` + | `mat4x3<${PrimitiveDataType}>` + | `mat4x4<${PrimitiveDataType}>`; + +/* Suffixes used by WGSL alias types */ +type ShaderTypeAliasSuffix = 'f' | 'i' | 'u' | 'h'; + +/** Shorthand type aliases recognized by WGSL */ +export type AttributeShaderTypeAlias = + | `vec2${ShaderTypeAliasSuffix}` + | `vec3${ShaderTypeAliasSuffix}` + | `vec4${ShaderTypeAliasSuffix}`; + +/** Shorthand type aliases recognized by WGSL */ +export type VariableShaderTypeAlias = + | AttributeShaderTypeAlias + | `mat2x2${ShaderTypeAliasSuffix}` + | `mat2x3${ShaderTypeAliasSuffix}` + | `mat2x4${ShaderTypeAliasSuffix}` + | `mat3x2${ShaderTypeAliasSuffix}` + | `mat3x3${ShaderTypeAliasSuffix}` + | `mat3x4${ShaderTypeAliasSuffix}` + | `mat4x2${ShaderTypeAliasSuffix}` + | `mat4x3${ShaderTypeAliasSuffix}` + | `mat4x4${ShaderTypeAliasSuffix}`; + +/** A composite shader type can include structs and arrays, recursively */ +export type CompositeShaderType = VariableShaderType | StructShaderType | ArrayShaderType; + +/** Represents a struct in WGSL */ +export type StructShaderType = { + members: Record; +}; + +/** Represents an array in WGSL */ +export type ArrayShaderType = { + type: CompositeShaderType; + length: number; +}; + +/** Information extracted from a AttributeShaderType constant */ +export type AttributeShaderTypeInfo = { + /** WGSL-style primitive data type, f32, i32, u32 */ + primitiveType: PrimitiveDataType; + /** Whether this is a normalized integer (that must be used as float) */ + components: 1 | 2 | 3 | 4; + /** Length in bytes of the data for one vertex */ + byteLength?: number; + /** Whether this is for integer or float vert */ + integer: boolean; + /** Whether this data type is signed */ + signed: boolean; +}; diff --git a/modules/core/src/gpu-type-utils/texture-formats.ts b/modules/core/src/shadertypes/texture-formats.ts similarity index 58% rename from modules/core/src/gpu-type-utils/texture-formats.ts rename to modules/core/src/shadertypes/texture-formats.ts index 2333a2958a..af920d21de 100644 --- a/modules/core/src/gpu-type-utils/texture-formats.ts +++ b/modules/core/src/shadertypes/texture-formats.ts @@ -2,6 +2,8 @@ // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors +import {NormalizedDataType} from './data-types'; + /** * These represent the main compressed texture formats * Each format typically has a number of more specific subformats @@ -174,3 +176,77 @@ export type WebGL2ColorTextureFormat = | 'atc-rgb-unorm-webgl' | 'atc-rgba-unorm-webgl' | 'atc-rgbai-unorm-webgl'; + +/** + * Texture feature checks + * @note these must be a subset of DeviceFeatures. + */ +export type TextureFeature = + | 'texture-compression-bc' + | 'texture-compression-astc' + | 'texture-compression-etc2' + | 'texture-compression-etc1-webgl' + | 'texture-compression-pvrtc-webgl' + | 'texture-compression-atc-webgl' + | 'float32-renderable-webgl' + | 'float16-renderable-webgl' + | 'rgb9e5ufloat-renderable-webgl' + | 'snorm8-renderable-webgl' + | 'norm16-renderable-webgl' + | 'snorm16-renderable-webgl' + | 'float32-filterable' + | 'float16-filterable-webgl'; + +/** Information about the structure of a texture format */ +export type TextureFormatInfo = { + /** The format that is described */ + format: TextureFormat; + /** Color or depth stencil attachment formats */ + attachment?: 'color' | 'depth' | 'stencil' | 'depth-stencil'; + /** String describing which channels this texture has */ + channels: 'r' | 'rg' | 'rgb' | 'rgba' | 'bgra'; + /** Number of components (corresponds to channels string) */ + components: 1 | 2 | 3 | 4; + /** What is the data type of each component */ + dataType?: NormalizedDataType; + /** If this is a packed data type */ + packed?: boolean; + /** Number of bytes per pixel */ + bytesPerPixel?: number; + /** Number of bits per channel (may be unreliable for packed formats) */ + bitsPerChannel: [number, number, number, number]; + /** SRGB texture format? */ + srgb?: boolean; + /** WebGL specific texture format? */ + webgl?: boolean; + /** Is this an integer or floating point format? */ + integer: boolean; + /** Is this a signed or unsigned format? */ + signed: boolean; + /** Is this a normalized integer format? */ + normalized: boolean; + /** Is this a compressed texture format */ + compressed?: boolean; + /** Compressed formats only: Block size for ASTC formats (texture width must be a multiple of this value) */ + blockWidth?: number; + /** Compressed formats only: Block size for ASTC formats (texture height must be a multiple of this value) */ + blockHeight?: number; +}; + +/** + * Texture format capabilities. + * @note Not directly usable. Can contain TextureFeature strings that need to be checked against a specific device. + */ +export type TextureFormatCapabilities = { + format: TextureFormat; + /** Can the format be created */ + create: TextureFeature | boolean; + /** If a feature string, the specified device feature determines if format is renderable. */ + render: TextureFeature | boolean; + /** If a feature string, the specified device feature determines if format is filterable. */ + filter: TextureFeature | boolean; + /** If a feature string, the specified device feature determines if format is blendable. */ + blend: TextureFeature | boolean; + /** If a feature string, the specified device feature determines if format is storeable. */ + store: TextureFeature | boolean; +}; diff --git a/modules/core/src/shadertypes/utils/decode-data-types.ts b/modules/core/src/shadertypes/utils/decode-data-types.ts new file mode 100644 index 0000000000..8599c9d7c3 --- /dev/null +++ b/modules/core/src/shadertypes/utils/decode-data-types.ts @@ -0,0 +1,113 @@ +// luma.gl +// SPDX-License-Identifier: MIT +// Copyright (c) vis.gl contributors + +import {TypedArray, TypedArrayConstructor} from '../../types'; +import {PrimitiveDataType, SignedDataType, NormalizedDataType, DataTypeInfo} from '../data-types'; + +/** + * Gets info about a data type constant (signed or normalized) + * @returns underlying primitive / signed types, byte length, normalization, integer, signed flags + */ +export function getDataTypeInfo(type: NormalizedDataType): DataTypeInfo { + const [signedType, primitiveType, byteLength] = NORMALIZED_TYPE_MAP[type]; + const normalized: boolean = type.includes('norm'); + const integer: boolean = !normalized && !type.startsWith('float'); + const signed: boolean = type.startsWith('s'); + + return { + signedType, + primitiveType, + byteLength, + normalized, + integer, + signed + }; +} + +/** Align offset to 1, 2 or 4 elements (4, 8 or 16 bytes) */ +export function alignTo(size: number, count: number): number { + // prettier-ignore + switch (count) { + case 1: return size; // Pad upwards to even multiple of 2 + case 2: return size + (size % 2); // Pad upwards to even multiple of 2 + default: return size + ((4 - (size % 4)) % 4); // Pad upwards to even multiple of 4 + } +} + +/** Returns the VariableShaderType that corresponds to a typed array */ +export function getDataTypeFromTypedArray( + arrayOrType: TypedArray | TypedArrayConstructor +): SignedDataType { + const type = ArrayBuffer.isView(arrayOrType) ? arrayOrType.constructor : arrayOrType; + switch (type) { + case Float32Array: + return 'float32'; + case Uint16Array: + return 'uint16'; + case Uint32Array: + return 'uint32'; + case Uint8Array: + case Uint8ClampedArray: + return 'uint8'; + case Int8Array: + return 'sint8'; + case Int16Array: + return 'sint16'; + case Int32Array: + return 'sint32'; + default: + // Failed to deduce data type from typed array + throw new Error(type.constructor.name); + } +} + +/** Returns the TypedArray that corresponds to a shader data type */ +export function getTypedArrayFromDataType( + type: NormalizedDataType | PrimitiveDataType +): TypedArrayConstructor { + switch (type) { + case 'f32': + case 'float32': + return Float32Array; + case 'u32': + case 'uint32': + return Uint32Array; + case 'i32': + case 'sint32': + return Int32Array; + case 'uint16': + case 'unorm16': + return Uint16Array; + case 'sint16': + case 'snorm16': + return Int16Array; + case 'uint8': + case 'unorm8': + return Uint8Array; + case 'sint8': + case 'snorm8': + return Int8Array; + case 'f16': + default: + throw new Error(type); + } +} + +const NORMALIZED_TYPE_MAP: Record< + NormalizedDataType, + [SignedDataType, PrimitiveDataType, bytes: 1 | 2 | 4, normalized: boolean] +> = { + uint8: ['uint8', 'u32', 1, false], + sint8: ['sint8', 'i32', 1, false], + unorm8: ['uint8', 'f32', 1, true], + snorm8: ['sint8', 'f32', 1, true], + uint16: ['uint16', 'u32', 2, false], + sint16: ['sint16', 'i32', 2, false], + unorm16: ['uint16', 'u32', 2, true], + snorm16: ['sint16', 'i32', 2, true], + float16: ['float16', 'f16', 2, false], + float32: ['float32', 'f32', 4, false], + uint32: ['uint32', 'u32', 4, false], + sint32: ['sint32', 'i32', 4, false] +}; diff --git a/modules/core/src/shadertypes/utils/decode-shader-types.ts b/modules/core/src/shadertypes/utils/decode-shader-types.ts new file mode 100644 index 0000000000..631e3378e8 --- /dev/null +++ b/modules/core/src/shadertypes/utils/decode-shader-types.ts @@ -0,0 +1,204 @@ +// luma.gl +// SPDX-License-Identifier: MIT +// Copyright (c) vis.gl contributors + +import {PrimitiveDataType} from '../data-types'; +import type { + VariableShaderType, + AttributeShaderType, + AttributeShaderTypeInfo, + VariableShaderTypeAlias, + AttributeShaderTypeAlias +} from '../shader-types'; + +/** Split a uniform type string into type and components */ +export function getVariableShaderTypeInfo(format: VariableShaderType): { + type: PrimitiveDataType; + components: number; +} { + const decoded = UNIFORM_FORMATS[format]; + return decoded; +} + +/** Decodes a vertex type, returning byte length and flags (integer, signed, normalized) */ +export function getAttributeShaderTypeInfo( + attributeType: AttributeShaderType +): AttributeShaderTypeInfo { + const [primitiveType, components] = TYPE_INFO[attributeType]; + const integer: boolean = primitiveType === 'i32' || primitiveType === 'u32'; + const signed: boolean = primitiveType !== 'u32'; + + const byteLength = PRIMITIVE_TYPE_SIZES[primitiveType] * components; + return { + primitiveType, + components, + byteLength, + integer, + signed + }; +} + +export function resolveAttributeShaderTypeAlias( + alias: AttributeShaderTypeAlias | AttributeShaderType +): AttributeShaderType { + return WGSL_ATTRIBUTE_TYPE_ALIAS_MAP[alias as AttributeShaderTypeAlias] || alias; +} + +export function resolveVariableShaderTypeAlias( + alias: VariableShaderTypeAlias | VariableShaderType +): VariableShaderType { + return WGSL_VARIABLE_TYPE_ALIAS_MAP[alias as VariableShaderTypeAlias] || alias; +} + +// TABLES + +const PRIMITIVE_TYPE_SIZES: Record = { + f32: 4, + f16: 2, + i32: 4, + u32: 4 + // 'bool-webgl': 4, +}; + +/** All valid shader attribute types. A table guarantees exhaustive list and fast execution */ +const TYPE_INFO: Record = { + f32: ['f32', 1], + 'vec2': ['f32', 2], + 'vec3': ['f32', 3], + 'vec4': ['f32', 4], + f16: ['f16', 1], + 'vec2': ['f16', 2], + 'vec3': ['f16', 3], + 'vec4': ['f16', 4], + i32: ['i32', 1], + 'vec2': ['i32', 2], + 'vec3': ['i32', 3], + 'vec4': ['i32', 4], + u32: ['u32', 1], + 'vec2': ['u32', 2], + 'vec3': ['u32', 3], + 'vec4': ['u32', 4] +}; + +/** @todo These tables are quite big, consider parsing type strings instead */ +const UNIFORM_FORMATS: Record = { + f32: {type: 'f32', components: 1}, + f16: {type: 'f16', components: 1}, + i32: {type: 'i32', components: 1}, + u32: {type: 'u32', components: 1}, + // 'bool-webgl': {type: 'bool-webgl', components: 1}, + 'vec2': {type: 'f32', components: 2}, + 'vec3': {type: 'f32', components: 3}, + 'vec4': {type: 'f32', components: 4}, + 'vec2': {type: 'f16', components: 2}, + 'vec3': {type: 'f16', components: 3}, + 'vec4': {type: 'f16', components: 4}, + 'vec2': {type: 'i32', components: 2}, + 'vec3': {type: 'i32', components: 3}, + 'vec4': {type: 'i32', components: 4}, + 'vec2': {type: 'u32', components: 2}, + 'vec3': {type: 'u32', components: 3}, + 'vec4': {type: 'u32', components: 4}, + + 'mat2x2': {type: 'f32', components: 4}, + 'mat2x3': {type: 'f32', components: 6}, + 'mat2x4': {type: 'f32', components: 8}, + 'mat3x2': {type: 'f32', components: 6}, + 'mat3x3': {type: 'f32', components: 9}, + 'mat3x4': {type: 'f32', components: 12}, + 'mat4x2': {type: 'f32', components: 8}, + 'mat4x3': {type: 'f32', components: 12}, + 'mat4x4': {type: 'f32', components: 16}, + + 'mat2x2': {type: 'f16', components: 4}, + 'mat2x3': {type: 'f16', components: 6}, + 'mat2x4': {type: 'f16', components: 8}, + 'mat3x2': {type: 'f16', components: 6}, + 'mat3x3': {type: 'f16', components: 9}, + 'mat3x4': {type: 'f16', components: 12}, + 'mat4x2': {type: 'f16', components: 8}, + 'mat4x3': {type: 'f16', components: 12}, + 'mat4x4': {type: 'f16', components: 16}, + + 'mat2x2': {type: 'i32', components: 4}, + 'mat2x3': {type: 'i32', components: 6}, + 'mat2x4': {type: 'i32', components: 8}, + 'mat3x2': {type: 'i32', components: 6}, + 'mat3x3': {type: 'i32', components: 9}, + 'mat3x4': {type: 'i32', components: 12}, + 'mat4x2': {type: 'i32', components: 8}, + 'mat4x3': {type: 'i32', components: 12}, + 'mat4x4': {type: 'i32', components: 16}, + + 'mat2x2': {type: 'u32', components: 4}, + 'mat2x3': {type: 'u32', components: 6}, + 'mat2x4': {type: 'u32', components: 8}, + 'mat3x2': {type: 'u32', components: 6}, + 'mat3x3': {type: 'u32', components: 9}, + 'mat3x4': {type: 'u32', components: 12}, + 'mat4x2': {type: 'u32', components: 8}, + 'mat4x3': {type: 'u32', components: 12}, + 'mat4x4': {type: 'u32', components: 16} +}; + +/** Predeclared aliases @see https://www.w3.org/TR/WGSL/#vector-types */ +export const WGSL_ATTRIBUTE_TYPE_ALIAS_MAP: Record = + { + vec2i: 'vec2', + vec3i: 'vec3', + vec4i: 'vec4', + vec2u: 'vec2', + vec3u: 'vec3', + vec4u: 'vec4', + vec2f: 'vec2', + vec3f: 'vec3', + vec4f: 'vec4', + // Requires the f16 extension. + vec2h: 'vec2', + vec3h: 'vec3', + vec4h: 'vec4' + }; + +/** @todo These tables are quite big, consider parsing alias strings instead */ +export const WGSL_VARIABLE_TYPE_ALIAS_MAP: Record = { + ...WGSL_ATTRIBUTE_TYPE_ALIAS_MAP, + mat2x2f: 'mat2x2', + mat2x3f: 'mat2x3', + mat2x4f: 'mat2x4', + mat3x2f: 'mat3x2', + mat3x3f: 'mat3x3', + mat3x4f: 'mat3x4', + mat4x2f: 'mat4x2', + mat4x3f: 'mat4x3', + mat4x4f: 'mat4x4', + + mat2x2i: 'mat2x2', + mat2x3i: 'mat2x3', + mat2x4i: 'mat2x4', + mat3x2i: 'mat3x2', + mat3x3i: 'mat3x3', + mat3x4i: 'mat3x4', + mat4x2i: 'mat4x2', + mat4x3i: 'mat4x3', + mat4x4i: 'mat4x4', + + mat2x2u: 'mat2x2', + mat2x3u: 'mat2x3', + mat2x4u: 'mat2x4', + mat3x2u: 'mat3x2', + mat3x3u: 'mat3x3', + mat3x4u: 'mat3x4', + mat4x2u: 'mat4x2', + mat4x3u: 'mat4x3', + mat4x4u: 'mat4x4', + + mat2x2h: 'mat2x2', + mat2x3h: 'mat2x3', + mat2x4h: 'mat2x4', + mat3x2h: 'mat3x2', + mat3x3h: 'mat3x3', + mat3x4h: 'mat3x4', + mat4x2h: 'mat4x2', + mat4x3h: 'mat4x3', + mat4x4h: 'mat4x4' +}; diff --git a/modules/core/src/gpu-type-utils/decode-texture-format.ts b/modules/core/src/shadertypes/utils/decode-texture-format.ts similarity index 82% rename from modules/core/src/gpu-type-utils/decode-texture-format.ts rename to modules/core/src/shadertypes/utils/decode-texture-format.ts index 9aaf7f793a..8725a80283 100644 --- a/modules/core/src/gpu-type-utils/decode-texture-format.ts +++ b/modules/core/src/shadertypes/utils/decode-texture-format.ts @@ -2,11 +2,14 @@ // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors -import {TextureFormat, CompressedTextureFormat} from './texture-formats'; -import {VertexType} from './vertex-formats'; -import {decodeVertexType} from './decode-data-type'; -import {TextureFormatInfo} from './texture-format-info'; - +import type {NormalizedDataType} from '../data-types'; +import type { + TextureFormat, + CompressedTextureFormat, + TextureFormatInfo, + TextureFormatCapabilities +} from '../texture-formats'; +import {getDataTypeInfo} from './decode-data-types'; import {getTextureFormatDefinition} from './texture-format-table'; // prettier-ignore @@ -28,8 +31,8 @@ export function isTextureFormatCompressed( /** * Decodes a texture format, returning e.g. attatchment type, components, byte length and flags (integer, signed, normalized) */ -export function decodeTextureFormat(format: TextureFormat): TextureFormatInfo { - let formatInfo: TextureFormatInfo = decodeTextureFormatUsingTable(format); +export function getTextureFormatInfo(format: TextureFormat): TextureFormatInfo { + let formatInfo: TextureFormatInfo = getTextureFormatInfoUsingTable(format); if (isTextureFormatCompressed(format)) { formatInfo.channels = 'rgb'; @@ -49,8 +52,8 @@ export function decodeTextureFormat(format: TextureFormat): TextureFormatInfo { const matches = RGB_FORMAT_REGEX.exec(format as string); if (matches) { const [, channels, length, type, srgb, suffix] = matches; - const dataType = `${type}${length}` as VertexType; - const decodedType = decodeVertexType(dataType); + const dataType = `${type}${length}` as NormalizedDataType; + const decodedType = getDataTypeInfo(dataType); const bits = decodedType.byteLength * 8; const components = channels.length as 1 | 2 | 3 | 4; const bitsPerChannel: [number, number, number, number] = [ @@ -63,7 +66,7 @@ export function decodeTextureFormat(format: TextureFormat): TextureFormatInfo { formatInfo = { format, attachment: formatInfo.attachment, - dataType: decodedType.dataType, + dataType: decodedType.signedType, components, channels: channels as 'r' | 'rg' | 'rgb' | 'rgba', integer: decodedType.integer, @@ -94,8 +97,40 @@ export function decodeTextureFormat(format: TextureFormat): TextureFormatInfo { return formatInfo; } +/** + * Returns the "static" capabilities of a texture format. + * @note Needs to be checked against current device + */ +export function getTextureFormatCapabilities(format: TextureFormat): TextureFormatCapabilities { + const info = getTextureFormatDefinition(format); + + const formatCapabilities: Required = { + format, + create: info.f ?? true, + render: info.render ?? true, + filter: info.filter ?? true, + blend: info.blend ?? true, + store: info.store ?? true + }; + + const formatInfo = getTextureFormatInfo(format); + const isDepthStencil = format.startsWith('depth') || format.startsWith('stencil'); + const isSigned = formatInfo?.signed; + const isInteger = formatInfo?.integer; + const isWebGLSpecific = formatInfo?.webgl; + + // signed formats are not renderable + formatCapabilities.render &&= !isSigned; + // signed and integer formats are not filterable + formatCapabilities.filter &&= !isDepthStencil && !isSigned && !isInteger && !isWebGLSpecific; + + return formatCapabilities; +} + +// HELPERS + /** Decode texture format info from the table */ -function decodeTextureFormatUsingTable(format: TextureFormat): TextureFormatInfo { +function getTextureFormatInfoUsingTable(format: TextureFormat): TextureFormatInfo { const info = getTextureFormatDefinition(format); const bytesPerPixel = info.bytesPerPixel || 1; diff --git a/modules/core/src/shadertypes/utils/decode-vertex-format.ts b/modules/core/src/shadertypes/utils/decode-vertex-format.ts new file mode 100644 index 0000000000..e4a4423636 --- /dev/null +++ b/modules/core/src/shadertypes/utils/decode-vertex-format.ts @@ -0,0 +1,119 @@ +// luma.gl +// SPDX-License-Identifier: MIT +// Copyright (c) vis.gl contributors + +import type {TypedArray} from '../../types'; +import type {NormalizedDataType, PrimitiveDataType} from '../data-types'; +import type {VertexFormat, VertexFormatInfo} from '../vertex-formats'; +import {getDataTypeInfo, getDataTypeFromTypedArray} from './decode-data-types'; + +/** + * Decodes a vertex format, returning type, components, byte length and flags (integer, signed, normalized) + */ +export function getVertexFormatInfo(format: VertexFormat): VertexFormatInfo { + // Strip the -webgl ending if present + let webglOnly: boolean | undefined; + if (format.endsWith('-webgl')) { + format.replace('-webgl', ''); + webglOnly = true; + } + // split components from type + const [type_, count] = format.split('x'); + const type = type_ as NormalizedDataType; + const components = (count ? parseInt(count) : 1) as 1 | 2 | 3 | 4; + // decode the type + const decodedType = getDataTypeInfo(type); + const result: VertexFormatInfo = { + type, + components, + byteLength: decodedType.byteLength * components, + integer: decodedType.integer, + signed: decodedType.signed, + normalized: decodedType.normalized + }; + if (webglOnly) { + result.webglOnly = true; + } + return result; +} + +/** Get the vertex format for an attribute with TypedArray and size */ +export function getVertexFormatFromAttribute( + typedArray: TypedArray, + size: number, + normalized?: boolean +): VertexFormat { + if (!size || size > 4) { + throw new Error(`size ${size}`); + } + + const components = size as 1 | 2 | 3 | 4; + const signedDataType = getDataTypeFromTypedArray(typedArray); + + let dataType: NormalizedDataType = signedDataType; + + // TODO - Special cases for WebGL (not supported on WebGPU), overrides the check below + if (dataType === 'uint8' && normalized && components === 1) { + return 'unorm8-webgl'; + } + if (dataType === 'uint8' && normalized && components === 3) { + return 'unorm8x3-webgl'; + } + + if (dataType === 'uint8' || dataType === 'sint8') { + if (components === 1 || components === 3) { + // WebGPU 8 bit formats must be aligned to 16 bit boundaries'); + throw new Error(`size: ${size}`); + } + if (normalized) { + dataType = dataType.replace('int', 'norm') as 'unorm8' | 'snorm8'; + } + return `${dataType}x${components}`; + } + if (dataType === 'uint16' || dataType === 'sint16') { + if (components === 1 || components === 3) { + // WebGPU 16 bit formats must be aligned to 32 bit boundaries + throw new Error(`size: ${size}`); + } + if (normalized) { + dataType = dataType.replace('int', 'norm') as 'unorm16' | 'snorm16'; + } + return `${dataType}x${components}`; + } + + if (components === 1 && dataType !== 'float16') { + return dataType; + } + + // @ts-expect-error TODO fix + return `${dataType}x${components}`; +} + +/** Return a "default" vertex format for a certain shader data type + The simplest vertex format that matches the shader attribute's data type */ + +export function getCompatibleVertexFormat(opts: { + primitiveType: PrimitiveDataType; + components: 1 | 2 | 3 | 4; +}): VertexFormat { + let vertexType: NormalizedDataType; + switch (opts.primitiveType) { + case 'f32': + vertexType = 'float32'; + break; + case 'i32': + vertexType = 'sint32'; + break; + case 'u32': + vertexType = 'uint32'; + break; + case 'f16': + return opts.components <= 2 ? 'float16x2' : 'float16x4'; + } + + // TODO logic does not work for float16 + if (opts.components === 1) { + return vertexType; + } + return `${vertexType}x${opts.components}`; +} diff --git a/modules/core/src/gpu-type-utils/texture-format-table.ts b/modules/core/src/shadertypes/utils/texture-format-table.ts similarity index 98% rename from modules/core/src/gpu-type-utils/texture-format-table.ts rename to modules/core/src/shadertypes/utils/texture-format-table.ts index b5af23b087..5927955cdd 100644 --- a/modules/core/src/gpu-type-utils/texture-format-table.ts +++ b/modules/core/src/shadertypes/utils/texture-format-table.ts @@ -2,10 +2,7 @@ // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors -import {TextureFormat} from './texture-formats'; -import {TextureFeature} from './texture-features'; -import {TextureFormatInfo} from './texture-format-info'; - +import {TextureFormat, TextureFeature, TextureFormatInfo} from '../texture-formats'; /* eslint-disable camelcase */ // Define local device feature strings to optimize minification diff --git a/modules/core/src/gpu-type-utils/vertex-formats.ts b/modules/core/src/shadertypes/vertex-formats.ts similarity index 60% rename from modules/core/src/gpu-type-utils/vertex-formats.ts rename to modules/core/src/shadertypes/vertex-formats.ts index ec2ca7a50f..204df3fb23 100644 --- a/modules/core/src/gpu-type-utils/vertex-formats.ts +++ b/modules/core/src/shadertypes/vertex-formats.ts @@ -2,41 +2,11 @@ // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors -/** Basic data types signed and unsigned integers, and floats, of varying sizes */ -export type DataType = - | 'uint8' - | 'sint8' - | 'uint16' - | 'sint16' - | 'uint32' - | 'sint32' - | 'float16' - | 'float32'; - -/** Vertex and Pixel data types. Include normalized integers */ -export type NormalizedDataType = - | 'uint8' - | 'sint8' - | 'unorm8' - | 'snorm8' - | 'uint16' - | 'sint16' - | 'unorm16' - | 'snorm16' - | 'uint32' - | 'sint32' - // WebGPU does not support normalized 32 bit integer attributes... - // | 'unorm32' - // | 'snorm32' - | 'float32' - | 'float16'; - -/** Describes the type (without number of components) of a vertex format */ -export type VertexType = NormalizedDataType; +import {NormalizedDataType} from './data-types'; /** - * Describes the memory format of a buffer that will be supplied to vertex attributes - * @note Must be compatible with the ShaderAttributeType of the shaders, see documentation. + * Describes the **memory format** and interpretation (normalization) of a buffer that will be supplied to vertex attributes + * @note Must be compatible with the AttributeShaderType of the shaders, see documentation. * @note This is a superset of WebGPU vertex formats to allow foe some flexibility for WebGL only applications * @todo Add device.isTextureFormatSupported() method? */ @@ -88,3 +58,20 @@ export type VertexFormat = | 'float32x2' | 'float32x3' | 'float32x4'; + +export type VertexFormatInfo = { + /** Type of each component */ + type: NormalizedDataType; + /** Length in bytes */ + byteLength: number; + /** Number of components per vertex / row */ + components: 1 | 2 | 3 | 4; + /** Is this an integer format (normalized integer formats are not integer) */ + integer: boolean; + /** Is this a signed format? */ + signed: boolean; + /** Is this a normalized format? */ + normalized: boolean; + /** Is this a webgl only format? */ + webglOnly?: boolean; +}; diff --git a/modules/core/test/adapter-utils/get-attribute-from-layout.spec.ts b/modules/core/test/adapter-utils/get-attribute-from-layout.spec.ts index 1b45eeff8a..9965a5b52f 100644 --- a/modules/core/test/adapter-utils/get-attribute-from-layout.spec.ts +++ b/modules/core/test/adapter-utils/get-attribute-from-layout.spec.ts @@ -3,7 +3,12 @@ // Copyright (c) vis.gl contributors import test from 'tape-promise/tape'; -import {ShaderLayout, getAttributeInfosFromLayouts, BufferLayout} from '@luma.gl/core'; +import { + ShaderLayout, + getAttributeInfosFromLayouts, + AttributeInfo, + BufferLayout +} from '@luma.gl/core'; const shaderLayout: ShaderLayout = { bindings: [], @@ -86,13 +91,13 @@ const bufferLayout: BufferLayout[] = [ } ]; -const resolvedLayout = { +const resolvedLayout: Record = { vertexPositions: { attributeName: 'vertexPositions', bufferName: 'vertexPositions', location: 0, shaderType: 'vec3', - shaderDataType: 'f32', + primitiveType: 'f32', shaderComponents: 3, vertexFormat: 'float32x3', bufferDataType: 'float32', @@ -108,7 +113,7 @@ const resolvedLayout = { bufferName: 'vertexPositions', location: 1, shaderType: 'vec3', - shaderDataType: 'f32', + primitiveType: 'f32', shaderComponents: 3, vertexFormat: 'float32x3', bufferDataType: 'float32', @@ -124,7 +129,7 @@ const resolvedLayout = { bufferName: 'vertexPositions', location: 0, shaderType: 'vec3', - shaderDataType: 'f32', + primitiveType: 'f32', shaderComponents: 3, vertexFormat: 'float32x3', bufferDataType: 'float32', @@ -140,7 +145,7 @@ const resolvedLayout = { bufferName: 'vertexPositions', location: 2, shaderType: 'vec3', - shaderDataType: 'f32', + primitiveType: 'f32', shaderComponents: 3, vertexFormat: 'float32x3', bufferDataType: 'float32', @@ -156,7 +161,7 @@ const resolvedLayout = { bufferName: 'vertexPositions', location: 1, shaderType: 'vec3', - shaderDataType: 'f32', + primitiveType: 'f32', shaderComponents: 3, vertexFormat: 'float32x3', bufferDataType: 'float32', @@ -172,7 +177,7 @@ const resolvedLayout = { bufferName: 'vertexPositions', location: 3, shaderType: 'vec3', - shaderDataType: 'f32', + primitiveType: 'f32', shaderComponents: 3, vertexFormat: 'float32x3', bufferDataType: 'float32', diff --git a/modules/core/test/adapter/resources/command-encoder.spec.ts b/modules/core/test/adapter/resources/command-encoder.spec.ts index 1697752895..264b886c2a 100644 --- a/modules/core/test/adapter/resources/command-encoder.spec.ts +++ b/modules/core/test/adapter/resources/command-encoder.spec.ts @@ -210,7 +210,9 @@ function testCopyToTexture( const sourceColor = [255, 128, 64, 32]; const sourceTexture = device_.createTexture({ - data: options.sourceIsFramebuffer ? null : new Uint8Array(sourceColor) + data: options.sourceIsFramebuffer ? null : new Uint8Array(sourceColor), + width: 1, + height: 1 }); const destinationTexture = sourceTexture.clone(); diff --git a/modules/core/test/adapter/resources/texture.spec.ts b/modules/core/test/adapter/resources/texture.spec.ts index 7f4d34dc75..1be1d7e3a7 100644 --- a/modules/core/test/adapter/resources/texture.spec.ts +++ b/modules/core/test/adapter/resources/texture.spec.ts @@ -5,7 +5,7 @@ import test from 'tape-promise/tape'; import {getWebGLTestDevice, getTestDevices} from '@luma.gl/test-utils'; -import {Device, Texture, TextureFormat, decodeTextureFormat, VertexType} from '@luma.gl/core'; +import {Device, Texture, TextureFormat, getTextureFormatInfo, VertexType} from '@luma.gl/core'; // TODO(v9): Avoid import from `@luma.gl/constants` in core tests. import {GL} from '@luma.gl/constants'; import {WebGLDevice} from '@luma.gl/webgl'; @@ -129,7 +129,7 @@ test('Texture#format simple creation', async t => { if (device.isTextureFormatSupported(formatName)) { // For compressed textures there may be a block size that we need to be a multiple of - const decodedFormat = decodeTextureFormat(formatName); + const decodedFormat = getTextureFormatInfo(formatName); const width = decodedFormat.blockWidth ?? 4; const height = decodedFormat.blockHeight ?? 4; @@ -180,7 +180,7 @@ function testFormatCreation(t, device: Device, withData: boolean = false) { for (const [formatName, formatInfo] of Object.entries(_getTextureFormatTable)) { const format = formatName as TextureFormat; - const decodedFormat = decodeTextureFormat(formatName); + const decodedFormat = getTextureFormatInfo(formatName); const {dataType, packed, bitsPerChannel} = decodedFormat; // WebGPU texture can currently only be set from 8 bit data diff --git a/modules/core/test/gpu-type-utils/decode-attribute-type.spec.ts b/modules/core/test/gpu-type-utils/decode-attribute-type.spec.ts deleted file mode 100644 index 580b7386a2..0000000000 --- a/modules/core/test/gpu-type-utils/decode-attribute-type.spec.ts +++ /dev/null @@ -1,40 +0,0 @@ -// luma.gl -// SPDX-License-Identifier: MIT -// Copyright (c) vis.gl contributors - -import test from 'tape-promise/tape'; -import {decodeShaderAttributeType, ShaderAttributeType} from '@luma.gl/core'; -import {ShaderAttributeTypeInfo} from '@luma.gl/core/gpu-type-utils/decode-attribute-type'; - -// prettier-ignore -const TEST_CASES: {format: ShaderAttributeType, result: ShaderAttributeTypeInfo}[] = [ - {format: 'f32', result: {dataType: 'f32', components: 1, byteLength: 1 * 4, integer: false, signed: true, defaultVertexFormat: 'float32'}}, - {format: 'vec2', result: {dataType: 'f32', components: 2, byteLength: 2 * 4, integer: false, signed: true, defaultVertexFormat: 'float32x2'}}, - {format: 'vec3', result: {dataType: 'f32', components: 3, byteLength: 3 * 4, integer: false, signed: true, defaultVertexFormat: 'float32x3'}}, - {format: 'vec4', result: {dataType: 'f32', components: 4, byteLength: 4 * 4, integer: false, signed: true, defaultVertexFormat: 'float32x4'}}, - {format: 'i32', result: {dataType: 'i32', components: 1, byteLength: 1 * 4, integer: true, signed: true, defaultVertexFormat: 'sint32'}}, - {format: 'vec2', result: {dataType: 'i32', components: 2, byteLength: 2 * 4, integer: true, signed: true, defaultVertexFormat: 'sint32x2'}}, - {format: 'vec3', result: {dataType: 'i32', components: 3, byteLength: 3 * 4, integer: true, signed: true, defaultVertexFormat: 'sint32x3'}}, - {format: 'vec4', result: {dataType: 'i32', components: 4, byteLength: 4 * 4, integer: true, signed: true, defaultVertexFormat: 'sint32x4'}}, - {format: 'u32', result: {dataType: 'u32', components: 1, byteLength: 1 * 4, integer: true, signed: false, defaultVertexFormat: 'uint32'}}, - {format: 'vec2', result: {dataType: 'u32', components: 2, byteLength: 2 * 4, integer: true, signed: false, defaultVertexFormat: 'uint32x2'}}, - {format: 'vec3', result: {dataType: 'u32', components: 3, byteLength: 3 * 4, integer: true, signed: false, defaultVertexFormat: 'uint32x3'}}, - {format: 'vec4', result: {dataType: 'u32', components: 4, byteLength: 4 * 4, integer: true, signed: false, defaultVertexFormat: 'uint32x4'}}, - {format: 'f16', result: {dataType: 'f16', components: 1, byteLength: 1 * 2, integer: false, signed: true, defaultVertexFormat: 'float16x2'}}, - {format: 'vec2', result: {dataType: 'f16', components: 2, byteLength: 2 * 2, integer: false, signed: true, defaultVertexFormat: 'float16x2'}}, - {format: 'vec3', result: {dataType: 'f16', components: 3, byteLength: 3 * 2, integer: false, signed: true, defaultVertexFormat: 'float16x4'}}, - {format: 'vec4', result: {dataType: 'f16', components: 4, byteLength: 4 * 2, integer: false, signed: true, defaultVertexFormat: 'float16x4'}}, - // {format: 'bool-webgl', result: {dataType: 'bool-webgl', components: 1, byteLength: 1 * 4, integer: true, signed: false}} -]; - -test('shadertypes#decodeShaderAttributeType', t => { - for (const tc of TEST_CASES) { - const decoded = decodeShaderAttributeType(tc.format); - t.deepEqual( - decoded, - tc.result, - `decodeShaderAttributeType('${tc.format}') => ${JSON.stringify(decoded.dataType)}` - ); - } - t.end(); -}); diff --git a/modules/core/test/gpu-type-utils/decode-vertex-format.spec.ts b/modules/core/test/gpu-type-utils/decode-vertex-format.spec.ts deleted file mode 100644 index 24d15839f5..0000000000 --- a/modules/core/test/gpu-type-utils/decode-vertex-format.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -// luma.gl -// SPDX-License-Identifier: MIT -// Copyright (c) vis.gl contributors - -import test from 'tape-promise/tape'; -import {decodeVertexFormat, VertexFormat} from '@luma.gl/core'; - -// prettier-ignore -const TEST_CASES: {format: VertexFormat, result: any}[] = [ - {format: 'float32', result: {type: 'float32', components: 1, byteLength: 4, integer: false, signed: false, normalized: false}}, - {format: 'uint32', result: {type: 'uint32', components: 1, byteLength: 4, integer: true, signed: false, normalized: false}}, - {format: 'sint32', result: {type: 'sint32', components: 1, byteLength: 4, integer: true, signed: true, normalized: false}}, - - {format: 'uint8x2', result: {type: 'uint8', components: 2, byteLength: 2, integer: true, signed: false, normalized: false}}, - {format: 'sint8x2', result: {type: 'sint8', components: 2, byteLength: 2, integer: true, signed: true, normalized: false}}, - {format: 'unorm8x2', result: {type: 'unorm8', components: 2, byteLength: 2, integer: false, signed: false, normalized: true}}, - {format: 'snorm8x2', result: {type: 'snorm8', components: 2, byteLength: 2, integer: false, signed: true, normalized: true}}, - {format: 'uint16x2', result: {type: 'uint16', components: 2, byteLength: 4, integer: true, signed: false, normalized: false}}, - {format: 'sint16x2', result: {type: 'sint16', components: 2, byteLength: 4, integer: true, signed: true, normalized: false}}, - {format: 'unorm16x2', result: {type: 'unorm16', components: 2, byteLength: 4, integer: false, signed: false, normalized: true}}, - {format: 'snorm16x2', result: {type: 'snorm16', components: 2, byteLength: 4, integer: false, signed: true, normalized: true}}, - {format: 'float16x2', result: {type: 'float16', components: 2, byteLength: 4, integer: false, signed: false, normalized: false}}, - {format: 'float32x2', result: {type: 'float32', components: 2, byteLength: 8, integer: false, signed: false, normalized: false}}, - {format: 'uint32x2', result: {type: 'uint32', components: 2, byteLength: 8, integer: true, signed: false, normalized: false}}, - {format: 'sint32x2', result: {type: 'sint32', components: 2, byteLength: 8, integer: true, signed: true, normalized: false}}, -]; - -test('shadertypes#decodeVertexFormat', t => { - for (const tc of TEST_CASES) { - const decoded = decodeVertexFormat(tc.format); - t.deepEqual( - decoded, - tc.result, - `decodeVertexFormat('${tc.format}') => ${JSON.stringify(decoded.type)}` - ); - } - t.end(); -}); diff --git a/modules/core/test/gpu-type-utils/get-texture-format-capabilities.spec.ts b/modules/core/test/gpu-type-utils/get-texture-format-capabilities.spec.ts deleted file mode 100644 index a5fcd8ab07..0000000000 --- a/modules/core/test/gpu-type-utils/get-texture-format-capabilities.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -// luma.gl -// SPDX-License-Identifier: MIT -// Copyright (c) vis.gl contributors - -import test from 'tape-promise/tape'; -import { - getTextureFormatCapabilities, - TextureFormat, - TextureFormatCapabilities -} from '@luma.gl/core'; - -// prettier-ignore -const TEST_CASES: {format: TextureFormat, result: Omit}[] = [ - // 8-bit formats - {format: 'r8unorm', result: {create: true, render: true, filter: true, blend: true, store: true}}, - - // 16-bit formats - {format: 'r16uint', result: {create: true, render: true, filter: false, blend: true, store: true}}, -]; - -test('shadertype#getTextureFormatCapabilities', t => { - for (const tc of TEST_CASES) { - const decoded = getTextureFormatCapabilities(tc.format); - - t.deepEqual( - decoded, - {format: tc.format, ...tc.result}, - `decodeVertexFormat('${tc.format}') => ${JSON.stringify(decoded)}` - ); - } - t.end(); -}); diff --git a/modules/core/test/index.ts b/modules/core/test/index.ts index a3939afc8d..9962c95895 100644 --- a/modules/core/test/index.ts +++ b/modules/core/test/index.ts @@ -2,12 +2,11 @@ import './utils/uid.spec'; // type utils -import './gpu-type-utils/decode-attribute-type.spec'; -import './gpu-type-utils/decode-vertex-format.spec'; -import './gpu-type-utils/vertex-format-from-attribute.spec'; +import './shadertypes/decode-attribute-type.spec'; +import './shadertypes/decode-vertex-format.spec'; +import './shadertypes/vertex-format-from-attribute.spec'; -import './gpu-type-utils/decode-texture-format.spec'; -import './gpu-type-utils/get-texture-format-capabilities.spec'; +import './shadertypes/decode-texture-format.spec'; // adapter utils import './adapter-utils/get-attribute-from-layout.spec'; diff --git a/modules/core/test/shadertypes/decode-attribute-type.spec.ts b/modules/core/test/shadertypes/decode-attribute-type.spec.ts new file mode 100644 index 0000000000..b469626053 --- /dev/null +++ b/modules/core/test/shadertypes/decode-attribute-type.spec.ts @@ -0,0 +1,43 @@ +// luma.gl +// SPDX-License-Identifier: MIT +// Copyright (c) vis.gl contributors + +import test from 'tape-promise/tape'; +import { + getAttributeShaderTypeInfo, + AttributeShaderType, + AttributeShaderTypeInfo +} from '@luma.gl/core'; + +// prettier-ignore +const TEST_CASES: {format: AttributeShaderType, result: AttributeShaderTypeInfo}[] = [ + {format: 'f32', result: {primitiveType: 'f32', components: 1, byteLength: 1 * 4, integer: false, signed: true}}, + {format: 'vec2', result: {primitiveType: 'f32', components: 2, byteLength: 2 * 4, integer: false, signed: true}}, + {format: 'vec3', result: {primitiveType: 'f32', components: 3, byteLength: 3 * 4, integer: false, signed: true}}, + {format: 'vec4', result: {primitiveType: 'f32', components: 4, byteLength: 4 * 4, integer: false, signed: true}}, + {format: 'i32', result: {primitiveType: 'i32', components: 1, byteLength: 1 * 4, integer: true, signed: true}}, + {format: 'vec2', result: {primitiveType: 'i32', components: 2, byteLength: 2 * 4, integer: true, signed: true}}, + {format: 'vec3', result: {primitiveType: 'i32', components: 3, byteLength: 3 * 4, integer: true, signed: true}}, + {format: 'vec4', result: {primitiveType: 'i32', components: 4, byteLength: 4 * 4, integer: true, signed: true}}, + {format: 'u32', result: {primitiveType: 'u32', components: 1, byteLength: 1 * 4, integer: true, signed: false}}, + {format: 'vec2', result: {primitiveType: 'u32', components: 2, byteLength: 2 * 4, integer: true, signed: false}}, + {format: 'vec3', result: {primitiveType: 'u32', components: 3, byteLength: 3 * 4, integer: true, signed: false}}, + {format: 'vec4', result: {primitiveType: 'u32', components: 4, byteLength: 4 * 4, integer: true, signed: false}}, + {format: 'f16', result: {primitiveType: 'f16', components: 1, byteLength: 1 * 2, integer: false, signed: true}}, + {format: 'vec2', result: {primitiveType: 'f16', components: 2, byteLength: 2 * 2, integer: false, signed: true}}, + {format: 'vec3', result: {primitiveType: 'f16', components: 3, byteLength: 3 * 2, integer: false, signed: true}}, + {format: 'vec4', result: {primitiveType: 'f16', components: 4, byteLength: 4 * 2, integer: false, signed: true}}, + // {format: 'bool-webgl', result: {primitiveType: 'bool-webgl', components: 1, byteLength: 1 * 4, integer: true, signed: false}} +]; + +test('shadertypes#getAttributeShaderTypeInfo', t => { + for (const tc of TEST_CASES) { + const decoded = getAttributeShaderTypeInfo(tc.format); + t.deepEqual( + decoded, + tc.result, + `getAttributeShaderTypeInfo('${tc.format}') => ${JSON.stringify(decoded.dataType)}` + ); + } + t.end(); +}); diff --git a/modules/core/test/gpu-type-utils/decode-texture-format.spec.ts b/modules/core/test/shadertypes/decode-texture-format.spec.ts similarity index 65% rename from modules/core/test/gpu-type-utils/decode-texture-format.spec.ts rename to modules/core/test/shadertypes/decode-texture-format.spec.ts index cef46fd197..2baf6933d9 100644 --- a/modules/core/test/gpu-type-utils/decode-texture-format.spec.ts +++ b/modules/core/test/shadertypes/decode-texture-format.spec.ts @@ -3,7 +3,12 @@ // Copyright (c) vis.gl contributors import test from 'tape-promise/tape'; -import {decodeTextureFormat, TextureFormat} from '@luma.gl/core'; +import { + getTextureFormatInfo, + TextureFormat, + getTextureFormatCapabilities, + TextureFormatCapabilities +} from '@luma.gl/core'; // prettier-ignore const TEST_CASES: {format: TextureFormat, result: any}[] = [ @@ -19,14 +24,36 @@ const TEST_CASES: {format: TextureFormat, result: any}[] = [ {format: 'r16float', result: {attachment: 'color', dataType: 'float16', components: 1, channels: 'r', integer: false, signed: false, normalized: false, bitsPerChannel: [16, 0, 0, 0], bytesPerPixel: 2, packed: false, srgb: false }} ]; -test('shadertype#decodeTextureFormat', t => { +test('shadertype#getTextureFormatInfo', t => { for (const tc of TEST_CASES) { - const decoded = decodeTextureFormat(tc.format); + const decoded = getTextureFormatInfo(tc.format); t.deepEqual( decoded, {format: tc.format, ...tc.result}, - `decodeTextureFormat('${tc.format}') => ${JSON.stringify(decoded.dataType)}` + `getTextureFormatInfo('${tc.format}') => ${JSON.stringify(decoded.dataType)}` + ); + } + t.end(); +}); + +// prettier-ignore +const TEST_CASES_CAPABILITIES: {format: TextureFormat, result: Omit}[] = [ + // 8-bit formats + {format: 'r8unorm', result: {create: true, render: true, filter: true, blend: true, store: true}}, + + // 16-bit formats + {format: 'r16uint', result: {create: true, render: true, filter: false, blend: true, store: true}}, +]; + +test('shadertype#getTextureFormatCapabilities', t => { + for (const tc of TEST_CASES_CAPABILITIES) { + const decoded = getTextureFormatCapabilities(tc.format); + + t.deepEqual( + decoded, + {format: tc.format, ...tc.result}, + `getVertexFormatInfo('${tc.format}') => ${JSON.stringify(decoded)}` ); } t.end(); diff --git a/modules/core/test/shadertypes/decode-vertex-format.spec.ts b/modules/core/test/shadertypes/decode-vertex-format.spec.ts new file mode 100644 index 0000000000..acd291916f --- /dev/null +++ b/modules/core/test/shadertypes/decode-vertex-format.spec.ts @@ -0,0 +1,61 @@ +// luma.gl +// SPDX-License-Identifier: MIT +// Copyright (c) vis.gl contributors + +import test from 'tape-promise/tape'; +import {getVertexFormatInfo, VertexFormat} from '@luma.gl/core'; + +// prettier-ignore +const TEST_CASES: {format: VertexFormat, result: any}[] = [ + {format: 'float32', result: {type: 'float32', components: 1, byteLength: 4, integer: false, signed: false, normalized: false}}, + {format: 'uint32', result: {type: 'uint32', components: 1, byteLength: 4, integer: true, signed: false, normalized: false}}, + {format: 'sint32', result: {type: 'sint32', components: 1, byteLength: 4, integer: true, signed: true, normalized: false}}, + + {format: 'uint8x2', result: {type: 'uint8', components: 2, byteLength: 2, integer: true, signed: false, normalized: false}}, + {format: 'sint8x2', result: {type: 'sint8', components: 2, byteLength: 2, integer: true, signed: true, normalized: false}}, + {format: 'unorm8x2', result: {type: 'unorm8', components: 2, byteLength: 2, integer: false, signed: false, normalized: true}}, + {format: 'snorm8x2', result: {type: 'snorm8', components: 2, byteLength: 2, integer: false, signed: true, normalized: true}}, + {format: 'uint16x2', result: {type: 'uint16', components: 2, byteLength: 4, integer: true, signed: false, normalized: false}}, + {format: 'sint16x2', result: {type: 'sint16', components: 2, byteLength: 4, integer: true, signed: true, normalized: false}}, + {format: 'unorm16x2', result: {type: 'unorm16', components: 2, byteLength: 4, integer: false, signed: false, normalized: true}}, + {format: 'snorm16x2', result: {type: 'snorm16', components: 2, byteLength: 4, integer: false, signed: true, normalized: true}}, + {format: 'float16x2', result: {type: 'float16', components: 2, byteLength: 4, integer: false, signed: false, normalized: false}}, + {format: 'float32x2', result: {type: 'float32', components: 2, byteLength: 8, integer: false, signed: false, normalized: false}}, + {format: 'uint32x2', result: {type: 'uint32', components: 2, byteLength: 8, integer: true, signed: false, normalized: false}}, + {format: 'sint32x2', result: {type: 'sint32', components: 2, byteLength: 8, integer: true, signed: true, normalized: false}}, +]; + +test('shadertypes#getVertexFormatInfo', t => { + for (const tc of TEST_CASES) { + const decoded = getVertexFormatInfo(tc.format); + t.deepEqual( + decoded, + tc.result, + `getVertexFormatInfo('${tc.format}') => ${JSON.stringify(decoded.type)}` + ); + } + t.end(); +}); + +// test default vertex format deduction +/* +const TEST_CASES: {format: AttributeShaderType, result: AttributeShaderTypeInfo}[] = [ + {format: 'f32', result: {primitiveType: 'f32', components: 1, byteLength: 1 * 4, integer: false, signed: true, defaultVertexFormat: 'float32'}}, + {format: 'vec2', result: {primitiveType: 'f32', components: 2, byteLength: 2 * 4, integer: false, signed: true, defaultVertexFormat: 'float32x2'}}, + {format: 'vec3', result: {primitiveType: 'f32', components: 3, byteLength: 3 * 4, integer: false, signed: true, defaultVertexFormat: 'float32x3'}}, + {format: 'vec4', result: {primitiveType: 'f32', components: 4, byteLength: 4 * 4, integer: false, signed: true, defaultVertexFormat: 'float32x4'}}, + {format: 'i32', result: {primitiveType: 'i32', components: 1, byteLength: 1 * 4, integer: true, signed: true, defaultVertexFormat: 'sint32'}}, + {format: 'vec2', result: {primitiveType: 'i32', components: 2, byteLength: 2 * 4, integer: true, signed: true, defaultVertexFormat: 'sint32x2'}}, + {format: 'vec3', result: {primitiveType: 'i32', components: 3, byteLength: 3 * 4, integer: true, signed: true, defaultVertexFormat: 'sint32x3'}}, + {format: 'vec4', result: {primitiveType: 'i32', components: 4, byteLength: 4 * 4, integer: true, signed: true, defaultVertexFormat: 'sint32x4'}}, + {format: 'u32', result: {primitiveType: 'u32', components: 1, byteLength: 1 * 4, integer: true, signed: false, defaultVertexFormat: 'uint32'}}, + {format: 'vec2', result: {primitiveType: 'u32', components: 2, byteLength: 2 * 4, integer: true, signed: false, defaultVertexFormat: 'uint32x2'}}, + {format: 'vec3', result: {primitiveType: 'u32', components: 3, byteLength: 3 * 4, integer: true, signed: false, defaultVertexFormat: 'uint32x3'}}, + {format: 'vec4', result: {primitiveType: 'u32', components: 4, byteLength: 4 * 4, integer: true, signed: false, defaultVertexFormat: 'uint32x4'}}, + {format: 'f16', result: {primitiveType: 'f16', components: 1, byteLength: 1 * 2, integer: false, signed: true, defaultVertexFormat: 'float16x2'}}, + {format: 'vec2', result: {primitiveType: 'f16', components: 2, byteLength: 2 * 2, integer: false, signed: true, defaultVertexFormat: 'float16x2'}}, + {format: 'vec3', result: {primitiveType: 'f16', components: 3, byteLength: 3 * 2, integer: false, signed: true, defaultVertexFormat: 'float16x4'}}, + {format: 'vec4', result: {primitiveType: 'f16', components: 4, byteLength: 4 * 2, integer: false, signed: true, defaultVertexFormat: 'float16x4'}}, + // {format: 'bool-webgl', result: {primitiveType: 'bool-webgl', components: 1, byteLength: 1 * 4, integer: true, signed: false}} +]; +*/ diff --git a/modules/core/test/gpu-type-utils/vertex-format-from-attribute.spec.ts b/modules/core/test/shadertypes/vertex-format-from-attribute.spec.ts similarity index 100% rename from modules/core/test/gpu-type-utils/vertex-format-from-attribute.spec.ts rename to modules/core/test/shadertypes/vertex-format-from-attribute.spec.ts diff --git a/modules/engine/src/debug/copy-texture-to-image.ts b/modules/engine/src/debug/copy-texture-to-image.ts index f85ac10c14..a332171958 100644 --- a/modules/engine/src/debug/copy-texture-to-image.ts +++ b/modules/engine/src/debug/copy-texture-to-image.ts @@ -2,8 +2,7 @@ // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors -import {Texture, Framebuffer} from '@luma.gl/core'; -import {flipRows, scalePixels} from './pixel-data-utils'; +import {Texture, Framebuffer, TypedArray} from '@luma.gl/core'; /** * Options for copying texture pixels to image @@ -71,3 +70,54 @@ export function copyTextureToDataUrl( return canvas.toDataURL('image/png'); } + +// HELPERS + +/** + * Flip rows (can be used on arrays returned from `Framebuffer.readPixels`) + * https: *stackoverflow.com/questions/41969562/ + * how-can-i-flip-the-result-of-webglrenderingcontext-readpixels + * @param param0 + */ +export function flipRows(options: { + data: TypedArray; + width: number; + height: number; + bytesPerPixel?: number; + temp?: Uint8Array; +}): void { + const {data, width, height, bytesPerPixel = 4, temp} = options; + const bytesPerRow = width * bytesPerPixel; + + // make a temp buffer to hold one row + const tempBuffer = temp || new Uint8Array(bytesPerRow); + for (let y = 0; y < height / 2; ++y) { + const topOffset = y * bytesPerRow; + const bottomOffset = (height - y - 1) * bytesPerRow; + // make copy of a row on the top half + tempBuffer.set(data.subarray(topOffset, topOffset + bytesPerRow)); + // copy a row from the bottom half to the top + data.copyWithin(topOffset, bottomOffset, bottomOffset + bytesPerRow); + // copy the copy of the top half row to the bottom half + data.set(tempBuffer, bottomOffset); + } +} + +export function scalePixels(options: {data: TypedArray; width: number; height: number}): { + data: Uint8Array; + width: number; + height: number; +} { + const {data, width, height} = options; + const newWidth = Math.round(width / 2); + const newHeight = Math.round(height / 2); + const newData = new Uint8Array(newWidth * newHeight * 4); + for (let y = 0; y < newHeight; y++) { + for (let x = 0; x < newWidth; x++) { + for (let c = 0; c < 4; c++) { + newData[(y * newWidth + x) * 4 + c] = data[(y * 2 * width + x * 2) * 4 + c]; + } + } + } + return {data: newData, width: newWidth, height: newHeight}; +} diff --git a/modules/engine/src/shader-inputs.ts b/modules/engine/src/shader-inputs.ts index c8d58d99d4..8dece21a0b 100644 --- a/modules/engine/src/shader-inputs.ts +++ b/modules/engine/src/shader-inputs.ts @@ -4,7 +4,7 @@ import type {Binding, UniformValue} from '@luma.gl/core'; import {log} from '@luma.gl/core'; -// import type {ShaderUniformType, UniformValue, UniformFormat, UniformInfoDevice, Texture, Sampler} from '@luma.gl/core'; +// import type {VariableShaderType, UniformValue, UniformFormat, UniformInfoDevice, Texture, Sampler} from '@luma.gl/core'; import {getShaderModuleDependencies, ShaderModule} from '@luma.gl/shadertools'; import {splitUniformsAndBindings} from './model/split-uniforms-and-bindings'; diff --git a/modules/engine/test/index.ts b/modules/engine/test/index.ts index 2181710c98..13abffd975 100644 --- a/modules/engine/test/index.ts +++ b/modules/engine/test/index.ts @@ -4,6 +4,7 @@ // utils import './utils/deep-equal.spec'; +import './utils/split-uniforms-and-bindings.spec'; // model etc import './lib/model.spec'; diff --git a/modules/webgl/test/utils/split-uniforms-and-bindings.spec.ts b/modules/engine/test/utils/split-uniforms-and-bindings.spec.ts similarity index 90% rename from modules/webgl/test/utils/split-uniforms-and-bindings.spec.ts rename to modules/engine/test/utils/split-uniforms-and-bindings.spec.ts index 1b0f79e6fb..12593b51ce 100644 --- a/modules/webgl/test/utils/split-uniforms-and-bindings.spec.ts +++ b/modules/engine/test/utils/split-uniforms-and-bindings.spec.ts @@ -3,7 +3,7 @@ // Copyright (c) vis.gl contributors import {WEBGLSampler, WEBGLTexture} from '@luma.gl/webgl'; -import {splitUniformsAndBindings} from '@luma.gl/webgl/utils/split-uniforms-and-bindings'; +import {splitUniformsAndBindings} from '@luma.gl/engine/model/split-uniforms-and-bindings'; import {getWebGLTestDevice} from '@luma.gl/test-utils'; import test from 'tape-promise/tape'; diff --git a/modules/shadertools/src/lib/wgsl/get-shader-layout-wgsl.ts b/modules/shadertools/src/lib/wgsl/get-shader-layout-wgsl.ts index d85c84a6aa..8ac3f6b299 100644 --- a/modules/shadertools/src/lib/wgsl/get-shader-layout-wgsl.ts +++ b/modules/shadertools/src/lib/wgsl/get-shader-layout-wgsl.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors -import {ShaderAttributeType, ShaderLayout, log} from '@luma.gl/core'; +import {AttributeShaderType, ShaderLayout, log} from '@luma.gl/core'; import {WgslReflect} from 'wgsl_reflect'; /** @@ -80,7 +80,7 @@ export function getShaderLayoutFromWGSL(source: string): ShaderLayout { } /** Get a valid shader attribute type string from a wgsl-reflect type */ -function getType(type: any): ShaderAttributeType { +function getType(type: any): AttributeShaderType { return type.format ? `${type.name}<${type.format.name}>` : type.name; } diff --git a/modules/shadertools/test/index.ts b/modules/shadertools/test/index.ts index ba2bfd1c8b..ff16c33703 100644 --- a/modules/shadertools/test/index.ts +++ b/modules/shadertools/test/index.ts @@ -52,7 +52,7 @@ import './modules/engine/picking.spec'; // Math modules // TODO - these are breaking in test-browser but not in test-headless?? -import './modules-webgl1/fp64/fp64-arithmetic-transform.spec'; +// import './modules-webgl1/fp64/fp64-arithmetic-transform.spec'; // Light and picking // import './modules-webgl1/dirlight/dirlight.spec'; diff --git a/modules/webgl/src/adapter/converters/shader-formats.ts b/modules/webgl/src/adapter/converters/shader-formats.ts index 72d6b8602e..60cac6c626 100644 --- a/modules/webgl/src/adapter/converters/shader-formats.ts +++ b/modules/webgl/src/adapter/converters/shader-formats.ts @@ -2,31 +2,35 @@ // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors -import {GL} from '@luma.gl/constants'; -import {ShaderAttributeType, ShaderDataType} from '@luma.gl/core'; +import {GL, GLDataType, GLPixelType} from '@luma.gl/constants'; +import {SignedDataType} from '@luma.gl/core'; -/** Get shader attribute type from GL constants */ -export function getShaderAttributeTypeFromGL( - type: GL, - components: 1 | 2 | 3 | 4 -): ShaderAttributeType { - const dataType = getShaderDataTypeFromGL(type); - switch (components) { - case 1: - return dataType; - case 2: - return `vec2<${dataType}>`; - case 3: - return `vec2<${dataType}>`; - case 4: - return `vec2<${dataType}>`; - default: - throw new Error(String(components)); - } +/** Get shadertypes data type from GL constants */ +export function convertGLDataTypeToDataType(type: GLDataType | GLPixelType): SignedDataType { + return GL_DATA_TYPE_MAP[type]; } -/** Get shader data type from GL constants */ -export function getShaderDataTypeFromGL(type: GL): ShaderDataType { +const GL_DATA_TYPE_MAP: Record = { + [GL.INT]: 'sint32', + [GL.UNSIGNED_INT]: 'uint32', + [GL.SHORT]: 'sint16', + [GL.UNSIGNED_SHORT]: 'uint16', + [GL.BYTE]: 'sint8', + [GL.UNSIGNED_BYTE]: 'uint8', + [GL.FLOAT]: 'float32', + [GL.HALF_FLOAT]: 'float16', + [GL.UNSIGNED_SHORT_5_6_5]: 'uint16', + [GL.UNSIGNED_SHORT_4_4_4_4]: 'uint16', + [GL.UNSIGNED_SHORT_5_5_5_1]: 'uint16', + [GL.UNSIGNED_INT_2_10_10_10_REV]: 'uint32', + [GL.UNSIGNED_INT_10F_11F_11F_REV]: 'uint32', + [GL.UNSIGNED_INT_5_9_9_9_REV]: 'uint32', + [GL.UNSIGNED_INT_24_8]: 'uint32', + [GL.FLOAT_32_UNSIGNED_INT_24_8_REV]: 'uint32' +}; + +/** Get shader data type from GL constants * +export function getPrimitiveTypeFromGL(type: GL): PrimitiveDataType { switch (type) { case GL.INT: return 'i32'; @@ -49,9 +53,30 @@ export function getShaderDataTypeFromGL(type: GL): ShaderDataType { } } -/** GetGL constant from shader data type */ +/** Get shader attribute type from GL constants * +export function getShaderAttributeTypeFromGL( + type: GL, + components: 1 | 2 | 3 | 4 +): AttributeShaderType { + const dataType = getPrimitiveTypeFromGL(type); + switch (components) { + case 1: + return dataType; + case 2: + return `vec2<${dataType}>`; + case 3: + return `vec2<${dataType}>`; + case 4: + return `vec2<${dataType}>`; + default: + throw new Error(String(components)); + } +} +*/ + +/** GetGL constant from shader data type export function getGLFromShaderDataType( - type: ShaderDataType + type: PrimitiveDataType ): GL.INT | GL.UNSIGNED_INT | GL.FLOAT | GL.HALF_FLOAT { switch (type) { // TODO @@ -67,3 +92,4 @@ export function getGLFromShaderDataType( throw new Error(String(type)); } } +*/ diff --git a/modules/webgl/src/adapter/converters/webgl-shadertypes.ts b/modules/webgl/src/adapter/converters/webgl-shadertypes.ts new file mode 100644 index 0000000000..7c1bd7abff --- /dev/null +++ b/modules/webgl/src/adapter/converters/webgl-shadertypes.ts @@ -0,0 +1,149 @@ +// luma.gl +// SPDX-License-Identifier: MIT +// Copyright (c) vis.gl contributors + +import {VariableShaderType, SignedDataType, VertexFormat, NormalizedDataType} from '@luma.gl/core'; +import {GL, GLUniformType, GLSamplerType, GLDataType} from '@luma.gl/constants'; + +export type TextureBindingInfo = { + viewDimension: '1d' | '2d' | '2d-array' | 'cube' | 'cube-array' | '3d'; + sampleType: 'float' | 'unfilterable-float' | 'depth' | 'sint' | 'uint'; +}; + +/** Converts to a luma shadertype to a GL data type (GL.BYTE, GL.FLOAT32 etc) */ +export function convertDataTypeToGLDataType(normalizedType: NormalizedDataType): GLDataType { + return NORMALIZED_SHADER_TYPE_TO_WEBGL[normalizedType]; +} + +/** Converts to a luma shadertype to a GL data type (GL.BYTE, GL.FLOAT32 etc) */ +export function convertShaderVariableTypeToGLDataType( + normalizedType: VariableShaderType +): GLDataType { + return NORMALIZED_SHADER_TYPE_TO_WEBGL[normalizedType]; +} + +/** Convert a WebGL "compisite type (e.g. GL.VEC3) into the corresponding luma shader uniform type */ +export function convertGLUniformTypeToShaderVariableType( + glUniformType: GLUniformType +): VariableShaderType { + return WEBGL_SHADER_TYPES[glUniformType]; +} + +/** Check if a WebGL "uniform:" is a texture binding */ +export function isGLSamplerType(type: GLUniformType | GLSamplerType): type is GLSamplerType { + return Boolean(WEBGL_SAMPLER_TO_TEXTURE_BINDINGS[type]); +} + +/* Get luma texture binding info (viewDimension and sampleType) from a WebGL "sampler" binding */ +export function getTextureBindingFromGLSamplerType( + glSamplerType: GLSamplerType +): TextureBindingInfo { + return WEBGL_SAMPLER_TO_TEXTURE_BINDINGS[glSamplerType]; +} + +/** Get vertex format from GL constants */ +export function getVertexFormatFromGL(type: GLDataType, components: 1 | 2 | 3 | 4): VertexFormat { + const base = getVertexTypeFromGL(type); + // prettier-ignore + switch (components) { + // @ts-expect-error TODO deal with lack of formats + case 1: return base; + case 2: return `${base}x2`; + // @ts-expect-error TODO deal with lack of formats + case 3: return `${base}x3`; + case 4: return `${base}x4`; + } + // @ts-ignore unreachable + throw new Error(String(components)); +} + +/** Get data type from GL constants */ +export function getVertexTypeFromGL(glType: GLDataType, normalized = false): NormalizedDataType { + const index = normalized ? 1 : 0; + return WEBGL_TO_NORMALIZED_DATA_TYPE[glType][index]; +} + +// Composite types table +const WEBGL_SHADER_TYPES: Record = { + [GL.FLOAT]: 'f32', + [GL.FLOAT_VEC2]: 'vec2', + [GL.FLOAT_VEC3]: 'vec3', + [GL.FLOAT_VEC4]: 'vec4', + + [GL.INT]: 'i32', + [GL.INT_VEC2]: 'vec2', + [GL.INT_VEC3]: 'vec3', + [GL.INT_VEC4]: 'vec4', + + [GL.UNSIGNED_INT]: 'u32', + [GL.UNSIGNED_INT_VEC2]: 'vec2', + [GL.UNSIGNED_INT_VEC3]: 'vec3', + [GL.UNSIGNED_INT_VEC4]: 'vec4', + + [GL.BOOL]: 'f32', + [GL.BOOL_VEC2]: 'vec2', + [GL.BOOL_VEC3]: 'vec3', + [GL.BOOL_VEC4]: 'vec4', + + // TODO - are sizes/components below correct? + [GL.FLOAT_MAT2]: 'mat2x2', + [GL.FLOAT_MAT2x3]: 'mat2x3', + [GL.FLOAT_MAT2x4]: 'mat2x4', + + [GL.FLOAT_MAT3x2]: 'mat3x2', + [GL.FLOAT_MAT3]: 'mat3x3', + [GL.FLOAT_MAT3x4]: 'mat3x4', + + [GL.FLOAT_MAT4x2]: 'mat4x2', + [GL.FLOAT_MAT4x3]: 'mat4x3', + [GL.FLOAT_MAT4]: 'mat4x4' +}; + +const WEBGL_SAMPLER_TO_TEXTURE_BINDINGS: Record = { + [GL.SAMPLER_2D]: {viewDimension: '2d', sampleType: 'float'}, + [GL.SAMPLER_CUBE]: {viewDimension: 'cube', sampleType: 'float'}, + [GL.SAMPLER_3D]: {viewDimension: '3d', sampleType: 'float'}, + [GL.SAMPLER_2D_SHADOW]: {viewDimension: '3d', sampleType: 'depth'}, + [GL.SAMPLER_2D_ARRAY]: {viewDimension: '2d-array', sampleType: 'float'}, + [GL.SAMPLER_2D_ARRAY_SHADOW]: {viewDimension: '2d-array', sampleType: 'depth'}, + [GL.SAMPLER_CUBE_SHADOW]: {viewDimension: 'cube', sampleType: 'float'}, + [GL.INT_SAMPLER_2D]: {viewDimension: '2d', sampleType: 'sint'}, + [GL.INT_SAMPLER_3D]: {viewDimension: '3d', sampleType: 'sint'}, + [GL.INT_SAMPLER_CUBE]: {viewDimension: 'cube', sampleType: 'sint'}, + [GL.INT_SAMPLER_2D_ARRAY]: {viewDimension: '2d-array', sampleType: 'uint'}, + [GL.UNSIGNED_INT_SAMPLER_2D]: {viewDimension: '2d', sampleType: 'uint'}, + [GL.UNSIGNED_INT_SAMPLER_3D]: {viewDimension: '3d', sampleType: 'uint'}, + [GL.UNSIGNED_INT_SAMPLER_CUBE]: {viewDimension: 'cube', sampleType: 'uint'}, + [GL.UNSIGNED_INT_SAMPLER_2D_ARRAY]: {viewDimension: '2d-array', sampleType: 'uint'} +}; + +/** Map from WebGL normalized types to WebGL */ +const NORMALIZED_SHADER_TYPE_TO_WEBGL: Record = { + uint8: GL.UNSIGNED_BYTE, + sint8: GL.BYTE, + unorm8: GL.UNSIGNED_BYTE, + snorm8: GL.BYTE, + uint16: GL.UNSIGNED_SHORT, + sint16: GL.SHORT, + unorm16: GL.UNSIGNED_SHORT, + snorm16: GL.SHORT, + uint32: GL.UNSIGNED_INT, + sint32: GL.INT, + // WebGPU does not support normalized 32 bit integer attributes + // 'unorm32': GL.UNSIGNED_INT, + // 'snorm32': GL.INT, + float16: GL.HALF_FLOAT, + float32: GL.FLOAT +}; + +/* Map from WebGL types to webgpu normalized types */ +const WEBGL_TO_NORMALIZED_DATA_TYPE: Record = { + [GL.BYTE]: ['sint8', 'snorm16'], + [GL.UNSIGNED_BYTE]: ['uint8', 'unorm8'], + [GL.SHORT]: ['sint16', 'unorm16'], + [GL.UNSIGNED_SHORT]: ['uint16', 'unorm16'], + [GL.INT]: ['sint32', 'sint32'], + [GL.UNSIGNED_INT]: ['uint32', 'uint32'], + [GL.FLOAT]: ['float32', 'float32'], + [GL.HALF_FLOAT]: ['float16', 'float16'] +}; diff --git a/modules/webgl/src/adapter/converters/webgl-texture-table.ts b/modules/webgl/src/adapter/converters/webgl-texture-table.ts index eece3cc899..c0e2949427 100644 --- a/modules/webgl/src/adapter/converters/webgl-texture-table.ts +++ b/modules/webgl/src/adapter/converters/webgl-texture-table.ts @@ -8,10 +8,10 @@ import type { TextureFormatCapabilities, DeviceTextureFormatCapabilities } from '@luma.gl/core'; -import {decodeTextureFormat} from '@luma.gl/core'; +import {getTextureFormatInfo} from '@luma.gl/core'; import {GL, GLPixelType, GLExtensions, GLTexelDataFormat} from '@luma.gl/constants'; import {getWebGLExtension} from '../../context/helpers/webgl-extensions'; -import {getGLFromVertexType} from './vertex-formats'; +import {getGLFromVertexType} from './webgl-vertex-formats'; /* eslint-disable camelcase */ @@ -332,7 +332,7 @@ export function getTextureFormatWebGL(format: TextureFormat): { } { const formatData = WEBGL_TEXTURE_FORMATS[format]; const webglFormat = convertTextureFormatToGL(format); - const decoded = decodeTextureFormat(format); + const decoded = getTextureFormatInfo(format); return { internalFormat: webglFormat, format: @@ -349,7 +349,7 @@ export function getTextureFormatWebGL(format: TextureFormat): { export function getDepthStencilAttachmentWebGL( format: TextureFormat ): GL.DEPTH_ATTACHMENT | GL.STENCIL_ATTACHMENT | GL.DEPTH_STENCIL_ATTACHMENT { - const formatInfo = decodeTextureFormat(format); + const formatInfo = getTextureFormatInfo(format); switch (formatInfo.attachment) { case 'depth': return GL.DEPTH_ATTACHMENT; @@ -364,7 +364,7 @@ export function getDepthStencilAttachmentWebGL( /** TODO - VERY roundabout legacy way of calculating bytes per pixel */ export function getTextureFormatBytesPerPixel(format: TextureFormat): number { - const formatInfo = decodeTextureFormat(format); + const formatInfo = getTextureFormatInfo(format); return formatInfo.bytesPerPixel; } diff --git a/modules/webgl/src/adapter/converters/vertex-formats.ts b/modules/webgl/src/adapter/converters/webgl-vertex-formats.ts similarity index 95% rename from modules/webgl/src/adapter/converters/vertex-formats.ts rename to modules/webgl/src/adapter/converters/webgl-vertex-formats.ts index ad6b2df77e..6b6fe97a33 100644 --- a/modules/webgl/src/adapter/converters/vertex-formats.ts +++ b/modules/webgl/src/adapter/converters/webgl-vertex-formats.ts @@ -3,7 +3,7 @@ // Copyright (c) vis.gl contributors import {GL} from '@luma.gl/constants'; -import {VertexFormat, VertexType} from '@luma.gl/core'; +import {VertexFormat, NormalizedDataType} from '@luma.gl/core'; type GLDataType = | GL.UNSIGNED_BYTE @@ -32,7 +32,7 @@ export function getVertexFormatFromGL(type: GLDataType, components: 1 | 2 | 3 | } /** Get data type from GL constants */ -export function getVertexTypeFromGL(type: GLDataType, normalized = false): VertexType { +export function getVertexTypeFromGL(type: GLDataType, normalized = false): NormalizedDataType { // prettier-ignore switch (type) { // WebGPU does not support normalized 32 bit integer attributes @@ -50,7 +50,7 @@ export function getVertexTypeFromGL(type: GLDataType, normalized = false): Verte } export function getGLFromVertexType( - dataType: VertexType + dataType: NormalizedDataType ): | GL.UNSIGNED_BYTE | GL.BYTE diff --git a/modules/webgl/src/adapter/helpers/decode-webgl-types.ts b/modules/webgl/src/adapter/helpers/decode-webgl-types.ts deleted file mode 100644 index 082e75051d..0000000000 --- a/modules/webgl/src/adapter/helpers/decode-webgl-types.ts +++ /dev/null @@ -1,134 +0,0 @@ -// luma.gl -// SPDX-License-Identifier: MIT -// Copyright (c) vis.gl contributors - -import {ShaderUniformType, ShaderAttributeType, VertexFormat} from '@luma.gl/core'; -import {GL, GLUniformType, GLSamplerType, GLCompositeType, GLDataType} from '@luma.gl/constants'; - -/** Check is uniform is of sampler type */ -export function isSamplerUniform(type: GLUniformType): boolean { - return SAMPLER_TYPES.includes(type as GLSamplerType); -} - -const SAMPLER_TYPES: GLSamplerType[] = [ - GL.SAMPLER_2D, - GL.SAMPLER_CUBE, - GL.SAMPLER_3D, - GL.SAMPLER_2D_SHADOW, - GL.SAMPLER_2D_ARRAY, - GL.SAMPLER_2D_ARRAY_SHADOW, - GL.SAMPLER_CUBE_SHADOW, - GL.INT_SAMPLER_2D, - GL.INT_SAMPLER_3D, - GL.INT_SAMPLER_CUBE, - GL.INT_SAMPLER_2D_ARRAY, - GL.UNSIGNED_INT_SAMPLER_2D, - GL.UNSIGNED_INT_SAMPLER_3D, - GL.UNSIGNED_INT_SAMPLER_CUBE, - GL.UNSIGNED_INT_SAMPLER_2D_ARRAY -]; - -// Composite types table -const COMPOSITE_GL_TYPES: Record< - GLCompositeType, - [GLDataType, number, string, ShaderUniformType, VertexFormat?] -> = { - [GL.FLOAT]: [GL.FLOAT, 1, 'float', 'f32', 'float32'], - [GL.FLOAT_VEC2]: [GL.FLOAT, 2, 'vec2', 'vec2', 'float32x2'], - [GL.FLOAT_VEC3]: [GL.FLOAT, 3, 'vec3', 'vec3', 'float32x3'], - [GL.FLOAT_VEC4]: [GL.FLOAT, 4, 'vec4', 'vec4', 'float32x4'], - - [GL.INT]: [GL.INT, 1, 'int', 'i32', 'sint32'], - [GL.INT_VEC2]: [GL.INT, 2, 'ivec2', 'vec2', 'sint32x2'], - [GL.INT_VEC3]: [GL.INT, 3, 'ivec3', 'vec3', 'sint32x3'], - [GL.INT_VEC4]: [GL.INT, 4, 'ivec4', 'vec4', 'sint32x4'], - - [GL.UNSIGNED_INT]: [GL.UNSIGNED_INT, 1, 'uint', 'u32', 'uint32'], - [GL.UNSIGNED_INT_VEC2]: [GL.UNSIGNED_INT, 2, 'uvec2', 'vec2', 'uint32x2'], - [GL.UNSIGNED_INT_VEC3]: [GL.UNSIGNED_INT, 3, 'uvec3', 'vec3', 'uint32x3'], - [GL.UNSIGNED_INT_VEC4]: [GL.UNSIGNED_INT, 4, 'uvec4', 'vec4', 'uint32x4'], - - [GL.BOOL]: [GL.FLOAT, 1, 'bool', 'f32', 'float32'], - [GL.BOOL_VEC2]: [GL.FLOAT, 2, 'bvec2', 'vec2', 'float32x2'], - [GL.BOOL_VEC3]: [GL.FLOAT, 3, 'bvec3', 'vec3', 'float32x3'], - [GL.BOOL_VEC4]: [GL.FLOAT, 4, 'bvec4', 'vec4', 'float32x4'], - - // TODO - are sizes/components below correct? - [GL.FLOAT_MAT2]: [GL.FLOAT, 8, 'mat2', 'mat2x2'], // 4 - [GL.FLOAT_MAT2x3]: [GL.FLOAT, 8, 'mat2x3', 'mat2x3'], // 6 - [GL.FLOAT_MAT2x4]: [GL.FLOAT, 8, 'mat2x4', 'mat2x4'], // 8 - - [GL.FLOAT_MAT3x2]: [GL.FLOAT, 12, 'mat3x2', 'mat3x2'], // 6 - [GL.FLOAT_MAT3]: [GL.FLOAT, 12, 'mat3', 'mat3x3'], // 9 - [GL.FLOAT_MAT3x4]: [GL.FLOAT, 12, 'mat3x4', 'mat3x4'], // 12 - - [GL.FLOAT_MAT4x2]: [GL.FLOAT, 16, 'mat4x2', 'mat4x2'], // 8 - [GL.FLOAT_MAT4x3]: [GL.FLOAT, 16, 'mat4x3', 'mat4x3'], // 12 - [GL.FLOAT_MAT4]: [GL.FLOAT, 16, 'mat4', 'mat4x4'] // 16 -}; - -/** Decomposes a composite type (GL.VEC3) into a basic type (GL.FLOAT) and components (3) */ -export function decodeGLUniformType(glUniformType: GL): { - format: ShaderUniformType; - components: number; - glType: GLDataType; -} { - const typeAndSize = COMPOSITE_GL_TYPES[glUniformType]; - if (!typeAndSize) { - throw new Error('uniform'); - } - const [glType, components, , format] = typeAndSize; - return {format, components, glType}; -} - -/** Decomposes a composite type (GL.VEC3) into a basic type (GL.FLOAT) and components (3) */ -export function decodeGLAttributeType(glAttributeType: GL): { - attributeType: ShaderAttributeType; - vertexFormat: VertexFormat; - components: number; - // glType: GLDataType; -} { - const typeAndSize = COMPOSITE_GL_TYPES[glAttributeType]; - if (!typeAndSize) { - throw new Error('attribute'); - } - const [, components, , shaderType, vertexFormat] = typeAndSize; - // TODO sanity - if (shaderType.startsWith('mat' ...)) - const attributeType = shaderType as unknown as ShaderAttributeType; - return {attributeType, vertexFormat, components}; // , glType}; -} - -/** Decomposes a composite type GL.VEC3 into a basic type (GL.FLOAT) and components (3) */ -export function decomposeCompositeGLDataType( - compositeGLDataType: GLCompositeType -): {type: GLDataType; components: number} | null { - const typeAndSize = COMPOSITE_GL_TYPES[compositeGLDataType]; - if (!typeAndSize) { - return null; - } - const [type, components] = typeAndSize; - return {type, components}; -} - -export function getCompositeGLDataType( - type: GL, - components -): {glType: GLDataType; name: string} | null { - switch (type) { - case GL.BYTE: - case GL.UNSIGNED_BYTE: - case GL.SHORT: - case GL.UNSIGNED_SHORT: - type = GL.FLOAT; - break; - default: - } - - for (const glType in COMPOSITE_GL_TYPES) { - const [compType, compComponents, name] = COMPOSITE_GL_TYPES[glType]; - if (compType === type && compComponents === components) { - return {glType: Number(glType), name}; - } - } - return null; -} diff --git a/modules/webgl/src/adapter/helpers/get-shader-layout.ts b/modules/webgl/src/adapter/helpers/get-shader-layout-from-glsl.ts similarity index 84% rename from modules/webgl/src/adapter/helpers/get-shader-layout.ts rename to modules/webgl/src/adapter/helpers/get-shader-layout-from-glsl.ts index 41fee4ff4e..05a771a01f 100644 --- a/modules/webgl/src/adapter/helpers/get-shader-layout.ts +++ b/modules/webgl/src/adapter/helpers/get-shader-layout-from-glsl.ts @@ -7,11 +7,17 @@ import type { UniformBinding, UniformBlockBinding, AttributeDeclaration, - VaryingBinding + VaryingBinding, + AttributeShaderType } from '@luma.gl/core'; +import {getVariableShaderTypeInfo} from '@luma.gl/core'; -import {GL} from '@luma.gl/constants'; -import {decodeGLUniformType, decodeGLAttributeType, isSamplerUniform} from './decode-webgl-types'; +import {GL, GLUniformType} from '@luma.gl/constants'; +import { + isGLSamplerType, + getTextureBindingFromGLSamplerType, + convertGLUniformTypeToShaderVariableType +} from '../converters/webgl-shadertypes'; /** * Extract metadata describing binding information for a program's shaders @@ -53,8 +59,8 @@ export function getShaderLayoutFromGLSL( const uniforms: UniformBinding[] = readUniformBindings(gl, program); let textureUnit = 0; for (const uniform of uniforms) { - if (isSamplerUniform(uniform.type)) { - const {viewDimension, sampleType} = getSamplerInfo(uniform.type); + if (isGLSamplerType(uniform.type)) { + const {viewDimension, sampleType} = getTextureBindingFromGLSamplerType(uniform.type); shaderLayout.bindings.push({ type: 'texture', name: uniform.name, @@ -108,7 +114,7 @@ function readAttributeDeclarations( const location = gl.getAttribLocation(program, name); // Add only user provided attributes, for built-in attributes like `gl_InstanceID` location will be < 0 if (location >= 0) { - const {attributeType} = decodeGLAttributeType(compositeType); + const attributeType = convertGLUniformTypeToShaderVariableType(compositeType); // Whether an attribute is instanced is essentially fixed by the structure of the shader code, // so it is arguably a static property of the shader. @@ -120,7 +126,7 @@ function readAttributeDeclarations( name, location, stepMode, - type: attributeType + type: attributeType as AttributeShaderType // size - for arrays, size is the number of elements in the array }); } @@ -145,10 +151,10 @@ function readVaryings(gl: WebGL2RenderingContext, program: WebGLProgram): Varyin if (!activeInfo) { throw new Error('activeInfo'); } - const {name, type: compositeType, size} = activeInfo; - const {glType, components} = decodeGLUniformType(compositeType); - const varying = {location, name, type: glType, size: size * components}; // Base values - varyings.push(varying); + const {name, type: glUniformType, size} = activeInfo; + const uniformType = convertGLUniformTypeToShaderVariableType(glUniformType as GLUniformType); + const {type, components} = getVariableShaderTypeInfo(uniformType); + varyings.push({location, name, type, size: size * components}); } varyings.sort((a, b) => a.location - b.location); @@ -251,9 +257,11 @@ function readUniformBlocks( throw new Error('activeInfo'); } + const format = convertGLUniformTypeToShaderVariableType(uniformType[i]); + blockInfo.uniforms.push({ name: activeInfo.name, - format: decodeGLUniformType(uniformType[i]).format, + format, type: uniformType[i], arrayLength: uniformArrayLength[i], byteOffset: uniformOffset[i], @@ -291,44 +299,6 @@ function readUniformBlocks( } */ -const SAMPLER_UNIFORMS_GL_TO_GPU: Record< - number, - [ - '1d' | '2d' | '2d-array' | 'cube' | 'cube-array' | '3d', - 'float' | 'unfilterable-float' | 'depth' | 'sint' | 'uint' - ] -> = { - [GL.SAMPLER_2D]: ['2d', 'float'], - [GL.SAMPLER_CUBE]: ['cube', 'float'], - [GL.SAMPLER_3D]: ['3d', 'float'], - [GL.SAMPLER_2D_SHADOW]: ['3d', 'depth'], - [GL.SAMPLER_2D_ARRAY]: ['2d-array', 'float'], - [GL.SAMPLER_2D_ARRAY_SHADOW]: ['2d-array', 'depth'], - [GL.SAMPLER_CUBE_SHADOW]: ['cube', 'float'], - [GL.INT_SAMPLER_2D]: ['2d', 'sint'], - [GL.INT_SAMPLER_3D]: ['3d', 'sint'], - [GL.INT_SAMPLER_CUBE]: ['cube', 'sint'], - [GL.INT_SAMPLER_2D_ARRAY]: ['2d-array', 'uint'], - [GL.UNSIGNED_INT_SAMPLER_2D]: ['2d', 'uint'], - [GL.UNSIGNED_INT_SAMPLER_3D]: ['3d', 'uint'], - [GL.UNSIGNED_INT_SAMPLER_CUBE]: ['cube', 'uint'], - [GL.UNSIGNED_INT_SAMPLER_2D_ARRAY]: ['2d-array', 'uint'] -}; - -type SamplerInfo = { - viewDimension: '1d' | '2d' | '2d-array' | 'cube' | 'cube-array' | '3d'; - sampleType: 'float' | 'unfilterable-float' | 'depth' | 'sint' | 'uint'; -}; - -function getSamplerInfo(type: GL): SamplerInfo { - const sampler = SAMPLER_UNIFORMS_GL_TO_GPU[type]; - if (!sampler) { - throw new Error('sampler'); - } - const [viewDimension, sampleType] = sampler; - return {viewDimension, sampleType}; -} - // HELPERS function parseUniformName(name: string): {name: string; length: number; isArray: boolean} { diff --git a/modules/webgl/src/adapter/helpers/set-uniform.ts b/modules/webgl/src/adapter/helpers/set-uniform.ts index 82a0215031..0cf4ca73d6 100644 --- a/modules/webgl/src/adapter/helpers/set-uniform.ts +++ b/modules/webgl/src/adapter/helpers/set-uniform.ts @@ -6,14 +6,14 @@ // Uniforms import type {UniformValue} from '@luma.gl/core'; -import {GL, GLCompositeType, GLSamplerType} from '@luma.gl/constants'; +import {GL, GLUniformType, GLSamplerType} from '@luma.gl/constants'; /** Set a raw uniform (without type conversion and caching) */ /* eslint-disable max-len */ export function setUniform( gl: WebGL2RenderingContext, location: WebGLUniformLocation, - type: GLCompositeType | GLSamplerType, + type: GLUniformType | GLSamplerType, value: UniformValue ): void { const gl2 = gl as WebGL2RenderingContext; diff --git a/modules/webgl/src/adapter/helpers/typed-array-utils.ts b/modules/webgl/src/adapter/helpers/typed-array-utils.ts deleted file mode 100644 index 1656aa0837..0000000000 --- a/modules/webgl/src/adapter/helpers/typed-array-utils.ts +++ /dev/null @@ -1,129 +0,0 @@ -// luma.gl -// SPDX-License-Identifier: MIT -// Copyright (c) vis.gl contributors - -import {TypedArray, TypedArrayConstructor} from '@math.gl/types'; -import {GL, GLDataType, GLPixelType} from '@luma.gl/constants'; - -const ERR_TYPE_DEDUCTION = 'Failed to deduce GL constant from typed array'; - -/** - * Converts TYPED ARRAYS to corresponding GL constant - * Used to auto deduce gl parameter types - * @deprecated Use getDataTypeFromTypedArray - * @param arrayOrType - * @returns - */ -export function getGLTypeFromTypedArray(arrayOrType: TypedArray): GLDataType { - // If typed array, look up constructor - const type = ArrayBuffer.isView(arrayOrType) ? arrayOrType.constructor : arrayOrType; - switch (type) { - case Float32Array: - return GL.FLOAT; - case Uint16Array: - return GL.UNSIGNED_SHORT; - case Uint32Array: - return GL.UNSIGNED_INT; - case Uint8Array: - return GL.UNSIGNED_BYTE; - case Uint8ClampedArray: - return GL.UNSIGNED_BYTE; - case Int8Array: - return GL.BYTE; - case Int16Array: - return GL.SHORT; - case Int32Array: - return GL.INT; - default: - throw new Error(ERR_TYPE_DEDUCTION); - } -} - -/** - * Converts GL constant to corresponding TYPED ARRAY - * Used to auto deduce gl parameter types - * @deprecated Use getTypedArrayFromDataType - * @param glType - * @param param1 - * @returns - */ -// eslint-disable-next-line complexity -export function getTypedArrayFromGLType( - glType: GLDataType | GLPixelType, - options?: { - clamped?: boolean; - } -): TypedArrayConstructor { - const {clamped = true} = options || {}; - // Sorted in some order of likelihood to reduce amount of comparisons - switch (glType) { - case GL.FLOAT: - return Float32Array; - case GL.UNSIGNED_SHORT: - case GL.UNSIGNED_SHORT_5_6_5: - case GL.UNSIGNED_SHORT_4_4_4_4: - case GL.UNSIGNED_SHORT_5_5_5_1: - return Uint16Array; - case GL.UNSIGNED_INT: - return Uint32Array; - case GL.UNSIGNED_BYTE: - return clamped ? Uint8ClampedArray : Uint8Array; - case GL.BYTE: - return Int8Array; - case GL.SHORT: - return Int16Array; - case GL.INT: - return Int32Array; - default: - throw new Error('Failed to deduce typed array type from GL constant'); - } -} - -/** - * Flip rows (can be used on arrays returned from `Framebuffer.readPixels`) - * https: *stackoverflow.com/questions/41969562/ - * how-can-i-flip-the-result-of-webglrenderingcontext-readpixels - * @param param0 - */ -export function flipRows(options: { - data: TypedArray; - width: number; - height: number; - bytesPerPixel?: number; - temp?: Uint8Array; -}): void { - const {data, width, height, bytesPerPixel = 4, temp} = options; - const bytesPerRow = width * bytesPerPixel; - - // make a temp buffer to hold one row - const tempBuffer = temp || new Uint8Array(bytesPerRow); - for (let y = 0; y < height / 2; ++y) { - const topOffset = y * bytesPerRow; - const bottomOffset = (height - y - 1) * bytesPerRow; - // make copy of a row on the top half - tempBuffer.set(data.subarray(topOffset, topOffset + bytesPerRow)); - // copy a row from the bottom half to the top - data.copyWithin(topOffset, bottomOffset, bottomOffset + bytesPerRow); - // copy the copy of the top half row to the bottom half - data.set(tempBuffer, bottomOffset); - } -} - -export function scalePixels(options: {data: TypedArray; width: number; height: number}): { - data: Uint8Array; - width: number; - height: number; -} { - const {data, width, height} = options; - const newWidth = Math.round(width / 2); - const newHeight = Math.round(height / 2); - const newData = new Uint8Array(newWidth * newHeight * 4); - for (let y = 0; y < newHeight; y++) { - for (let x = 0; x < newWidth; x++) { - for (let c = 0; c < 4; c++) { - newData[(y * newWidth + x) * 4 + c] = data[(y * 2 * width + x * 2) * 4 + c]; - } - } - } - return {data: newData, width: newWidth, height: newHeight}; -} diff --git a/modules/webgl/src/adapter/helpers/webgl-texture-utils.ts b/modules/webgl/src/adapter/helpers/webgl-texture-utils.ts index 3a568437d1..cada8bd2dc 100644 --- a/modules/webgl/src/adapter/helpers/webgl-texture-utils.ts +++ b/modules/webgl/src/adapter/helpers/webgl-texture-utils.ts @@ -2,7 +2,8 @@ // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors -import {Buffer, Texture, Framebuffer, FramebufferProps} from '@luma.gl/core'; +import type {Buffer, Texture, FramebufferProps} from '@luma.gl/core'; +import {Framebuffer, getTypedArrayFromDataType, getDataTypeFromTypedArray} from '@luma.gl/core'; import { GL, GLTextureTarget, @@ -12,11 +13,12 @@ import { GLDataType } from '@luma.gl/constants'; +import {convertDataTypeToGLDataType} from '../converters/webgl-shadertypes'; import {WEBGLFramebuffer} from '../resources/webgl-framebuffer'; -import {getGLTypeFromTypedArray, getTypedArrayFromGLType} from './typed-array-utils'; import {glFormatToComponents, glTypeToBytes} from './format-utils'; import {WEBGLBuffer} from '../resources/webgl-buffer'; import {WEBGLTexture} from '../resources/webgl-texture'; +import {convertGLDataTypeToDataType} from '../converters/shader-formats'; /** A "border" parameter is required in many WebGL texture APIs, but must always be 0... */ const BORDER = 0; @@ -449,7 +451,8 @@ export function readPixelsToArray( target = getPixelArray(target, sourceType, sourceFormat, sourceWidth, sourceHeight, sourceDepth); // Pixel array available, if necessary, deduce type from it. - sourceType = sourceType || getGLTypeFromTypedArray(target); + const signedType = getDataTypeFromTypedArray(target); + sourceType = sourceType || convertDataTypeToGLDataType(signedType); // Note: luma.gl overrides bindFramebuffer so that we can reliably restore the previous framebuffer (this is the only function for which we do that) const prevHandle = gl.bindFramebuffer( @@ -696,10 +699,11 @@ function getPixelArray( if (pixelArray) { return pixelArray; } - // const formatInfo = decodeTextureFormat(format); + // const formatInfo = getTextureFormatInfo(format); // Allocate pixel array if not already available, using supplied type glType ||= GL.UNSIGNED_BYTE; - const ArrayType = getTypedArrayFromGLType(glType, {clamped: false}); + const shaderType = convertGLDataTypeToDataType(glType); + const ArrayType = getTypedArrayFromDataType(shaderType); const components = glFormatToComponents(glFormat); // TODO - check for composite type (components = 1). return new ArrayType(width * height * components) as Uint8Array | Uint16Array | Float32Array; diff --git a/modules/webgl/src/adapter/resources/webgl-render-pipeline.ts b/modules/webgl/src/adapter/resources/webgl-render-pipeline.ts index 1bfe933dcd..5414a7dff2 100644 --- a/modules/webgl/src/adapter/resources/webgl-render-pipeline.ts +++ b/modules/webgl/src/adapter/resources/webgl-render-pipeline.ts @@ -16,10 +16,9 @@ import {RenderPipeline, log} from '@luma.gl/core'; // import {getAttributeInfosFromLayouts} from '@luma.gl/core'; import {GL} from '@luma.gl/constants'; -import {getShaderLayoutFromGLSL} from '../helpers/get-shader-layout'; +import {getShaderLayoutFromGLSL} from '../helpers/get-shader-layout-from-glsl'; import {withDeviceAndGLParameters} from '../converters/device-parameters'; import {setUniform} from '../helpers/set-uniform'; -import {splitUniformsAndBindings} from '../../utils/split-uniforms-and-bindings'; // import {copyUniform, checkUniformValues} from '../../classes/uniforms'; import {WebGLDevice} from '../webgl-device'; @@ -276,21 +275,6 @@ export class WEBGLRenderPipeline extends RenderPipeline { return true; } - // DEPRECATED METHODS - - override setUniformsWebGL(uniforms: Record) { - const {bindings} = splitUniformsAndBindings(uniforms); - Object.keys(bindings).forEach(name => { - log.warn( - `Unsupported value "${JSON.stringify( - bindings[name] - )}" used in setUniforms() for key ${name}. Use setBindings() instead?` - )(); - }); - // TODO - check against layout - Object.assign(this.uniforms, uniforms); - } - // PRIVATE METHODS // setAttributes(attributes: Record): void {} diff --git a/modules/webgl/src/adapter/resources/webgl-texture-view.ts b/modules/webgl/src/adapter/resources/webgl-texture-view.ts index d00889599b..106621ac4e 100644 --- a/modules/webgl/src/adapter/resources/webgl-texture-view.ts +++ b/modules/webgl/src/adapter/resources/webgl-texture-view.ts @@ -3,7 +3,7 @@ // Copyright (c) vis.gl contributors import type {Device, TextureViewProps} from '@luma.gl/core'; -// import {decodeTextureFormat} from '@luma.gl/core'; +// import {getTextureFormatInfo} from '@luma.gl/core'; import {TextureView, Texture} from '@luma.gl/core'; import {WebGLDevice} from '../webgl-device'; diff --git a/modules/webgl/src/adapter/resources/webgl-vertex-array.ts b/modules/webgl/src/adapter/resources/webgl-vertex-array.ts index 863a2713ef..3684a7db09 100644 --- a/modules/webgl/src/adapter/resources/webgl-vertex-array.ts +++ b/modules/webgl/src/adapter/resources/webgl-vertex-array.ts @@ -11,7 +11,7 @@ import {getBrowser} from '@probe.gl/env'; import {WebGLDevice} from '../webgl-device'; import {WEBGLBuffer} from '../resources/webgl-buffer'; -import {getGLFromVertexType} from '../converters/vertex-formats'; +import {getGLFromVertexType} from '../converters/webgl-vertex-formats'; import {fillArray} from '../../utils/fill-array'; /** VertexArrayObject wrapper */ diff --git a/modules/webgl/src/index.ts b/modules/webgl/src/index.ts index 8990b0fb64..9846d12491 100644 --- a/modules/webgl/src/index.ts +++ b/modules/webgl/src/index.ts @@ -42,7 +42,7 @@ export {WEBGLTransformFeedback} from './adapter/resources/webgl-transform-feedba export {setDeviceParameters, withDeviceParameters} from './adapter/converters/device-parameters'; // HELPERS - EXPERIMENTAL -export {getShaderLayoutFromGLSL} from './adapter/helpers/get-shader-layout'; +export {getShaderLayoutFromGLSL} from './adapter/helpers/get-shader-layout-from-glsl'; export {WebGLStateTracker} from './context/state-tracker/webgl-state-tracker'; // DEPRECATED TEST EXPORTS diff --git a/modules/webgl/src/utils/split-uniforms-and-bindings.ts b/modules/webgl/src/utils/split-uniforms-and-bindings.ts deleted file mode 100644 index 1da76354c1..0000000000 --- a/modules/webgl/src/utils/split-uniforms-and-bindings.ts +++ /dev/null @@ -1,31 +0,0 @@ -// luma.gl -// SPDX-License-Identifier: MIT -// Copyright (c) vis.gl contributors - -import type {UniformValue, Binding} from '@luma.gl/core'; -import {isNumericArray} from '@math.gl/types'; - -export function isUniformValue(value: unknown): value is UniformValue { - return isNumericArray(value) !== null || typeof value === 'number' || typeof value === 'boolean'; -} - -type UniformsAndBindings = { - bindings: Record; - uniforms: Record; -}; - -export function splitUniformsAndBindings( - uniforms: Record -): UniformsAndBindings { - const result: UniformsAndBindings = {bindings: {}, uniforms: {}}; - Object.keys(uniforms).forEach(name => { - const uniform = uniforms[name]; - if (isUniformValue(uniform)) { - result.uniforms[name] = uniform; - } else { - result.bindings[name] = uniform; - } - }); - - return result; -} diff --git a/modules/webgpu/src/adapter/helpers/get-vertex-buffer-layout.ts b/modules/webgpu/src/adapter/helpers/get-vertex-buffer-layout.ts index 9fe3130c0b..55aff3d846 100644 --- a/modules/webgpu/src/adapter/helpers/get-vertex-buffer-layout.ts +++ b/modules/webgpu/src/adapter/helpers/get-vertex-buffer-layout.ts @@ -3,7 +3,7 @@ // Copyright (c) vis.gl contributors import type {ShaderLayout, BufferLayout, AttributeDeclaration, VertexFormat} from '@luma.gl/core'; -import {log, decodeVertexFormat} from '@luma.gl/core'; +import {log, getVertexFormatInfo} from '@luma.gl/core'; // import {getAttributeInfosFromLayouts} from '@luma.gl/core'; /** Throw error on any WebGL-only vertex formats */ @@ -58,7 +58,7 @@ export function getVertexBufferLayout( shaderLocation: location }); - byteStride += decodeVertexFormat(format).byteLength; + byteStride += getVertexFormatInfo(format).byteLength; } // non-interleaved mapping (just set offset and stride) } else { @@ -66,7 +66,7 @@ export function getVertexBufferLayout( if (!attributeLayout) { continue; // eslint-disable-line no-continue } - byteStride = decodeVertexFormat(format).byteLength; + byteStride = getVertexFormatInfo(format).byteLength; stepMode = attributeLayout.stepMode || @@ -91,7 +91,7 @@ export function getVertexBufferLayout( for (const attribute of shaderLayout.attributes) { if (!usedAttributes.has(attribute.name)) { vertexBufferLayouts.push({ - arrayStride: decodeVertexFormat('float32x3').byteLength, + arrayStride: getVertexFormatInfo('float32x3').byteLength, stepMode: attribute.stepMode || (attribute.name.startsWith('instance') ? 'instance' : 'vertex'), attributes: [ diff --git a/package.json b/package.json index 62c0c71b27..74c605cd46 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "@types/offscreencanvas": "^2019.6.4" }, "volta": { - "node": "20.11.1", + "node": "20.17.0", "yarn": "4.4.1" } } diff --git a/website/package.json b/website/package.json index c96843718c..5e8d7333f7 100644 --- a/website/package.json +++ b/website/package.json @@ -37,7 +37,7 @@ }, "browserslist": {}, "volta": { - "node": "20.11.1", - "yarn": "4.4.0" + "node": "20.17.0", + "yarn": "4.4.1" } } diff --git a/modules/webgl/wip/constants-to-keys.ts b/wip/wip/constants-to-keys.ts similarity index 100% rename from modules/webgl/wip/constants-to-keys.ts rename to wip/wip/constants-to-keys.ts diff --git a/modules/webgl/wip/deprecated/accessor.ts b/wip/wip/deprecated/accessor.ts similarity index 100% rename from modules/webgl/wip/deprecated/accessor.ts rename to wip/wip/deprecated/accessor.ts diff --git a/modules/webgl/wip/webgl-renderbuffer.spec.ts b/wip/wip/webgl-renderbuffer.spec.ts similarity index 100% rename from modules/webgl/wip/webgl-renderbuffer.spec.ts rename to wip/wip/webgl-renderbuffer.spec.ts diff --git a/modules/webgl/wip/webgl-renderbuffer.ts b/wip/wip/webgl-renderbuffer.ts similarity index 100% rename from modules/webgl/wip/webgl-renderbuffer.ts rename to wip/wip/webgl-renderbuffer.ts diff --git a/modules/webgl/wip/webgl-resource.ts b/wip/wip/webgl-resource.ts similarity index 100% rename from modules/webgl/wip/webgl-resource.ts rename to wip/wip/webgl-resource.ts diff --git a/modules/webgl/wip/webgl-vertex-array-object.spec.ts b/wip/wip/webgl-vertex-array-object.spec.ts similarity index 100% rename from modules/webgl/wip/webgl-vertex-array-object.spec.ts rename to wip/wip/webgl-vertex-array-object.spec.ts