human/src/tfjs/humangl.ts

137 lines
4.5 KiB
TypeScript
Raw Normal View History

/** TFJS custom backend registration */
2021-11-12 21:07:23 +01:00
import type { Human } from '../human';
2021-09-27 19:58:13 +02:00
import { log } from '../util/util';
import * as tf from '../../dist/tfjs.esm.js';
import * as image from '../image/image';
2021-09-17 20:07:44 +02:00
import * as models from '../models';
2021-11-14 17:22:52 +01:00
import type { AnyCanvas } from '../exports';
2021-09-17 20:07:44 +02:00
// import { env } from '../env';
export const config = {
name: 'humangl',
2021-09-17 17:23:00 +02:00
priority: 999,
2022-08-21 21:23:03 +02:00
canvas: null as null | AnyCanvas,
gl: null as null | WebGL2RenderingContext,
extensions: [] as string[] | null,
webGLattr: { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.2
alpha: false,
antialias: false,
premultipliedAlpha: false,
preserveDrawingBuffer: false,
depth: false,
stencil: false,
2022-09-02 16:22:24 +02:00
failIfMajorPerformanceCaveat: false, // default=true
desynchronized: true, // default=undefined
},
};
function extensions(): void {
/*
https://www.khronos.org/registry/webgl/extensions/
https://webglreport.com/?v=2
*/
const gl = config.gl;
if (!gl) return;
2022-08-21 19:34:51 +02:00
config.extensions = gl.getSupportedExtensions();
// gl.getExtension('KHR_parallel_shader_compile');
}
/**
* Registers custom WebGL2 backend to be used by Human library
*
* @returns void
*/
2022-08-21 21:23:03 +02:00
export function register(instance: Human): void {
2021-09-17 17:23:00 +02:00
// force backend reload if gl context is not valid
2021-09-20 23:17:13 +02:00
if (instance.config.backend !== 'humangl') return;
2022-08-24 14:10:36 +02:00
if ((config.name in tf.engine().registry) && !config?.gl?.getParameter(config.gl.VERSION)) {
2022-09-02 17:57:47 +02:00
log('humangl error: backend invalid context');
2021-09-17 17:23:00 +02:00
models.reset(instance);
2021-09-17 20:07:44 +02:00
/*
log('resetting humangl backend');
2021-09-17 17:23:00 +02:00
await tf.removeBackend(config.name);
await register(instance); // re-register
2021-09-17 20:07:44 +02:00
*/
2021-09-17 17:23:00 +02:00
}
if (!tf.findBackend(config.name)) {
try {
2022-08-21 21:23:03 +02:00
config.canvas = image.canvas(100, 100);
} catch (err) {
2022-09-02 17:57:47 +02:00
log('humangl error: cannot create canvas:', err);
return;
}
try {
2022-08-21 19:34:51 +02:00
config.gl = config.canvas.getContext('webgl2', config.webGLattr);
if (!config.gl) {
2022-09-02 17:57:47 +02:00
log('humangl error: cannot get webgl context');
2022-08-21 19:34:51 +02:00
return;
}
const glv2 = config.gl.getParameter(config.gl.VERSION).includes('2.0');
if (!glv2) {
2022-09-02 20:07:10 +02:00
log('backend override: using fallback webgl backend as webgl 2.0 is not detected');
instance.config.backend = 'webgl';
return;
}
2021-09-17 17:23:00 +02:00
if (config.canvas) {
2022-08-21 21:23:03 +02:00
config.canvas.addEventListener('webglcontextlost', (e) => {
2022-09-02 17:57:47 +02:00
log('humangl error:', e.type);
2021-10-04 23:03:36 +02:00
log('possible browser memory leak using webgl or conflict with multiple backend registrations');
2021-09-17 20:07:44 +02:00
instance.emit('error');
2021-11-14 17:22:52 +01:00
throw new Error('backend error: webgl context lost');
2021-11-06 15:21:51 +01:00
// log('resetting humangl backend');
// env.initial = true;
// models.reset(instance);
// await tf.removeBackend(config.name);
// await register(instance); // re-register
2021-09-17 17:23:00 +02:00
});
config.canvas.addEventListener('webglcontextrestored', (e) => {
2022-09-02 17:57:47 +02:00
log('humangl error: context restored:', e);
2021-09-17 17:23:00 +02:00
});
config.canvas.addEventListener('webglcontextcreationerror', (e) => {
2022-09-02 17:57:47 +02:00
log('humangl error: context create:', e);
2021-09-17 17:23:00 +02:00
});
}
} catch (err) {
2022-09-02 17:57:47 +02:00
log('humangl error: cannot get webgl context:', err);
return;
}
try {
tf.setWebGLContext(2, config.gl);
} catch (err) {
2022-09-02 17:57:47 +02:00
log('humangl error: cannot set webgl context:', err);
return;
}
try {
const ctx = new tf.GPGPUContext(config.gl);
tf.registerBackend(config.name, () => new tf.MathBackendWebGL(ctx), config.priority);
} catch (err) {
2022-09-02 17:57:47 +02:00
log('humangl error: cannot register webgl backend:', err);
return;
}
try {
const kernels = tf.getKernelsForBackend('webgl');
kernels.forEach((kernelConfig) => {
const newKernelConfig = { ...kernelConfig, backendName: config.name };
tf.registerKernel(newKernelConfig);
});
} catch (err) {
2022-09-02 17:57:47 +02:00
log('humangl error: cannot update webgl backend registration:', err);
2021-10-03 14:12:26 +02:00
return;
}
try {
2022-08-21 19:34:51 +02:00
if (tf.env().flagRegistry.WEBGL_VERSION) tf.env().set('WEBGL_VERSION', 2);
} catch (err) {
2022-09-02 17:57:47 +02:00
log('humangl error: cannot set WebGL backend flags:', err);
return;
}
extensions();
2022-09-02 17:57:47 +02:00
const current = tf.backend().getGPGPUContext ? tf.backend().getGPGPUContext().gl : null;
if (current) {
2022-09-02 20:07:10 +02:00
if (instance.config.debug) log('humangl backend registered:', { webgl: current.getParameter(current.VERSION) as string, renderer: current.getParameter(current.RENDERER) as string });
2022-09-02 17:57:47 +02:00
} else {
log('humangl error: no current gl context:', current, config.gl);
}
}
}