mirror of https://github.com/vladmandic/human
140 lines
4.7 KiB
TypeScript
140 lines
4.7 KiB
TypeScript
/** TFJS custom backend registration */
|
|
|
|
import * as tf from 'dist/tfjs.esm.js';
|
|
import type { Human } from '../human';
|
|
import { log } from '../util/util';
|
|
import * as image from '../image/image';
|
|
import * as models from '../models';
|
|
import type { AnyCanvas } from '../exports';
|
|
import type { MathBackendWebGL } from './types';
|
|
// import { env } from '../env';
|
|
|
|
export const config = {
|
|
name: 'humangl',
|
|
priority: 999,
|
|
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,
|
|
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;
|
|
config.extensions = gl.getSupportedExtensions();
|
|
// gl.getExtension('KHR_parallel_shader_compile');
|
|
}
|
|
|
|
/**
|
|
* Registers custom WebGL2 backend to be used by Human library
|
|
*
|
|
* @returns void
|
|
*/
|
|
export function register(instance: Human): void {
|
|
// force backend reload if gl context is not valid
|
|
if (instance.config.backend !== 'humangl') return;
|
|
if ((config.name in tf.engine().registry) && !config?.gl?.getParameter(config.gl.VERSION)) {
|
|
log('humangl error: backend invalid context');
|
|
models.reset(instance);
|
|
/*
|
|
log('resetting humangl backend');
|
|
await tf.removeBackend(config.name);
|
|
await register(instance); // re-register
|
|
*/
|
|
}
|
|
if (!tf.findBackend(config.name)) {
|
|
try {
|
|
config.canvas = image.canvas(100, 100);
|
|
} catch (err) {
|
|
log('humangl error: cannot create canvas:', err);
|
|
return;
|
|
}
|
|
try {
|
|
config.gl = config.canvas.getContext('webgl2', config.webGLattr);
|
|
if (!config.gl) {
|
|
log('humangl error: cannot get webgl context');
|
|
return;
|
|
}
|
|
const glv2 = config.gl.getParameter(config.gl.VERSION).includes('2.0');
|
|
if (!glv2) {
|
|
log('backend override: using fallback webgl backend as webgl 2.0 is not detected');
|
|
instance.config.backend = 'webgl';
|
|
return;
|
|
}
|
|
if (config.canvas) {
|
|
config.canvas.addEventListener('webglcontextlost', (e) => {
|
|
log('humangl error:', e.type);
|
|
log('possible browser memory leak using webgl or conflict with multiple backend registrations');
|
|
instance.emit('error');
|
|
throw new Error('backend error: webgl context lost');
|
|
// log('resetting humangl backend');
|
|
// env.initial = true;
|
|
// models.reset(instance);
|
|
// await tf.removeBackend(config.name);
|
|
// await register(instance); // re-register
|
|
});
|
|
config.canvas.addEventListener('webglcontextrestored', (e) => {
|
|
log('humangl error: context restored:', e);
|
|
});
|
|
config.canvas.addEventListener('webglcontextcreationerror', (e) => {
|
|
log('humangl error: context create:', e);
|
|
});
|
|
}
|
|
} catch (err) {
|
|
log('humangl error: cannot get webgl context:', err);
|
|
return;
|
|
}
|
|
try {
|
|
tf.setWebGLContext(2, config.gl);
|
|
} catch (err) {
|
|
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) {
|
|
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) {
|
|
log('humangl error: cannot update webgl backend registration:', err);
|
|
return;
|
|
}
|
|
try {
|
|
// @ts-ignore private property
|
|
if (tf.env().flagRegistry.WEBGL_VERSION) tf.env().set('WEBGL_VERSION', 2);
|
|
} catch (err) {
|
|
log('humangl error: cannot set WebGL backend flags:', err);
|
|
return;
|
|
}
|
|
extensions();
|
|
const backend = tf.backend() as MathBackendWebGL;
|
|
const current = typeof backend['gpgpu'] !== 'undefined' ? backend.getGPGPUContext().gl : null;
|
|
if (current) {
|
|
if (instance.config.debug) log('humangl backend registered:', { webgl: current.getParameter(current.VERSION) as string, renderer: current.getParameter(current.RENDERER) as string });
|
|
} else {
|
|
log('humangl error: no current gl context:', current, config.gl);
|
|
}
|
|
}
|
|
}
|