From 2fc095ea1f18e4017f4002c350faa55da894a78c Mon Sep 17 00:00:00 2001 From: Ib Green Date: Sun, 28 Apr 2024 22:25:12 -0400 Subject: [PATCH 1/4] chore(core): Clean up WebGLStateTracker --- .../adapter/converters/device-parameters.ts | 2 +- .../adapter/resources/webgl-render-pass.ts | 2 +- modules/webgl/src/adapter/webgl-device.ts | 3 +- ...ontext-state.ts => webgl-state-tracker.ts} | 41 ++++++++++--------- .../context/state-tracker/with-parameters.ts | 2 +- modules/webgl/src/index.ts | 3 +- ...te.spec.ts => webgl-state-tracker.spec.ts} | 0 modules/webgl/test/index.ts | 2 +- 8 files changed, 29 insertions(+), 26 deletions(-) rename modules/webgl/src/context/state-tracker/{track-context-state.ts => webgl-state-tracker.ts} (91%) rename modules/webgl/test/context/state-tracker/{track-context-state.spec.ts => webgl-state-tracker.spec.ts} (100%) diff --git a/modules/webgl/src/adapter/converters/device-parameters.ts b/modules/webgl/src/adapter/converters/device-parameters.ts index d95307e5e9..86de192244 100644 --- a/modules/webgl/src/adapter/converters/device-parameters.ts +++ b/modules/webgl/src/adapter/converters/device-parameters.ts @@ -14,7 +14,7 @@ import type { GLProvokingVertex, GLStencilOp } from '@luma.gl/constants'; -import {pushContextState, popContextState} from '../../context/state-tracker/track-context-state'; +import {pushContextState, popContextState} from '../../context/state-tracker/webgl-state-tracker'; import {setGLParameters} from '../../context/parameters/unified-parameter-api'; import {WebGLDevice} from '../webgl-device'; diff --git a/modules/webgl/src/adapter/resources/webgl-render-pass.ts b/modules/webgl/src/adapter/resources/webgl-render-pass.ts index aaaa817b2b..e3768af478 100644 --- a/modules/webgl/src/adapter/resources/webgl-render-pass.ts +++ b/modules/webgl/src/adapter/resources/webgl-render-pass.ts @@ -8,7 +8,7 @@ import {WebGLDevice} from '../webgl-device'; import {GL, GLParameters} from '@luma.gl/constants'; import {withGLParameters} from '../../context/state-tracker/with-parameters'; import {setGLParameters} from '../../context/parameters/unified-parameter-api'; -import {pushContextState, popContextState} from '../../context/state-tracker/track-context-state'; +import {pushContextState, popContextState} from '../../context/state-tracker/webgl-state-tracker'; import {WEBGLQuerySet} from './webgl-query-set'; // Should collapse during minification diff --git a/modules/webgl/src/adapter/webgl-device.ts b/modules/webgl/src/adapter/webgl-device.ts index 49d755a635..a75ef9dbbb 100644 --- a/modules/webgl/src/adapter/webgl-device.ts +++ b/modules/webgl/src/adapter/webgl-device.ts @@ -8,10 +8,11 @@ import type {Buffer, Texture, Framebuffer, VertexArray, VertexArrayProps} from ' import {Device, CanvasContext, log} from '@luma.gl/core'; import type {GLExtensions} from '@luma.gl/constants'; import { + WebGLStateTracker, popContextState, pushContextState, trackContextState -} from '../context/state-tracker/track-context-state'; +} from '../context/state-tracker/webgl-state-tracker'; import {createBrowserContext} from '../context/helpers/create-browser-context'; import {getDeviceInfo} from './device-helpers/webgl-device-info'; import {WebGLDeviceFeatures} from './device-helpers/webgl-device-features'; diff --git a/modules/webgl/src/context/state-tracker/track-context-state.ts b/modules/webgl/src/context/state-tracker/webgl-state-tracker.ts similarity index 91% rename from modules/webgl/src/context/state-tracker/track-context-state.ts rename to modules/webgl/src/context/state-tracker/webgl-state-tracker.ts index 261eb760e1..dffb8c99dd 100644 --- a/modules/webgl/src/context/state-tracker/track-context-state.ts +++ b/modules/webgl/src/context/state-tracker/webgl-state-tracker.ts @@ -2,20 +2,26 @@ // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors -// Support for listening to context state changes and intercepting state queries -// NOTE: this system does not handle buffer bindings +import {setGLParameters, getGLParameters} from '../parameters/unified-parameter-api'; +import {deepArrayEqual} from './deep-array-equal'; import { GL_PARAMETER_DEFAULTS, GL_HOOKED_SETTERS, NON_CACHE_PARAMETERS } from '../parameters/webgl-parameter-tables'; -import {setGLParameters, getGLParameters} from '../parameters/unified-parameter-api'; -import {deepArrayEqual} from './deep-array-equal'; -// HELPER CLASS - GLState +// HELPER CLASS - WebGLStateTracker + +/** + * Support for listening to context state changes and intercepting state queries + * NOTE: this system does not handle buffer bindings + */ +export class WebGLStateTracker { + static get(gl: WebGL2RenderingContext): WebGLStateTracker { + // @ts-expect-error + return gl.state as WebGLStateTracker; + } -/* eslint-disable no-shadow */ -class GLState { gl: WebGL2RenderingContext; program: unknown = null; stateStack: object[] = []; @@ -89,11 +95,6 @@ class GLState { } } -function getContextState(gl: WebGL2RenderingContext): GLState { - // @ts-expect-error - return gl.state as GLState; -} - // PUBLIC API /** @@ -124,7 +125,7 @@ export function trackContextState( // Create a state cache // @ts-expect-error - gl.state = new GLState(gl, {copyState}); + gl.state = new WebGLStateTracker(gl, {copyState}); installProgramSpy(gl); @@ -139,7 +140,7 @@ export function trackContextState( installGetterOverride(gl, 'isEnabled'); } - const glState = getContextState(gl); + const glState = WebGLStateTracker.get(gl); glState.enable = enable; return gl; @@ -149,10 +150,10 @@ export function trackContextState( * Saves current WebGL context state onto an internal per-context stack */ export function pushContextState(gl: WebGL2RenderingContext): void { - let glState = getContextState(gl); + let glState = WebGLStateTracker.get(gl); if (!glState) { trackContextState(gl, {copyState: false}); - glState = getContextState(gl); + glState = WebGLStateTracker.get(gl); } glState.push(); } @@ -161,7 +162,7 @@ export function pushContextState(gl: WebGL2RenderingContext): void { * Restores previously saved WebGL context state */ export function popContextState(gl: WebGL2RenderingContext): void { - const glState = getContextState(gl); + const glState = WebGLStateTracker.get(gl); // assert(glState); glState.pop(); } @@ -185,7 +186,7 @@ function installGetterOverride(gl: WebGL2RenderingContext, functionName: string) return originalGetterFunc(pname); } - const glState = getContextState(gl); + const glState = WebGLStateTracker.get(gl); if (!(pname in glState.cache)) { // WebGL limits are not prepopulated in the cache, call the original getter when first queried. glState.cache[pname] = originalGetterFunc(pname); @@ -229,7 +230,7 @@ function installSetterSpy(gl: WebGL2RenderingContext, functionName: string, sett gl[functionName] = function set(...params) { // Update the value // Call the setter with the state cache and the params so that it can store the parameters - const glState = getContextState(gl); + const glState = WebGLStateTracker.get(gl); // eslint-disable-next-line @typescript-eslint/unbound-method const {valueChanged, oldValue} = setter(glState._updateCache, ...params); @@ -257,7 +258,7 @@ function installProgramSpy(gl: WebGL2RenderingContext): void { const originalUseProgram = gl.useProgram.bind(gl); gl.useProgram = function useProgramLuma(handle) { - const glState = getContextState(gl); + const glState = WebGLStateTracker.get(gl); if (glState.program !== handle) { originalUseProgram(handle); glState.program = handle; diff --git a/modules/webgl/src/context/state-tracker/with-parameters.ts b/modules/webgl/src/context/state-tracker/with-parameters.ts index 96cc426317..2eeea60fbb 100644 --- a/modules/webgl/src/context/state-tracker/with-parameters.ts +++ b/modules/webgl/src/context/state-tracker/with-parameters.ts @@ -3,7 +3,7 @@ // Copyright (c) vis.gl contributors import {GLParameters, setGLParameters} from '../parameters/unified-parameter-api'; -import {pushContextState, popContextState} from './track-context-state'; +import {pushContextState, popContextState} from './webgl-state-tracker'; /** * Execute a function with a set of temporary WebGL parameter overrides diff --git a/modules/webgl/src/index.ts b/modules/webgl/src/index.ts index d9f452f02f..048018fded 100644 --- a/modules/webgl/src/index.ts +++ b/modules/webgl/src/index.ts @@ -50,10 +50,11 @@ export {TEXTURE_FORMATS as _TEXTURE_FORMATS} from './adapter/converters/texture- // DEPRECATED TEST EXPORTS // State tracking export { + WebGLStateTracker, trackContextState, pushContextState, popContextState -} from './context/state-tracker/track-context-state'; +} from './context/state-tracker/webgl-state-tracker'; export { resetGLParameters, diff --git a/modules/webgl/test/context/state-tracker/track-context-state.spec.ts b/modules/webgl/test/context/state-tracker/webgl-state-tracker.spec.ts similarity index 100% rename from modules/webgl/test/context/state-tracker/track-context-state.spec.ts rename to modules/webgl/test/context/state-tracker/webgl-state-tracker.spec.ts diff --git a/modules/webgl/test/index.ts b/modules/webgl/test/index.ts index a601b17895..56bb8aa485 100644 --- a/modules/webgl/test/index.ts +++ b/modules/webgl/test/index.ts @@ -18,7 +18,7 @@ import './adapter/helpers/webgl-topology-utils.spec'; // state-tracker import './context/state-tracker/deep-array-equal.spec'; import './context/state-tracker/set-parameters.spec'; -import './context/state-tracker/track-context-state.spec'; +import './context/state-tracker/webgl-state-tracker.spec'; import './context/state-tracker/context-state.spec'; // ADAPTER From bae12d72d2ae4af1fe0cd6532a41830522e843a4 Mon Sep 17 00:00:00 2001 From: Ib Green Date: Sun, 28 Apr 2024 22:37:55 -0400 Subject: [PATCH 2/4] simplify --- .../adapter/converters/device-parameters.ts | 18 +++++----- .../adapter/resources/webgl-render-pass.ts | 5 ++- modules/webgl/src/adapter/webgl-device.ts | 13 +++---- .../state-tracker/webgl-state-tracker.ts | 21 ------------ .../context/state-tracker/with-parameters.ts | 9 ++--- modules/webgl/src/index.ts | 7 +--- .../state-tracker/webgl-state-tracker.spec.ts | 34 +++++++++---------- 7 files changed, 37 insertions(+), 70 deletions(-) diff --git a/modules/webgl/src/adapter/converters/device-parameters.ts b/modules/webgl/src/adapter/converters/device-parameters.ts index 86de192244..ffc2519a17 100644 --- a/modules/webgl/src/adapter/converters/device-parameters.ts +++ b/modules/webgl/src/adapter/converters/device-parameters.ts @@ -14,7 +14,6 @@ import type { GLProvokingVertex, GLStencilOp } from '@luma.gl/constants'; -import {pushContextState, popContextState} from '../../context/state-tracker/webgl-state-tracker'; import {setGLParameters} from '../../context/parameters/unified-parameter-api'; import {WebGLDevice} from '../webgl-device'; @@ -41,13 +40,13 @@ export function withDeviceAndGLParameters( // Wrap in a try-catch to ensure that parameters are restored on exceptions const webglDevice = device as WebGLDevice; - pushContextState(webglDevice.gl); + webglDevice.pushState(); try { setDeviceParameters(device, parameters); setGLParameters(webglDevice.gl, glParameters); return func(device); } finally { - popContextState(webglDevice.gl); + webglDevice.popState(); } } @@ -72,12 +71,12 @@ export function withGLParameters( // Wrap in a try-catch to ensure that parameters are restored on exceptions const webglDevice = device as WebGLDevice; - pushContextState(webglDevice.gl); + webglDevice.pushState(); try { setGLParameters(webglDevice.gl, parameters); return func(device); } finally { - popContextState(webglDevice.gl); + webglDevice.popState(); } } @@ -99,15 +98,14 @@ export function withDeviceParameters( return func(device); } - // Wrap in a try-catch to ensure that parameters are restored on exceptions - // @ts-expect-error - pushContextState(device.gl); + // Wrap in a try-catch to ensure that parameters are restored on exceptions' + const webglDevice = device as WebGLDevice; + webglDevice.pushState(); try { setDeviceParameters(device, parameters); return func(device); } finally { - // @ts-expect-error - popContextState(device.gl); + webglDevice.popState(); } } diff --git a/modules/webgl/src/adapter/resources/webgl-render-pass.ts b/modules/webgl/src/adapter/resources/webgl-render-pass.ts index e3768af478..33216ba3ac 100644 --- a/modules/webgl/src/adapter/resources/webgl-render-pass.ts +++ b/modules/webgl/src/adapter/resources/webgl-render-pass.ts @@ -8,7 +8,6 @@ import {WebGLDevice} from '../webgl-device'; import {GL, GLParameters} from '@luma.gl/constants'; import {withGLParameters} from '../../context/state-tracker/with-parameters'; import {setGLParameters} from '../../context/parameters/unified-parameter-api'; -import {pushContextState, popContextState} from '../../context/state-tracker/webgl-state-tracker'; import {WEBGLQuerySet} from './webgl-query-set'; // Should collapse during minification @@ -30,7 +29,7 @@ export class WEBGLRenderPass extends RenderPass { this.device = device; // TODO - do parameters (scissorRect) affect the clear operation? - pushContextState(this.device.gl); + this.device.pushState(); this.setParameters(this.props.parameters); // Hack - for now WebGL draws in "immediate mode" (instead of queueing the operations)... @@ -38,7 +37,7 @@ export class WEBGLRenderPass extends RenderPass { } end(): void { - popContextState(this.device.gl); + this.device.popState(); // should add commands to CommandEncoder. } diff --git a/modules/webgl/src/adapter/webgl-device.ts b/modules/webgl/src/adapter/webgl-device.ts index a75ef9dbbb..9a68b39906 100644 --- a/modules/webgl/src/adapter/webgl-device.ts +++ b/modules/webgl/src/adapter/webgl-device.ts @@ -7,12 +7,7 @@ import type {DeviceProps, DeviceInfo, CanvasContextProps, TextureFormat} from '@ import type {Buffer, Texture, Framebuffer, VertexArray, VertexArrayProps} from '@luma.gl/core'; import {Device, CanvasContext, log} from '@luma.gl/core'; import type {GLExtensions} from '@luma.gl/constants'; -import { - WebGLStateTracker, - popContextState, - pushContextState, - trackContextState -} from '../context/state-tracker/webgl-state-tracker'; +import {WebGLStateTracker, trackContextState} from '../context/state-tracker/webgl-state-tracker'; import {createBrowserContext} from '../context/helpers/create-browser-context'; import {getDeviceInfo} from './device-helpers/webgl-device-info'; import {WebGLDeviceFeatures} from './device-helpers/webgl-device-features'; @@ -462,12 +457,14 @@ ${device.info.vendor}, ${device.info.renderer} for canvas: ${device.canvasContex /** Save current WebGL context state onto an internal stack */ pushState(): void { - pushContextState(this.gl); + const webglState = WebGLStateTracker.get(this.gl); + webglState.push(); } /** Restores previously saved context state */ popState(): void { - popContextState(this.gl); + const webglState = WebGLStateTracker.get(this.gl); + webglState.pop(); } /** diff --git a/modules/webgl/src/context/state-tracker/webgl-state-tracker.ts b/modules/webgl/src/context/state-tracker/webgl-state-tracker.ts index dffb8c99dd..d5e6ce7bb3 100644 --- a/modules/webgl/src/context/state-tracker/webgl-state-tracker.ts +++ b/modules/webgl/src/context/state-tracker/webgl-state-tracker.ts @@ -146,27 +146,6 @@ export function trackContextState( return gl; } -/** - * Saves current WebGL context state onto an internal per-context stack - */ -export function pushContextState(gl: WebGL2RenderingContext): void { - let glState = WebGLStateTracker.get(gl); - if (!glState) { - trackContextState(gl, {copyState: false}); - glState = WebGLStateTracker.get(gl); - } - glState.push(); -} - -/** - * Restores previously saved WebGL context state - */ -export function popContextState(gl: WebGL2RenderingContext): void { - const glState = WebGLStateTracker.get(gl); - // assert(glState); - glState.pop(); -} - // HELPER FUNCTIONS - INSTALL GET/SET INTERCEPTORS (SPYS) ON THE CONTEXT /** diff --git a/modules/webgl/src/context/state-tracker/with-parameters.ts b/modules/webgl/src/context/state-tracker/with-parameters.ts index 2eeea60fbb..7b178da23a 100644 --- a/modules/webgl/src/context/state-tracker/with-parameters.ts +++ b/modules/webgl/src/context/state-tracker/with-parameters.ts @@ -3,7 +3,7 @@ // Copyright (c) vis.gl contributors import {GLParameters, setGLParameters} from '../parameters/unified-parameter-api'; -import {pushContextState, popContextState} from './webgl-state-tracker'; +import {WebGLStateTracker} from './webgl-state-tracker'; /** * Execute a function with a set of temporary WebGL parameter overrides @@ -25,7 +25,8 @@ export function withGLParameters( const {nocatch = true} = parameters; - pushContextState(gl); + const webglState = WebGLStateTracker.get(gl); + webglState.push(); setGLParameters(gl, parameters); // Setup is done, call the function @@ -34,13 +35,13 @@ export function withGLParameters( if (nocatch) { // Avoid try catch to minimize stack size impact for safe execution paths value = func(gl); - popContextState(gl); + webglState.pop(); } else { // Wrap in a try-catch to ensure that parameters are restored on exceptions try { value = func(gl); } finally { - popContextState(gl); + webglState.pop(); } } diff --git a/modules/webgl/src/index.ts b/modules/webgl/src/index.ts index 048018fded..2e2274ce78 100644 --- a/modules/webgl/src/index.ts +++ b/modules/webgl/src/index.ts @@ -49,12 +49,7 @@ export {TEXTURE_FORMATS as _TEXTURE_FORMATS} from './adapter/converters/texture- // DEPRECATED TEST EXPORTS // State tracking -export { - WebGLStateTracker, - trackContextState, - pushContextState, - popContextState -} from './context/state-tracker/webgl-state-tracker'; +export {WebGLStateTracker, trackContextState} from './context/state-tracker/webgl-state-tracker'; export { resetGLParameters, diff --git a/modules/webgl/test/context/state-tracker/webgl-state-tracker.spec.ts b/modules/webgl/test/context/state-tracker/webgl-state-tracker.spec.ts index 628a4aa465..f22faf2041 100644 --- a/modules/webgl/test/context/state-tracker/webgl-state-tracker.spec.ts +++ b/modules/webgl/test/context/state-tracker/webgl-state-tracker.spec.ts @@ -8,9 +8,8 @@ import {createTestDevice} from '@luma.gl/test-utils'; import type {WebGLDevice} from '@luma.gl/webgl'; import { + WebGLStateTracker, trackContextState, - pushContextState, - popContextState, getGLParameters, setGLParameters, resetGLParameters, @@ -30,14 +29,13 @@ import {ENUM_STYLE_SETTINGS_SET1, ENUM_STYLE_SETTINGS_SET2} from './data/sample- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion const device = createTestDevice({debug: true}) as WebGLDevice; -test('WebGLState#imports', t => { +test('WebGLStateTracker#imports', t => { + t.ok(typeof WebGLStateTracker === 'function', 'WebGLStateTracker imported OK'); t.ok(typeof trackContextState === 'function', 'trackContextState imported OK'); - t.ok(typeof pushContextState === 'function', 'trackContextState imported OK'); - t.ok(typeof popContextState === 'function', 'trackContextState imported OK'); t.end(); }); -test('WebGLState#trackContextState', t => { +test('WebGLStateTracker#trackContextState', t => { const {gl} = device; t.doesNotThrow( () => trackContextState(gl, {copyState: false}), @@ -46,7 +44,7 @@ test('WebGLState#trackContextState', t => { t.end(); }); -test('WebGLState#push & pop', t => { +test('WebGLStateTracker#push & pop', t => { const {gl} = device; resetGLParameters(gl); @@ -62,7 +60,7 @@ test('WebGLState#push & pop', t => { ); } - pushContextState(gl); + device.pushState(); // Set custom values and verify. setGLParameters(gl, ENUM_STYLE_SETTINGS_SET1); @@ -76,7 +74,7 @@ test('WebGLState#push & pop', t => { ); } - pushContextState(gl); + device.pushState(); // Set custom values and verify setGLParameters(gl, ENUM_STYLE_SETTINGS_SET2); @@ -90,7 +88,7 @@ test('WebGLState#push & pop', t => { } // Pop and verify values restore to previous state - popContextState(gl); + device.popState(); parameters = getGLParameters(gl); for (const key in ENUM_STYLE_SETTINGS_SET1) { @@ -102,7 +100,7 @@ test('WebGLState#push & pop', t => { ); } - popContextState(gl); + device.popState(); parameters = getGLParameters(gl); for (const key in GL_PARAMETER_DEFAULTS) { @@ -117,7 +115,7 @@ test('WebGLState#push & pop', t => { t.end(); }); -test('WebGLState#gl API', t => { +test('WebGLStateTracker#gl API', t => { const {gl} = device; resetGLParameters(gl); @@ -133,7 +131,7 @@ test('WebGLState#gl API', t => { ); } - pushContextState(gl); + device.pushState(); // TODO: test gl calls for compsite setters too (may be just call all gl calls). for (const key in ENUM_STYLE_SETTINGS_SET1) { @@ -159,7 +157,7 @@ test('WebGLState#gl API', t => { } } - popContextState(gl); + device.popState(); parameters = getGLParameters(gl); for (const key in GL_PARAMETER_DEFAULTS) { const value = parameters[key]; @@ -173,12 +171,12 @@ test('WebGLState#gl API', t => { t.end(); }); -test('WebGLState#intercept gl calls', t => { +test('WebGLStateTracker#intercept gl calls', t => { const {gl} = device; resetGLParameters(gl); - pushContextState(gl); + device.pushState(); const buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buffer); @@ -199,7 +197,7 @@ test('WebGLState#intercept gl calls', t => { gl.stencilOp(gl.KEEP, gl.ZERO, gl.REPLACE); t.is(getGLParameters(gl, gl.STENCIL_PASS_DEPTH_FAIL), gl.ZERO, 'direct gl call is tracked'); - popContextState(gl); + device.popState(); const parameters = getGLParameters(gl); // Verify default values. @@ -216,7 +214,7 @@ test('WebGLState#intercept gl calls', t => { t.end(); }); -test('WebGLState#not cached parameters', t => { +test('WebGLStateTracker#not cached parameters', t => { const {gl} = device; resetGLParameters(gl); From 7859594bb7529d7daa03bc849f5890a3fc75185f Mon Sep 17 00:00:00 2001 From: Ib Green Date: Sun, 28 Apr 2024 22:38:37 -0400 Subject: [PATCH 3/4] lint --- modules/webgl/src/context/state-tracker/webgl-state-tracker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/webgl/src/context/state-tracker/webgl-state-tracker.ts b/modules/webgl/src/context/state-tracker/webgl-state-tracker.ts index d5e6ce7bb3..5e3bb0cf42 100644 --- a/modules/webgl/src/context/state-tracker/webgl-state-tracker.ts +++ b/modules/webgl/src/context/state-tracker/webgl-state-tracker.ts @@ -20,7 +20,7 @@ export class WebGLStateTracker { static get(gl: WebGL2RenderingContext): WebGLStateTracker { // @ts-expect-error return gl.state as WebGLStateTracker; - } + } gl: WebGL2RenderingContext; program: unknown = null; From 0c668b8ff15688a244f4f68b65ced18aae99b04a Mon Sep 17 00:00:00 2001 From: Ib Green Date: Mon, 29 Apr 2024 06:33:40 -0400 Subject: [PATCH 4/4] trackState --- modules/webgl/src/adapter/webgl-device.ts | 9 +- .../state-tracker/webgl-state-tracker.ts | 97 ++++++++----------- modules/webgl/src/index.ts | 3 +- .../state-tracker/webgl-state-tracker.spec.ts | 18 ++-- 4 files changed, 51 insertions(+), 76 deletions(-) diff --git a/modules/webgl/src/adapter/webgl-device.ts b/modules/webgl/src/adapter/webgl-device.ts index 9a68b39906..02010b6ba3 100644 --- a/modules/webgl/src/adapter/webgl-device.ts +++ b/modules/webgl/src/adapter/webgl-device.ts @@ -7,7 +7,7 @@ import type {DeviceProps, DeviceInfo, CanvasContextProps, TextureFormat} from '@ import type {Buffer, Texture, Framebuffer, VertexArray, VertexArrayProps} from '@luma.gl/core'; import {Device, CanvasContext, log} from '@luma.gl/core'; import type {GLExtensions} from '@luma.gl/constants'; -import {WebGLStateTracker, trackContextState} from '../context/state-tracker/webgl-state-tracker'; +import {WebGLStateTracker} from '../context/state-tracker/webgl-state-tracker'; import {createBrowserContext} from '../context/helpers/create-browser-context'; import {getDeviceInfo} from './device-helpers/webgl-device-info'; import {WebGLDeviceFeatures} from './device-helpers/webgl-device-features'; @@ -227,13 +227,10 @@ ${device.info.vendor}, ${device.info.renderer} for canvas: ${device.canvasContex this.canvasContext.resize(); // Install context state tracking - // @ts-expect-error - hidden parameters - const {enable = true, copyState = false} = props; - trackContextState(this.gl, { - enable, - copyState, + const glState = new WebGLStateTracker(this.gl, { log: (...args: any[]) => log.log(1, ...args)() }); + glState.trackState(this.gl, {copyState: false}); // DEBUG contexts: Add debug instrumentation to the context, force log level to at least 1 if (props.debug) { diff --git a/modules/webgl/src/context/state-tracker/webgl-state-tracker.ts b/modules/webgl/src/context/state-tracker/webgl-state-tracker.ts index 5e3bb0cf42..8f418a4948 100644 --- a/modules/webgl/src/context/state-tracker/webgl-state-tracker.ts +++ b/modules/webgl/src/context/state-tracker/webgl-state-tracker.ts @@ -26,19 +26,19 @@ export class WebGLStateTracker { program: unknown = null; stateStack: object[] = []; enable = true; - cache: Record; + cache: Record = null!; log; + protected initialized = false; + constructor( gl: WebGL2RenderingContext, - { - copyState = false, // Copy cache from params (slow) or initialize from WebGL defaults (fast) - log = () => {} // Logging function, called when gl parameter change calls are actually issued - } = {} + props?: { + log; // Logging function, called when gl parameter change calls are actually issued + } ) { this.gl = gl; - this.cache = copyState ? getGLParameters(gl) : Object.assign({}, GL_PARAMETER_DEFAULTS); - this.log = log; + this.log = props?.log || (() => {}); this._updateCache = this._updateCache.bind(this); Object.seal(this); @@ -57,6 +57,38 @@ export class WebGLStateTracker { this.stateStack.pop(); } + /** + * Initialize WebGL state caching on a context + * can be called multiple times to enable/disable + * + * @note After calling this function, context state will be cached + * .push() and .pop() will be available for saving, + * temporarily modifying, and then restoring state. + */ + trackState(gl: WebGL2RenderingContext, options?: {copyState?: boolean}): void { + this.cache = options.copyState ? getGLParameters(gl) : Object.assign({}, GL_PARAMETER_DEFAULTS); + + if (this.initialized) { + throw new Error('WebGLStateTracker'); + } + this.initialized = true; + + // @ts-expect-error + this.gl.state = this; + + installProgramSpy(gl); + + // intercept all setter functions in the table + for (const key in GL_HOOKED_SETTERS) { + const setter = GL_HOOKED_SETTERS[key]; + installSetterSpy(gl, key, setter); + } + + // intercept all getter functions in the table + installGetterOverride(gl, 'getParameter'); + installGetterOverride(gl, 'isEnabled'); + } + /** // interceptor for context set functions - update our cache and our stack // values (Object) - the key values for this setter @@ -95,57 +127,6 @@ export class WebGLStateTracker { } } -// PUBLIC API - -/** - * Initialize WebGL state caching on a context - * can be called multiple times to enable/disable - * - * @note After calling this function, context state will be cached - * gl.state.push() and gl.state.pop() will be available for saving, - * temporarily modifying, and then restoring state. - */ -export function trackContextState( - gl: WebGL2RenderingContext, - options?: { - enable?: boolean; - copyState?: boolean; - log?: any; - } -): WebGL2RenderingContext { - const {enable = true, copyState} = options || {}; - // assert(copyState !== undefined); - // @ts-expect-error - if (!gl.state) { - // @ts-ignore - // const {polyfillContext} = global_; - // if (polyfillContext) { - // polyfillContext(gl); - // } - - // Create a state cache - // @ts-expect-error - gl.state = new WebGLStateTracker(gl, {copyState}); - - installProgramSpy(gl); - - // intercept all setter functions in the table - for (const key in GL_HOOKED_SETTERS) { - const setter = GL_HOOKED_SETTERS[key]; - installSetterSpy(gl, key, setter); - } - - // intercept all getter functions in the table - installGetterOverride(gl, 'getParameter'); - installGetterOverride(gl, 'isEnabled'); - } - - const glState = WebGLStateTracker.get(gl); - glState.enable = enable; - - return gl; -} - // HELPER FUNCTIONS - INSTALL GET/SET INTERCEPTORS (SPYS) ON THE CONTEXT /** diff --git a/modules/webgl/src/index.ts b/modules/webgl/src/index.ts index 2e2274ce78..419b88eb85 100644 --- a/modules/webgl/src/index.ts +++ b/modules/webgl/src/index.ts @@ -43,13 +43,12 @@ export {setDeviceParameters, withDeviceParameters} from './adapter/converters/de // HELPERS - EXPERIMENTAL export {getShaderLayout} from './adapter/helpers/get-shader-layout'; +export {WebGLStateTracker} from './context/state-tracker/webgl-state-tracker'; // TEST EXPORTS export {TEXTURE_FORMATS as _TEXTURE_FORMATS} from './adapter/converters/texture-formats'; // DEPRECATED TEST EXPORTS -// State tracking -export {WebGLStateTracker, trackContextState} from './context/state-tracker/webgl-state-tracker'; export { resetGLParameters, diff --git a/modules/webgl/test/context/state-tracker/webgl-state-tracker.spec.ts b/modules/webgl/test/context/state-tracker/webgl-state-tracker.spec.ts index f22faf2041..7a9a543415 100644 --- a/modules/webgl/test/context/state-tracker/webgl-state-tracker.spec.ts +++ b/modules/webgl/test/context/state-tracker/webgl-state-tracker.spec.ts @@ -9,7 +9,6 @@ import type {WebGLDevice} from '@luma.gl/webgl'; import { WebGLStateTracker, - trackContextState, getGLParameters, setGLParameters, resetGLParameters, @@ -31,18 +30,17 @@ const device = createTestDevice({debug: true}) as WebGLDevice; test('WebGLStateTracker#imports', t => { t.ok(typeof WebGLStateTracker === 'function', 'WebGLStateTracker imported OK'); - t.ok(typeof trackContextState === 'function', 'trackContextState imported OK'); t.end(); }); -test('WebGLStateTracker#trackContextState', t => { - const {gl} = device; - t.doesNotThrow( - () => trackContextState(gl, {copyState: false}), - 'trackContextState call succeeded' - ); - t.end(); -}); +// test.skip('WebGLStateTracker#trackContextState', t => { +// const {gl} = device; +// t.doesNotThrow( +// () => trackContextState(gl, {copyState: false}), +// 'trackContextState call succeeded' +// ); +// t.end(); +// }); test('WebGLStateTracker#push & pop', t => { const {gl} = device;