Skip to content

Commit

Permalink
chore(webgl): Consolidate WebGL extension handling (#1964)
Browse files Browse the repository at this point in the history
  • Loading branch information
ibgreen committed Feb 25, 2024
1 parent 17b32bd commit d385f3e
Show file tree
Hide file tree
Showing 21 changed files with 370 additions and 393 deletions.
27 changes: 24 additions & 3 deletions modules/constants/src/webgl-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,37 +345,59 @@ export type GLParameters = GLValueParameters & GLFunctionParameters;

/** WebGL2 Extensions */
export type GLExtensions = {
/** https://registry.khronos.org/webgl/extensions/EXT_color_buffer_float */
EXT_color_buffer_float?: EXT_color_buffer_float | null;
/** https://registry.khronos.org/webgl/extensions/EXT_color_buffer_half_float */
EXT_color_buffer_half_float?: EXT_color_buffer_half_float | null;
/** https://registry.khronos.org/webgl/extensions/EXT_texture_compression_bptc */
EXT_texture_compression_bptc?: EXT_texture_compression_bptc | null;
/** https://registry.khronos.org/webgl/extensions/EXT_texture_compression_rgtc */
EXT_texture_compression_rgtc?: EXT_texture_compression_rgtc | null;
/** https://registry.khronos.org/webgl/extensions/EXT_texture_filter_anisotropic */
EXT_texture_filter_anisotropic?: EXT_texture_filter_anisotropic | null;
/** https://registry.khronos.org/webgl/extensions/KHR_parallel_shader_compile */
KHR_parallel_shader_compile?: KHR_parallel_shader_compile | null;
/** https://registry.khronos.org/webgl/extensions/OES_fbo_render_mipmap */
OES_fbo_render_mipmap?: OES_fbo_render_mipmap | null;
/** https://registry.khronos.org/webgl/extensions/OES_texture_float */
OES_texture_float?: OES_texture_float | null;
/** https://registry.khronos.org/webgl/extensions/OES_texture_float_linear */
OES_texture_float_linear?: OES_texture_float_linear | null;
/** https://registry.khronos.org/webgl/extensions/OES_texture_half_float */
OES_texture_half_float?: OES_texture_half_float | null;
/** https://registry.khronos.org/webgl/extensions/OES_texture_half_float_linear */
OES_texture_half_float_linear?: OES_texture_half_float_linear | null;
/** https://registry.khronos.org/webgl/extensions/OES_vertex_array_object */
OES_vertex_array_object?: OES_vertex_array_object | null;
/** https://registry.khronos.org/webgl/extensions/EXT_float_blend */
EXT_float_blend?: EXT_float_blend | null;
/** https://registry.khronos.org/webgl/extensions/OVR_multiview2 */
OVR_multiview2?: OVR_multiview2 | null;
/** https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_astc */
WEBGL_compressed_texture_astc?: WEBGL_compressed_texture_astc | null;
/** https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_etc */
WEBGL_compressed_texture_etc?: WEBGL_compressed_texture_etc | null;
/** https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_etc1 */
WEBGL_compressed_texture_etc1?: WEBGL_compressed_texture_etc1 | null;
/** https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_pvrtc */
WEBGL_compressed_texture_pvrtc?: WEBGL_compressed_texture_pvrtc | null;
/** https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_s3tc */
WEBGL_compressed_texture_s3tc?: WEBGL_compressed_texture_s3tc | null;
/** https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_s3tc_srgb */
WEBGL_compressed_texture_s3tc_srgb?: WEBGL_compressed_texture_s3tc_srgb | null;
/** https://registry.khronos.org/webgl/extensions/WEBGL_debug_renderer_info */
WEBGL_debug_renderer_info?: WEBGL_debug_renderer_info | null;
/** https://registry.khronos.org/webgl/extensions/WEBGL_debug_shaders */
WEBGL_debug_shaders?: WEBGL_debug_shaders | null;
/** https://registry.khronos.org/webgl/extensions/WEBGL_lose_context */
WEBGL_lose_context?: WEBGL_lose_context | null;

// Predefined typescript types not available for the following extensions

/** https://registry.khronos.org/webgl/extensions/EXT_depth_clamp/ */
EXT_depth_clamp?: EXT_depth_clamp | null;

/** https://registry.khronos.org/webgl/extensions/WEBGL_provoking_vertex/ */
WEBGL_provoking_vertex?: WEBGL_provoking_vertex | null;

/** https://registry.khronos.org/webgl/extensions/WEBGL_polygon_mode/ */
WEBGL_polygon_mode?: WEBGL_polygon_mode | null;

Expand Down Expand Up @@ -404,7 +426,6 @@ export type GLExtensions = {

// ANGLE_instanced_arrays?: ANGLE_instanced_arrays | null;
// EXT_blend_minmax?: EXT_blend_minmax | null;
// EXT_float_blend?: EXT_float_blend | null;
// EXT_frag_depth?: EXT_frag_depth | null;
// EXT_sRGB?: EXT_sRGB | null;
// EXT_shader_texture_lod?: EXT_shader_texture_lod | null;
Expand Down
88 changes: 55 additions & 33 deletions modules/core/src/adapter/device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,36 +20,6 @@ import type {CommandEncoder, CommandEncoderProps} from './resources/command-enco
import type {VertexArray, VertexArrayProps} from './resources/vertex-array';
import type {TransformFeedback, TransformFeedbackProps} from './resources/transform-feedback';

/** Device properties */
export type DeviceProps = {
id?: string;

type?: 'webgl' | 'webgpu' | 'best-available';

// Common parameters
canvas?: HTMLCanvasElement | OffscreenCanvas | string | null; // A canvas element or a canvas string id
container?: HTMLElement | string | null;
width?: number /** width is only used when creating a new canvas */;
height?: number /** height is only used when creating a new canvas */;

// WebGLContext PARAMETERS - Can only be set on context creation...
// alpha?: boolean; // Default render target has an alpha buffer.
// depth?: boolean; // Default render target has a depth buffer of at least 16 bits.
// stencil?: boolean; // Default render target has a stencil buffer of at least 8 bits.
// antialias?: boolean; // Boolean that indicates whether or not to perform anti-aliasing.
// premultipliedAlpha?: boolean; // Boolean that indicates that the page compositor will assume the drawing buffer contains colors with pre-multiplied alpha.
// preserveDrawingBuffer?: boolean; // Default render target buffers will not be automatically cleared and will preserve their values until cleared or overwritten
// failIfMajorPerformanceCaveat?: boolean; // Do not create if the system performance is low.

// Unclear if these are still supported
debug?: boolean; // Instrument context (at the expense of performance)
manageState?: boolean; // Set to false to disable WebGL state management instrumentation
break?: string[]; // TODO: types

// @deprecated Attach to existing context
gl?: WebGL2RenderingContext | null;
};

/**
* Identifies the GPU vendor and driver.
* @note Chrome WebGPU does not provide much information, though more can be enabled with
Expand Down Expand Up @@ -125,7 +95,7 @@ export type WebGPUDeviceFeature =
| 'texture-compression-etc2'
| 'texture-compression-astc';

// Removed WebGPU features...
// WebGPU features that have been removed from the WebGPU spec...
// 'depth-clamping' |
// 'pipeline-statistics-query' |

Expand Down Expand Up @@ -170,6 +140,57 @@ export type DeviceFeature =
| WebGLDeviceFeature
| WebGLCompressedTextureFeatures;

/** Set-like class for features (lets apps check for WebGL / WebGPU extensions) */
export class DeviceFeatures {
protected features: Set<DeviceFeature>;

constructor(features: DeviceFeature[] = []) {
this.features = new Set<DeviceFeature>(features);
}

*[Symbol.iterator](): IterableIterator<DeviceFeature> {
yield* this.features;
}

has(feature: DeviceFeature): boolean {
return this.features.has(feature);
}
}

/** Device properties */
export type DeviceProps = {
id?: string;

type?: 'webgl' | 'webgpu' | 'best-available';

// Common parameters
canvas?: HTMLCanvasElement | OffscreenCanvas | string | null; // A canvas element or a canvas string id
container?: HTMLElement | string | null;
width?: number /** width is only used when creating a new canvas */;
height?: number /** height is only used when creating a new canvas */;

// WebGLContext PARAMETERS - Can only be set on context creation...
// alpha?: boolean; // Default render target has an alpha buffer.
// depth?: boolean; // Default render target has a depth buffer of at least 16 bits.
// stencil?: boolean; // Default render target has a stencil buffer of at least 8 bits.
// antialias?: boolean; // Boolean that indicates whether or not to perform anti-aliasing.
// premultipliedAlpha?: boolean; // Boolean that indicates that the page compositor will assume the drawing buffer contains colors with pre-multiplied alpha.
// preserveDrawingBuffer?: boolean; // Default render target buffers will not be automatically cleared and will preserve their values until cleared or overwritten
// failIfMajorPerformanceCaveat?: boolean; // Do not create if the system performance is low.

/** Instrument context (at the expense of performance) */
debug?: boolean;
/** Initialize the SpectorJS WebGL debugger */
spector?: boolean;

// Unclear if these are still supported
manageState?: boolean; // Set to false to disable WebGL state management instrumentation
break?: string[]; // TODO: types

// @deprecated Attach to existing context
gl?: WebGL2RenderingContext | null;
};

/**
* WebGPU Device/WebGL context abstraction
*/
Expand All @@ -182,7 +203,8 @@ export abstract class Device {
manageState: true,
width: 800, // width are height are only used by headless gl
height: 600,
debug: Boolean(log.get('debug')), // Instrument context (at the expense of performance)
debug: false, // Instrument context (at the expense of performance)
spector: false, // Initialize the SpectorJS WebGL debugger
break: [],

// alpha: undefined,
Expand Down Expand Up @@ -226,7 +248,7 @@ export abstract class Device {
abstract info: DeviceInfo;

/** Optional capability discovery */
abstract get features(): Set<DeviceFeature>;
abstract features: DeviceFeatures;

/** WebGPU style device limits */
abstract get limits(): DeviceLimits;
Expand Down
2 changes: 1 addition & 1 deletion modules/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export {isTypedArray, isNumberArray} from './utils/is-array';
export {luma} from './lib/luma';

export type {DeviceProps, DeviceLimits, DeviceInfo, DeviceFeature} from './adapter/device';
export {Device} from './adapter/device';
export {Device, DeviceFeatures} from './adapter/device';
export type {CanvasContextProps} from './adapter/canvas-context';
export {CanvasContext} from './adapter/canvas-context';

Expand Down
2 changes: 1 addition & 1 deletion modules/engine/src/model/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,7 @@ export function getPlatformInfo(device: Device): PlatformInfo {
shaderLanguage: device.info.shadingLanguage,
shaderLanguageVersion: device.info.shadingLanguageVersion as 100 | 300,
gpu: device.info.gpu,
features: device.features
features: new Set(device.features)
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function getInfo(device: Device): PlatformInfo {
gpu: device.info.gpu,
shaderLanguage: device.info.shadingLanguage,
shaderLanguageVersion: device.info.shadingLanguageVersion as 100 | 300,
features: device.features
features: new Set(device.features)
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function getInfo(device: Device): PlatformInfo {
gpu: device.info.gpu,
shaderLanguage: device.info.shadingLanguage,
shaderLanguageVersion: device.info.shadingLanguageVersion as 100 | 300,
features: device.features
features: new Set(device.features)
};
}

Expand Down
72 changes: 43 additions & 29 deletions modules/webgl/src/adapter/converters/texture-formats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

import type {TextureFormat, DeviceFeature} from '@luma.gl/core';
import {decodeTextureFormat} from '@luma.gl/core';
import {GL} from '@luma.gl/constants';
import {GL, GLExtensions} from '@luma.gl/constants';
import {getWebGLExtension} from '../../context/helpers/webgl-extensions';
import {getGLFromVertexType} from './vertex-formats';

/* eslint-disable camelcase */
Expand Down Expand Up @@ -38,7 +39,7 @@ const EXT_color_buffer_float = 'EXT_color_buffer_float';
// const EXT_HALF_FLOAT_WEBGL1 = 'EXT_color_buffer_half_float';

// prettier-ignore
const TEXTURE_FEATURE_CHECKS: Partial<Record<DeviceFeature, string[]>> = {
export const TEXTURE_FEATURES: Partial<Record<DeviceFeature, string[]>> = {
'float32-renderable-webgl': ['EXT_color_buffer_float'], // [false, 'EXT_color_buffer_float'],
'float16-renderable-webgl': ['EXT_color_buffer_half_float'],
'norm16-renderable-webgl': [EXT_texture_norm16],
Expand All @@ -61,19 +62,27 @@ const TEXTURE_FEATURE_CHECKS: Partial<Record<DeviceFeature, string[]>> = {
'texture-compression-atc-webgl': [X_ATC]
};

function checkTextureFeature(gl: WebGL2RenderingContext, feature: DeviceFeature): boolean {
const extensions = TEXTURE_FEATURE_CHECKS[feature] || [];
return extensions.every(extension => gl.getExtension(extension));
}

function checkTextureFeatures(gl: WebGL2RenderingContext, features: DeviceFeature[]): boolean {
return features.every(feature => checkTextureFeature(gl, feature));
/** 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: DeviceFeature): boolean {
return feature in TEXTURE_FEATURES;
}

/** Return a list of texture feature strings (for Device.features). Mainly compressed texture support */
export function getTextureFeatures(gl: WebGL2RenderingContext): DeviceFeature[] {
const textureFeatures = Object.keys(TEXTURE_FEATURE_CHECKS) as DeviceFeature[];
return textureFeatures.filter(feature => checkTextureFeature(gl, feature));
/** Checks a texture feature (for Device.features). Mainly compressed texture support */
export function checkTextureFeature(
gl: WebGL2RenderingContext,
feature: DeviceFeature,
extensions: GLExtensions
): boolean {
const textureExtensions = TEXTURE_FEATURES[feature] || [];
return textureExtensions.every(extension => getWebGLExtension(gl, extension, extensions));
}

// TEXTURE FORMATS
Expand Down Expand Up @@ -435,7 +444,8 @@ const TYPE_SIZES = {
/** Checks if a texture format is supported */
export function isTextureFormatSupported(
gl: WebGL2RenderingContext,
formatOrGL: TextureFormat | GL
formatOrGL: TextureFormat | GL,
extensions: GLExtensions
): boolean {
const format = convertGLToTextureFormat(formatOrGL);
const info = TEXTURE_FORMATS[format];
Expand All @@ -449,17 +459,18 @@ export function isTextureFormatSupported(
// Check extensions
const extension = info.x || info.gl2ext;
if (extension) {
return Boolean(gl.getExtension(extension));
return Boolean(getWebGLExtension(gl, extension, extensions));
}
return true;
}

export function isRenderbufferFormatSupported(
gl: WebGL2RenderingContext,
format: TextureFormat
format: TextureFormat,
extensions: GLExtensions
): boolean {
// Note: Order is important since the function call initializes extensions.
return isTextureFormatSupported(gl, format) && TEXTURE_FORMATS[format]?.renderbuffer;
return isTextureFormatSupported(gl, format, extensions) && TEXTURE_FORMATS[format]?.renderbuffer;
}

/**
Expand Down Expand Up @@ -491,7 +502,8 @@ export function convertTextureFormatToGL(format: TextureFormat): GL | undefined
/** Checks if a texture format is supported */
export function getTextureFormatSupport(
gl: WebGL2RenderingContext,
formatOrGL: TextureFormat | GL
formatOrGL: TextureFormat | GL,
extensions: GLExtensions
): {
supported: boolean;
filterable?: boolean;
Expand All @@ -511,20 +523,20 @@ export function getTextureFormatSupport(

// Support Check that we have a GL constant
let supported = info.gl === undefined;
supported = supported && checkTextureFeatures(gl, [info.f]);
supported = supported && checkTextureFeature(gl, info.f, extensions);

// Filtering
// const filterable = info.filter
// ? checkTextureFeatures(gl, [info.filter])
// ? checkTextureFeature(gl, infofilter])
// : decoded && !decoded.signed;
// const renderable = info.filter
// ? checkTextureFeatures(gl, [info.render])
// ? checkTextureFeature(gl, inforender])
// : decoded && !decoded.signed;

return {
supported,
renderable: supported && checkTextureFeatures(gl, [info.render]),
filterable: supported && checkTextureFeatures(gl, [info.filter]),
renderable: supported && checkTextureFeature(gl, info.render, extensions),
filterable: supported && checkTextureFeature(gl, info.filter, extensions),
blendable: false, // tod,
storable: false
};
Expand All @@ -533,10 +545,11 @@ export function getTextureFormatSupport(
/** Checks whether linear filtering (interpolated sampling) is available for floating point textures */
export function isTextureFormatFilterable(
gl: WebGL2RenderingContext,
formatOrGL: TextureFormat | GL
formatOrGL: TextureFormat | GL,
extensions: GLExtensions
): boolean {
const format = convertGLToTextureFormat(formatOrGL);
if (!isTextureFormatSupported(gl, format)) {
if (!isTextureFormatSupported(gl, format, extensions)) {
return false;
}
try {
Expand All @@ -548,20 +561,21 @@ export function isTextureFormatFilterable(
return false;
}
if (format.endsWith('32float')) {
return Boolean(gl.getExtension('OES_texture_float_linear'));
return Boolean(getWebGLExtension(gl, 'OES_texture_float_linear, extensions', extensions));
}
if (format.endsWith('16float')) {
return Boolean(gl.getExtension('OES_texture_half_float_linear'));
return Boolean(getWebGLExtension(gl, 'OES_texture_half_float_linear, extensions', extensions));
}
return true;
}

export function isTextureFormatRenderable(
gl: WebGL2RenderingContext,
formatOrGL: TextureFormat | GL
formatOrGL: TextureFormat | GL,
extensions: GLExtensions
): boolean {
const format = convertGLToTextureFormat(formatOrGL);
if (!isTextureFormatSupported(gl, format)) {
if (!isTextureFormatSupported(gl, format, extensions)) {
return false;
}
if (typeof format === 'number') {
Expand Down
Loading

0 comments on commit d385f3e

Please sign in to comment.