From de476c8075a5db2b47aea76cce9c92b2166a7cce Mon Sep 17 00:00:00 2001 From: Yulong Wang <7679871+fs-eire@users.noreply.github.com> Date: Wed, 21 Jun 2023 17:10:26 -0700 Subject: [PATCH] [js/web] update webgl context creating (#16436) ### Description Modify the creating of webgl context. Previous behavior: STEP.1 - create canvas (document.createElement), if failed, goto step.2 else step.3 STEP.2 - create offscreenCanvas, if failed abort STEP.3 - use the canvas created in step.1 or 2 to create webgl context. if successful return context else abort Now bahavior: STEP.1 create offscreenCanvas, if failed goto step.3 STEP.2 use it to create webgl context. if successful, return context STEP.3 create canvas (document.createElement). if failed, abort STEP.4 use it to create webgl context. if successful, return context else abort Motivation: we found in some environment, normalCanvas.getContext() returns null but offscreenCanvas.getContext() returns the context object. and when offscreenCanvas is available it is good idea to always prefer to use it. --- .../backends/webgl/webgl-context-factory.ts | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/js/web/lib/onnxjs/backends/webgl/webgl-context-factory.ts b/js/web/lib/onnxjs/backends/webgl/webgl-context-factory.ts index e2b060955b..6bf12500ec 100644 --- a/js/web/lib/onnxjs/backends/webgl/webgl-context-factory.ts +++ b/js/web/lib/onnxjs/backends/webgl/webgl-context-factory.ts @@ -20,7 +20,18 @@ export function createWebGLContext(contextId?: 'webgl'|'webgl2'): WebGLContext { context = cache.webgl; } - context = context || createNewWebGLContext(contextId); + if (!context) { + try { + // try to create webgl context from an offscreen canvas + const offscreenCanvas = createOffscreenCanvas(); + context = createNewWebGLContext(offscreenCanvas, contextId); + } catch (e) { + // if failed, fallback to try to use a normal canvas element + const canvas = createCanvas(); + context = createNewWebGLContext(canvas, contextId); + } + } + contextId = contextId || context.version === 1 ? 'webgl' : 'webgl2'; const gl = context.gl; @@ -44,8 +55,7 @@ export function createWebGLContext(contextId?: 'webgl'|'webgl2'): WebGLContext { return context; } -export function createNewWebGLContext(contextId?: 'webgl'|'webgl2'): WebGLContext { - const canvas = createCanvas(); +export function createNewWebGLContext(canvas: HTMLCanvasElement, contextId?: 'webgl'|'webgl2'): WebGLContext { const contextAttributes: WebGLContextAttributes = { alpha: false, depth: false, @@ -88,13 +98,17 @@ declare let OffscreenCanvas: {new (width: number, height: number): HTMLCanvasEle function createCanvas(): HTMLCanvasElement { if (typeof document === 'undefined') { - if (typeof OffscreenCanvas === 'undefined') { - throw new TypeError('failed to create canvas: OffscreenCanvas is not supported'); - } - return new OffscreenCanvas(1, 1); + throw new TypeError('failed to create canvas: document is not supported'); } const canvas: HTMLCanvasElement = document.createElement('canvas'); canvas.width = 1; canvas.height = 1; return canvas; } + +function createOffscreenCanvas(): HTMLCanvasElement { + if (typeof OffscreenCanvas === 'undefined') { + throw new TypeError('failed to create offscreen canvas: OffscreenCanvas is not supported'); + } + return new OffscreenCanvas(1, 1); +}