// luma.gl // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors import { decodeTextureFormat } from '@luma.gl/core'; import { GL } from '@luma.gl/constants'; import { getWebGLExtension } from "../../context/helpers/webgl-extensions.js"; import { getGLFromVertexType } from "./vertex-formats.js"; /* eslint-disable camelcase */ // TEXTURE FEATURES // Define local device feature strings to optimize minification const texture_compression_bc = 'texture-compression-bc'; const texture_compression_astc = 'texture-compression-astc'; const texture_compression_etc2 = 'texture-compression-etc2'; const texture_compression_etc1_webgl = 'texture-compression-etc1-webgl'; const texture_compression_pvrtc_webgl = 'texture-compression-pvrtc-webgl'; const texture_compression_atc_webgl = 'texture-compression-atc-webgl'; const float32_renderable = 'float32-renderable-webgl'; const float16_renderable = 'float16-renderable-webgl'; const rgb9e5ufloat_renderable = 'rgb9e5ufloat_renderable-webgl'; const snorm8_renderable = 'snorm8-renderable-webgl'; const norm16_renderable = 'norm16-renderable-webgl'; const snorm16_renderable = 'snorm16-renderable-webgl'; const float32_filterable = 'float32-filterable'; const float16_filterable = 'float16-filterable-webgl'; // Define local webgl extension strings to optimize minification const X_S3TC = 'WEBGL_compressed_texture_s3tc'; // BC1, BC2, BC3 const X_S3TC_SRGB = 'WEBGL_compressed_texture_s3tc_srgb'; // BC1, BC2, BC3 const X_RGTC = 'EXT_texture_compression_rgtc'; // BC4, BC5 const X_BPTC = 'EXT_texture_compression_bptc'; // BC6, BC7 const X_ETC2 = 'WEBGL_compressed_texture_etc'; // Renamed from 'WEBGL_compressed_texture_es3' const X_ASTC = 'WEBGL_compressed_texture_astc'; const X_ETC1 = 'WEBGL_compressed_texture_etc1'; const X_PVRTC = 'WEBGL_compressed_texture_pvrtc'; const X_ATC = 'WEBGL_compressed_texture_atc'; // Define local webgl extension strings to optimize minification const EXT_texture_norm16 = 'EXT_texture_norm16'; const EXT_render_snorm = 'EXT_render_snorm'; const EXT_color_buffer_float = 'EXT_color_buffer_float'; // prettier-ignore export const TEXTURE_FEATURES = { 'float32-renderable-webgl': ['EXT_color_buffer_float'], 'float16-renderable-webgl': ['EXT_color_buffer_half_float'], 'rgb9e5ufloat_renderable-webgl': ['WEBGL_render_shared_exponent'], 'snorm8-renderable-webgl': [EXT_render_snorm], 'norm16-renderable-webgl': [EXT_texture_norm16], 'snorm16-renderable-webgl': [EXT_texture_norm16, EXT_render_snorm], 'float32-filterable': ['OES_texture_float_linear'], 'float16-filterable-webgl': ['OES_texture_half_float_linear'], 'texture-filterable-anisotropic-webgl': ['EXT_texture_filter_anisotropic'], 'texture-blend-float-webgl': ['EXT_float_blend'], 'texture-compression-bc': [X_S3TC, X_S3TC_SRGB, X_RGTC, X_BPTC], // 'texture-compression-bc3-srgb-webgl': [X_S3TC_SRGB], // 'texture-compression-bc3-webgl': [X_S3TC], 'texture-compression-bc5-webgl': [X_RGTC], 'texture-compression-bc7-webgl': [X_BPTC], 'texture-compression-etc2': [X_ETC2], 'texture-compression-astc': [X_ASTC], 'texture-compression-etc1-webgl': [X_ETC1], 'texture-compression-pvrtc-webgl': [X_PVRTC], 'texture-compression-atc-webgl': [X_ATC] }; /** Return a list of texture feature strings (for Device.features). Mainly compressed texture support */ // export function getTextureFeatures( // gl: WebGL2RenderingContext, // extensions: GLExtensions // ): DeviceFeature[] { // const textureFeatures = Object.keys(TEXTURE_FEATURES) as DeviceFeature[]; // return textureFeatures.filter(feature => checkTextureFeature(gl, feature, extensions)); // } export function isTextureFeature(feature) { return feature in TEXTURE_FEATURES; } /** Checks a texture feature (for Device.features). Mainly compressed texture support */ export function checkTextureFeature(gl, feature, extensions) { const textureExtensions = TEXTURE_FEATURES[feature] || []; return textureExtensions.every(extension => getWebGLExtension(gl, extension, extensions)); } // TABLES /** * Texture format data - * Exported but can change without notice */ // prettier-ignore export const TEXTURE_FORMATS = { // Unsized formats that leave the precision up to the driver. TODO - Fix bpp constants 'rgb8unorm-unsized': { gl: 6407, b: 4, c: 2, bpp: 4, dataFormat: 6407, types: [5121, 33635] }, 'rgba8unorm-unsized': { gl: 6408, b: 4, c: 2, bpp: 4, dataFormat: 6408, types: [5121, 32819, 32820] }, // 'r8unorm-unsized': {gl: GL.LUMINANCE, b: 4, c: 2, bpp: 4}, // 'rgb8unorm-srgb-unsized': {gl: GL.SRGB_EXT, b: 4, c: 2, bpp: 4, gl1Ext: SRGB}, // 'rgba8unorm-srgb-unsized': {gl: GL.SRGB_ALPHA_EXT, b: 4, c: 2, bpp: 4, gl1Ext: SRGB}, // 8-bit formats 'r8unorm': { gl: 33321, b: 1, c: 1, rb: true }, 'r8snorm': { gl: 36756, b: 1, c: 1, render: snorm8_renderable }, 'r8uint': { gl: 33330, b: 1, c: 1, rb: true }, 'r8sint': { gl: 33329, b: 1, c: 1, rb: true }, // 16-bit formats 'rg8unorm': { gl: 33323, b: 2, c: 2, rb: true }, 'rg8snorm': { gl: 36757, b: 2, c: 2, render: snorm8_renderable }, 'rg8uint': { gl: 33336, b: 2, c: 2, rb: true }, 'rg8sint': { gl: 33335, b: 2, c: 2, rb: true }, 'r16uint': { gl: 33332, b: 2, c: 1, rb: true }, 'r16sint': { gl: 33331, b: 2, c: 1, rb: true }, 'r16float': { gl: 33325, b: 2, c: 1, render: float16_renderable, filter: 'float16-filterable-webgl', rb: true }, 'r16unorm-webgl': { gl: 33322, b: 2, c: 1, f: norm16_renderable, rb: true }, 'r16snorm-webgl': { gl: 36760, b: 2, c: 1, f: snorm16_renderable }, // Packed 16-bit formats 'rgba4unorm-webgl': { gl: 32854, b: 2, c: 4, wgpu: false, rb: true }, 'rgb565unorm-webgl': { gl: 36194, b: 2, c: 4, wgpu: false, rb: true }, 'rgb5a1unorm-webgl': { gl: 32855, b: 2, c: 4, wgpu: false, rb: true }, // 24-bit formats 'rgb8unorm-webgl': { gl: 32849, b: 3, c: 3, wgpu: false }, 'rgb8snorm-webgl': { gl: 36758, b: 3, c: 3, wgpu: false }, // 32-bit formats 'rgba8unorm': { gl: 32856, b: 4, c: 2, bpp: 4 }, 'rgba8unorm-srgb': { gl: 35907, b: 4, c: 4, bpp: 4 }, 'rgba8snorm': { gl: 36759, b: 4, c: 4, render: snorm8_renderable }, 'rgba8uint': { gl: 36220, b: 4, c: 4, bpp: 4 }, 'rgba8sint': { gl: 36238, b: 4, c: 4, bpp: 4 }, // reverse colors, webgpu only 'bgra8unorm': { b: 4, c: 4 }, 'bgra8unorm-srgb': { b: 4, c: 4 }, 'rg16uint': { gl: 33338, b: 4, c: 1, bpp: 4 }, 'rg16sint': { gl: 33337, b: 4, c: 2, bpp: 4 }, // When using a WebGL 2 context and the EXT_color_buffer_float WebGL2 extension 'rg16float': { gl: 33327, bpp: 4, b: 4, c: 2, render: float16_renderable, filter: float16_filterable, rb: true }, 'rg16unorm-webgl': { gl: 33324, b: 2, c: 2, render: norm16_renderable }, 'rg16snorm-webgl': { gl: 36761, b: 2, c: 2, render: snorm16_renderable }, 'r32uint': { gl: 33334, b: 4, c: 1, bpp: 4, rb: true }, 'r32sint': { gl: 33333, b: 4, c: 1, bpp: 4, rb: true }, 'r32float': { gl: 33326, bpp: 4, b: 4, c: 1, render: float32_renderable, filter: float32_filterable }, // Packed 32-bit formats 'rgb9e5ufloat': { gl: 35901, b: 4, c: 3, p: 1, render: rgb9e5ufloat_renderable }, // , filter: true}, 'rg11b10ufloat': { gl: 35898, b: 4, c: 3, p: 1, render: float32_renderable, rb: true }, 'rgb10a2unorm': { gl: 32857, b: 4, c: 4, p: 1, rb: true }, 'rgb10a2uint-webgl': { b: 4, c: 4, gl: 36975, p: 1, wgpu: false, bpp: 4, rb: true }, // 48-bit formats 'rgb16unorm-webgl': { gl: 32852, b: 2, c: 3, f: norm16_renderable }, // rgb not renderable 'rgb16snorm-webgl': { gl: 36762, b: 2, c: 3, f: norm16_renderable }, // rgb not renderable // 64-bit formats 'rg32uint': { gl: 33340, b: 8, c: 2, rb: true }, 'rg32sint': { gl: 33339, b: 8, c: 2, rb: true }, 'rg32float': { gl: 33328, b: 8, c: 2, render: float32_renderable, filter: float32_filterable, rb: true }, 'rgba16uint': { gl: 36214, b: 8, c: 4, rb: true }, 'rgba16sint': { gl: 36232, b: 8, c: 4, rb: true }, 'rgba16float': { gl: 34842, b: 8, c: 4, render: float16_renderable, filter: float16_filterable }, 'rgba16unorm-webgl': { gl: 32859, b: 2, c: 4, render: norm16_renderable, rb: true }, 'rgba16snorm-webgl': { gl: 36763, b: 2, c: 4, render: snorm16_renderable }, // 96-bit formats (deprecated!) 'rgb32float-webgl': { gl: 34837, render: float32_renderable, filter: float32_filterable, gl2ext: EXT_color_buffer_float, dataFormat: 6407, types: [5126] }, // 128-bit formats 'rgba32uint': { gl: 36208, b: 16, c: 4, rb: true }, 'rgba32sint': { gl: 36226, b: 16, c: 4, rb: true }, 'rgba32float': { gl: 34836, b: 16, c: 4, render: float32_renderable, filter: float32_filterable, rb: true }, // Depth and stencil formats 'stencil8': { gl: 36168, b: 1, c: 1, attachment: 36128, rb: true }, // 8 stencil bits 'depth16unorm': { gl: 33189, b: 2, c: 1, attachment: 36096, dataFormat: 6402, types: [5123], rb: true }, // 16 depth bits 'depth24plus': { gl: 33190, b: 3, c: 1, attachment: 36096, dataFormat: 6402, types: [5125] }, 'depth32float': { gl: 36012, b: 4, c: 1, attachment: 36096, dataFormat: 6402, types: [5126], rb: true }, // The depth component of the "depth24plus" and "depth24plus-stencil8" formats may be implemented as either a 24-bit depth value or a "depth32float" value. 'depth24plus-stencil8': { gl: 35056, b: 4, c: 2, p: 1, attachment: 33306, rb: true, depthTexture: true, dataFormat: 34041, types: [34042] }, // "depth24unorm-stencil8" feature 'depth24unorm-stencil8': { gl: 35056, b: 4, c: 2, p: 1, attachment: 33306, dataFormat: 34041, types: [34042], rb: true }, // "depth32float-stencil8" feature - TODO below is render buffer only? 'depth32float-stencil8': { gl: 36013, b: 5, c: 2, p: 1, attachment: 33306, dataFormat: 34041, types: [36269], rb: true }, // BC compressed formats: check device.features.has("texture-compression-bc"); 'bc1-rgb-unorm-webgl': { gl: 33776, x: X_S3TC, f: texture_compression_bc }, 'bc1-rgb-unorm-srgb-webgl': { gl: 35916, x: X_S3TC_SRGB, f: texture_compression_bc }, 'bc1-rgba-unorm': { gl: 33777, x: X_S3TC, f: texture_compression_bc }, 'bc1-rgba-unorm-srgb': { gl: 35916, x: X_S3TC_SRGB, f: texture_compression_bc }, 'bc2-rgba-unorm': { gl: 33778, x: X_S3TC, f: texture_compression_bc }, 'bc2-rgba-unorm-srgb': { gl: 35918, x: X_S3TC_SRGB, f: texture_compression_bc }, 'bc3-rgba-unorm': { gl: 33779, x: X_S3TC, f: texture_compression_bc }, 'bc3-rgba-unorm-srgb': { gl: 35919, x: X_S3TC_SRGB, f: texture_compression_bc }, 'bc4-r-unorm': { gl: 36283, x: X_RGTC, f: texture_compression_bc }, 'bc4-r-snorm': { gl: 36284, x: X_RGTC, f: texture_compression_bc }, 'bc5-rg-unorm': { gl: 36285, x: X_RGTC, f: texture_compression_bc }, 'bc5-rg-snorm': { gl: 36286, x: X_RGTC, f: texture_compression_bc }, 'bc6h-rgb-ufloat': { gl: 36495, x: X_BPTC, f: texture_compression_bc }, 'bc6h-rgb-float': { gl: 36494, x: X_BPTC, f: texture_compression_bc }, 'bc7-rgba-unorm': { gl: 36492, x: X_BPTC, f: texture_compression_bc }, 'bc7-rgba-unorm-srgb': { gl: 36493, x: X_BPTC, f: texture_compression_bc }, // WEBGL_compressed_texture_etc: device.features.has("texture-compression-etc2") // Note: Supposedly guaranteed availability compressed formats in WebGL2, but through CPU decompression 'etc2-rgb8unorm': { gl: 37492, f: texture_compression_etc2 }, 'etc2-rgb8unorm-srgb': { gl: 37494, f: texture_compression_etc2 }, 'etc2-rgb8a1unorm': { gl: 37496, f: texture_compression_etc2 }, 'etc2-rgb8a1unorm-srgb': { gl: 37497, f: texture_compression_etc2 }, 'etc2-rgba8unorm': { gl: 37493, f: texture_compression_etc2 }, 'etc2-rgba8unorm-srgb': { gl: 37495, f: texture_compression_etc2 }, 'eac-r11unorm': { gl: 37488, f: texture_compression_etc2 }, 'eac-r11snorm': { gl: 37489, f: texture_compression_etc2 }, 'eac-rg11unorm': { gl: 37490, f: texture_compression_etc2 }, 'eac-rg11snorm': { gl: 37491, f: texture_compression_etc2 }, // X_ASTC compressed formats: device.features.has("texture-compression-astc") 'astc-4x4-unorm': { gl: 37808, f: texture_compression_astc }, 'astc-4x4-unorm-srgb': { gl: 37840, f: texture_compression_astc }, 'astc-5x4-unorm': { gl: 37809, f: texture_compression_astc }, 'astc-5x4-unorm-srgb': { gl: 37841, f: texture_compression_astc }, 'astc-5x5-unorm': { gl: 37810, f: texture_compression_astc }, 'astc-5x5-unorm-srgb': { gl: 37842, f: texture_compression_astc }, 'astc-6x5-unorm': { gl: 37811, f: texture_compression_astc }, 'astc-6x5-unorm-srgb': { gl: 37843, f: texture_compression_astc }, 'astc-6x6-unorm': { gl: 37812, f: texture_compression_astc }, 'astc-6x6-unorm-srgb': { gl: 37844, f: texture_compression_astc }, 'astc-8x5-unorm': { gl: 37813, f: texture_compression_astc }, 'astc-8x5-unorm-srgb': { gl: 37845, f: texture_compression_astc }, 'astc-8x6-unorm': { gl: 37814, f: texture_compression_astc }, 'astc-8x6-unorm-srgb': { gl: 37846, f: texture_compression_astc }, 'astc-8x8-unorm': { gl: 37815, f: texture_compression_astc }, 'astc-8x8-unorm-srgb': { gl: 37847, f: texture_compression_astc }, 'astc-10x5-unorm': { gl: 37819, f: texture_compression_astc }, 'astc-10x5-unorm-srgb': { gl: 37851, f: texture_compression_astc }, 'astc-10x6-unorm': { gl: 37817, f: texture_compression_astc }, 'astc-10x6-unorm-srgb': { gl: 37849, f: texture_compression_astc }, 'astc-10x8-unorm': { gl: 37818, f: texture_compression_astc }, 'astc-10x8-unorm-srgb': { gl: 37850, f: texture_compression_astc }, 'astc-10x10-unorm': { gl: 37819, f: texture_compression_astc }, 'astc-10x10-unorm-srgb': { gl: 37851, f: texture_compression_astc }, 'astc-12x10-unorm': { gl: 37820, f: texture_compression_astc }, 'astc-12x10-unorm-srgb': { gl: 37852, f: texture_compression_astc }, 'astc-12x12-unorm': { gl: 37821, f: texture_compression_astc }, 'astc-12x12-unorm-srgb': { gl: 37853, f: texture_compression_astc }, // WEBGL_compressed_texture_pvrtc 'pvrtc-rgb4unorm-webgl': { gl: 35840, f: texture_compression_pvrtc_webgl }, 'pvrtc-rgba4unorm-webgl': { gl: 35842, f: texture_compression_pvrtc_webgl }, 'pvrtc-rbg2unorm-webgl': { gl: 35841, f: texture_compression_pvrtc_webgl }, 'pvrtc-rgba2unorm-webgl': { gl: 35843, f: texture_compression_pvrtc_webgl }, // WEBGL_compressed_texture_etc1 'etc1-rbg-unorm-webgl': { gl: 36196, f: texture_compression_etc1_webgl }, // WEBGL_compressed_texture_atc 'atc-rgb-unorm-webgl': { gl: 35986, f: texture_compression_atc_webgl }, 'atc-rgba-unorm-webgl': { gl: 35986, f: texture_compression_atc_webgl }, 'atc-rgbai-unorm-webgl': { gl: 34798, f: texture_compression_atc_webgl } }; /** Legal combinations for internalFormat, format and type * // [GL.DEPTH_COMPONENT]: {types: [GL.UNSIGNED_SHORT, GL.UNSIGNED_INT, GL.UNSIGNED_INT_24_8]}, // [GL.DEPTH_STENCIL]: , // Sized texture format // R [GL.R8]: {dataFormat: GL.RED, types: [GL.UNSIGNED_BYTE], gl2: true}, [GL.R16F]: {dataFormat: GL.RED, types: [GL.HALF_FLOAT, GL.FLOAT], gl2: true}, [GL.R8UI]: {dataFormat: GL.RED_INTEGER, types: [GL.UNSIGNED_BYTE], gl2: true}, // // RG [GL.RG8]: {dataFormat: GL.RG, types: [GL.UNSIGNED_BYTE], gl2: true}, [GL.RG16F]: {dataFormat: GL.RG, types: [GL.HALF_FLOAT, GL.FLOAT], gl2: true}, [GL.RG8UI]: {dataFormat: GL.RG_INTEGER, types: [GL.UNSIGNED_BYTE], gl2: true}, // // RGB [GL.RGB8]: {dataFormat: GL.RGB, types: [GL.UNSIGNED_BYTE], gl2: true}, [GL.SRGB8]: {dataFormat: GL.RGB, types: [GL.UNSIGNED_BYTE], gl2: true}, [GL.RGB16F]: {dataFormat: GL.RGB, types: [GL.HALF_FLOAT, GL.FLOAT], gl2: true}, [GL.RGB8UI]: {dataFormat: GL.RGB_INTEGER, types: [GL.UNSIGNED_BYTE], gl2: true}, // // RGBA [GL.RGB565]: {dataFormat: GL.RGB, types: [GL.UNSIGNED_BYTE, GL.UNSIGNED_SHORT_5_6_5], gl2: true}, [GL.R11F_G11F_B10F]: {dataFormat: GL.RGB, types: [GL.UNSIGNED_INT_10F_11F_11F_REV, GL.HALF_FLOAT, GL.FLOAT], gl2: true}, [GL.RGB9_E5]: {dataFormat: GL.RGB, types: [GL.HALF_FLOAT, GL.FLOAT], gl2: true}, [GL.RGBA8]: {dataFormat: GL.RGBA, types: [GL.UNSIGNED_BYTE], gl2: true}, [GL.SRGB8_ALPHA8]: {dataFormat: GL.RGBA, types: [GL.UNSIGNED_BYTE], gl2: true, gl1ext: EXT_SRGB}, [GL.RGB5_A1]: {dataFormat: GL.RGBA, types: [GL.UNSIGNED_BYTE, GL.UNSIGNED_SHORT_5_5_5_1], gl2: true}, [GL.RGBA4]: {dataFormat: GL.RGBA, types: [GL.UNSIGNED_BYTE, GL.UNSIGNED_SHORT_4_4_4_4], gl2: true}, [GL.RGBA16F]: {dataFormat: GL.RGBA, types: [GL.HALF_FLOAT, GL.FLOAT], gl2: true}, [GL.RGBA8UI]: {dataFormat: GL.RGBA_INTEGER, types: [GL.UNSIGNED_BYTE], gl2: true} */ /* This table is now baked into the above table type RenderbufferFormat = { bpp: number; gl2?: boolean; ext?: string; }; export const RENDERBUFFER_FORMATS: Record = { [GL.DEPTH_COMPONENT16]: {bpp: 2}, // 16 depth bits. // TODO - Not clear which webgpu value to map this to. // [GL.DEPTH_COMPONENT24]: {gl2: true, bpp: 3}, [GL.DEPTH_COMPONENT32F]: {gl2: true, bpp: 4}, [GL.STENCIL_INDEX8]: {bpp: 1}, // 8 stencil bits. [GL.DEPTH_STENCIL]: {bpp: 4}, [GL.DEPTH24_STENCIL8]: {gl2: true, bpp: 4}, [GL.DEPTH32F_STENCIL8]: {gl2: true, bpp: 5}, // When using a WebGL 1 context, color renderbuffer formats are limited [GL.RGBA4]: {gl2: true, bpp: 2}, [GL.RGB565]: {gl2: true, bpp: 2}, [GL.RGB5_A1]: {gl2: true, bpp: 2}, // When using a WebGL 2 context, the following values are available additionally: [GL.R8]: {gl2: true, bpp: 1}, [GL.R8UI]: {gl2: true, bpp: 1}, [GL.R8I]: {gl2: true, bpp: 1}, [GL.R16UI]: {gl2: true, bpp: 2}, [GL.R16I]: {gl2: true, bpp: 2}, [GL.R32UI]: {gl2: true, bpp: 4}, [GL.R32I]: {gl2: true, bpp: 4}, [GL.RG8]: {gl2: true, bpp: 2}, [GL.RG8UI]: {gl2: true, bpp: 2}, [GL.RG8I]: {gl2: true, bpp: 2}, [GL.RG16UI]: {gl2: true, bpp: 4}, [GL.RG16I]: {gl2: true, bpp: 4}, [GL.RG32UI]: {gl2: true, bpp: 8}, [GL.RG32I]: {gl2: true, bpp: 8}, [GL.RGB8]: {gl2: true, bpp: 3}, [GL.RGBA8]: {gl2: true, bpp: 4}, // [GL.SRGB8_ALPHA8]: {gl2: true, gl1: SRGB}, // When using the EXT_sRGB WebGL1 extension [GL.RGB10_A2]: {gl2: true, bpp: 4}, [GL.RGBA8UI]: {gl2: true, bpp: 4}, [GL.RGBA8I]: {gl2: true, bpp: 4}, [GL.RGB10_A2UI]: {gl2: true, bpp: 4}, [GL.RGBA16UI]: {gl2: true, bpp: 8}, [GL.RGBA16I]: {gl2: true, bpp: 8}, [GL.RGBA32I]: {gl2: true, bpp: 16}, [GL.RGBA32UI]: {gl2: true, bpp: 16}, // When using a WebGL 2 context and the EXT_color_buffer_float WebGL2 extension [GL.R16F]: {ext: EXT_FLOAT_WEBGL2, bpp: 2}, [GL.RG16F]: {ext: EXT_FLOAT_WEBGL2, bpp: 4}, [GL.RGBA16F]: {ext: EXT_FLOAT_WEBGL2, bpp: 8}, [GL.R32F]: {ext: EXT_FLOAT_WEBGL2, bpp: 4}, [GL.RG32F]: {ext: EXT_FLOAT_WEBGL2, bpp: 8}, // TODO - can't get WEBGL_color_buffer_float to work on renderbuffers [GL.RGBA32F]: {ext: EXT_FLOAT_WEBGL2, bpp: 16}, // [GL.RGBA32F]: {ext: EXT_FLOAT_WEBGL2}, [GL.R11F_G11F_B10F]: {ext: EXT_FLOAT_WEBGL2, bpp: 4} }; */ /** @deprecated should be removed */ const DATA_FORMAT_CHANNELS = { [6403]: 1, [36244]: 1, [33319]: 2, [33320]: 2, [6407]: 3, [36248]: 3, [6408]: 4, [36249]: 4, [6402]: 1, [34041]: 1, [6406]: 1, [6409]: 1, [6410]: 2 }; /** @deprecated should be removed */ const TYPE_SIZES = { [5126]: 4, [5125]: 4, [5124]: 4, [5123]: 2, [5122]: 2, [5131]: 2, [5120]: 1, [5121]: 1 }; // FUNCTIONS /** Checks if a texture format is supported */ export function isTextureFormatSupported(gl, format, extensions) { const info = TEXTURE_FORMATS[format]; if (!info) { return false; } // Check that we have a GL constant if (info.gl === undefined) { return false; } // Check extensions const extension = info.x || info.gl2ext; if (extension) { return Boolean(getWebGLExtension(gl, extension, extensions)); } return true; } export function isRenderbufferFormatSupported(gl, format, extensions) { // Note: Order is important since the function call initializes extensions. return isTextureFormatSupported(gl, format, extensions) && TEXTURE_FORMATS[format]?.rb; } /** * Map WebGL texture formats (GL constants) to WebGPU-style TextureFormat strings */ export function convertGLToTextureFormat(format) { if (typeof format === 'string') { return format; } const entry = Object.entries(TEXTURE_FORMATS).find(([, entry]) => entry.gl === format); if (!entry) { throw new Error(`Unknown texture format ${format}`); } return entry[0]; } /** * Map WebGPU style texture format strings to GL constants */ export function convertTextureFormatToGL(format) { const formatInfo = TEXTURE_FORMATS[format]; const webglFormat = formatInfo?.gl; if (webglFormat === undefined) { throw new Error(`Unsupported texture format ${format}`); } return webglFormat; } /** Checks if a texture format is supported */ export function getTextureFormatSupport(gl, format, extensions) { const info = TEXTURE_FORMATS[format]; if (!info) { return { supported: false }; } // let decoded; // try { // decoded = decodeTextureFormat(format); // } catch {} // Support Check that we have a GL constant let supported = info.gl === undefined; supported = supported && checkTextureFeature(gl, info.f, extensions); // Filtering // const filterable = info.filter // ? checkTextureFeature(gl, infofilter]) // : decoded && !decoded.signed; // const renderable = info.filter // ? checkTextureFeature(gl, inforender]) // : decoded && !decoded.signed; return { supported, renderable: supported && checkTextureFeature(gl, info.render, extensions), filterable: supported && checkTextureFeature(gl, info.filter, extensions), blendable: false, // tod, storable: false }; } /** Checks whether linear filtering (interpolated sampling) is available for floating point textures */ export function isTextureFormatFilterable(gl, format, extensions) { if (!isTextureFormatSupported(gl, format, extensions)) { return false; } if (format.startsWith('depth') || format.startsWith('stencil')) { return false; } try { const decoded = decodeTextureFormat(format); if (decoded.signed) { return false; } } catch { return false; } if (format.endsWith('32float')) { return Boolean(getWebGLExtension(gl, 'OES_texture_float_linear, extensions', extensions)); } if (format.endsWith('16float')) { return Boolean(getWebGLExtension(gl, 'OES_texture_half_float_linear, extensions', extensions)); } return true; } export function isTextureFormatRenderable(gl, format, extensions) { if (!isTextureFormatSupported(gl, format, extensions)) { return false; } if (typeof format === 'number') { return false; // isTextureFormatFilterableWebGL(gl, format); } // TODO depends on device... return true; } /** Get parameters necessary to work with format in WebGL: internalFormat, dataFormat, type, compressed, */ export function getWebGLTextureParameters(format) { const formatData = TEXTURE_FORMATS[format]; const webglFormat = convertTextureFormatToGL(format); const decoded = decodeTextureFormat(format); return { format: webglFormat, dataFormat: formatData?.dataFormat || getWebGLPixelDataFormat(decoded.format, decoded.integer, decoded.normalized, webglFormat), // depth formats don't have a type type: decoded.dataType ? getGLFromVertexType(decoded.dataType) : formatData?.types?.[0] || 5121, // @ts-expect-error compressed: decoded.compressed }; } export function getDepthStencilAttachmentWebGL(format) { const info = TEXTURE_FORMATS[format]; if (!info?.attachment) { throw new Error(`${format} is not a depth stencil format`); } return info.attachment; } /** TODO - VERY roundabout legacy way of calculating bytes per pixel */ export function getTextureFormatBytesPerPixel(format) { // TODO remove webgl1 support const params = getWebGLTextureParameters(format); // NOTE(Tarek): Default to RGBA bytes const channels = DATA_FORMAT_CHANNELS[params.dataFormat] || 4; const channelSize = TYPE_SIZES[params.type] || 1; return channels * channelSize; } // DATA TYPE HELPERS function getWebGLPixelDataFormat(dataFormat, integer, normalized, format) { // WebGL1 formats use same internalFormat if (format === 6408 || format === 6407) { return format; } // prettier-ignore switch (dataFormat) { case 'r': return integer && !normalized ? 36244 : 6403; case 'rg': return integer && !normalized ? 33320 : 33319; case 'rgb': return integer && !normalized ? 36248 : 6407; case 'rgba': return integer && !normalized ? 36249 : 6408; default: return 6408; } }