From 66b56734e2cdf2f814012d4e69869a294752f7cf Mon Sep 17 00:00:00 2001 From: Ping Yu <4018+pyu10055@users.noreply.github.com> Date: Fri, 3 Mar 2023 11:55:04 -0800 Subject: [PATCH] disable offscreen canvas for safari, since gl fencing is not working yet for its technology preview (#7436) Co-authored-by: Matthew Soulanille --- tfjs-backend-webgl/src/canvas_util.ts | 12 ++++--- tfjs-backend-webgl/src/gpgpu_context.ts | 48 ++++++++++++------------- tfjs-core/src/flags.ts | 6 ++++ 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/tfjs-backend-webgl/src/canvas_util.ts b/tfjs-backend-webgl/src/canvas_util.ts index 21a16393410..d0cb13deec3 100644 --- a/tfjs-backend-webgl/src/canvas_util.ts +++ b/tfjs-backend-webgl/src/canvas_util.ts @@ -70,7 +70,10 @@ export function getWebGLContext( } function createCanvas(webGLVersion: number) { - if (typeof OffscreenCanvas !== 'undefined' && webGLVersion === 2) { + // Use canvas element for Safari, since its offscreen canvas does not support + // fencing. + if (!env().getBool('IS_SAFARI') && typeof OffscreenCanvas !== 'undefined' && + webGLVersion === 2) { return new OffscreenCanvas(300, 150); } else if (typeof document !== 'undefined') { return document.createElement('canvas'); @@ -98,9 +101,10 @@ function getWebGLRenderingContext( } if (webGLVersion === 1) { - return (canvas.getContext('webgl', WEBGL_ATTRIBUTES) || - (canvas as HTMLCanvasElement) - .getContext('experimental-webgl', WEBGL_ATTRIBUTES)); + return ( + canvas.getContext('webgl', WEBGL_ATTRIBUTES) || + (canvas as HTMLCanvasElement) + .getContext('experimental-webgl', WEBGL_ATTRIBUTES)); } return canvas.getContext('webgl2', WEBGL_ATTRIBUTES) as WebGLRenderingContext; } diff --git a/tfjs-backend-webgl/src/gpgpu_context.ts b/tfjs-backend-webgl/src/gpgpu_context.ts index cc5294f53b1..925be718eae 100644 --- a/tfjs-backend-webgl/src/gpgpu_context.ts +++ b/tfjs-backend-webgl/src/gpgpu_context.ts @@ -29,7 +29,7 @@ export interface FenceContext { isFencePassed(): boolean; } -type WebGLVao = WebGLVertexArrayObject | WebGLVertexArrayObjectOES; +type WebGLVao = WebGLVertexArrayObject|WebGLVertexArrayObjectOES; export interface GPGPUContextProgram extends WebGLProgram { vao: WebGLVao; @@ -55,8 +55,8 @@ export class GPGPUContext { textureConfig: TextureConfig; createVertexArray: () => WebGLVao | null; - bindVertexArray: (vao: WebGLVao | null) => void; - deleteVertexArray: (vao: WebGLVao | null) => void; + bindVertexArray: (vao: WebGLVao|null) => void; + deleteVertexArray: (vao: WebGLVao|null) => void; getVertexArray: () => WebGLVao | null; constructor(gl?: WebGLRenderingContext) { @@ -72,20 +72,19 @@ export class GPGPUContext { if (env().getNumber('WEBGL_VERSION') === 2) { const gl2 = gl as WebGL2RenderingContext; this.createVertexArray = () => { - return webgl_util.callAndCheck(gl2, - () => gl2.createVertexArray()); + return webgl_util.callAndCheck(gl2, () => gl2.createVertexArray()); }; this.bindVertexArray = (vao: WebGLVao|null) => { - return webgl_util.callAndCheck(gl2, - () => gl2.bindVertexArray(vao as WebGLVertexArrayObject)); + return webgl_util.callAndCheck( + gl2, () => gl2.bindVertexArray(vao as WebGLVertexArrayObject)); }; this.deleteVertexArray = (vao: WebGLVao|null) => { - return webgl_util.callAndCheck(gl2, - () => gl2.deleteVertexArray(vao as WebGLVertexArrayObject)); + return webgl_util.callAndCheck( + gl2, () => gl2.deleteVertexArray(vao as WebGLVertexArrayObject)); }; this.getVertexArray = () => { - return webgl_util.callAndCheck(gl2, - () => gl2.getParameter(gl2.VERTEX_ARRAY_BINDING)); + return webgl_util.callAndCheck( + gl2, () => gl2.getParameter(gl2.VERTEX_ARRAY_BINDING)); }; } else if (gl != null) { const ext = gl.getExtension('OES_vertex_array_object'); @@ -95,20 +94,20 @@ export class GPGPUContext { ' OES_vertex_array_object.'); } this.createVertexArray = () => { - return webgl_util.callAndCheck(gl, - () => ext.createVertexArrayOES()); + return webgl_util.callAndCheck(gl, () => ext.createVertexArrayOES()); }; this.bindVertexArray = (vao: WebGLVao|null) => { - return webgl_util.callAndCheck(gl, - () => ext.bindVertexArrayOES(vao as WebGLVertexArrayObjectOES)); + return webgl_util.callAndCheck( + gl, () => ext.bindVertexArrayOES(vao as WebGLVertexArrayObjectOES)); }; this.deleteVertexArray = (vao: WebGLVao|null) => { - return webgl_util.callAndCheck(gl, - () => ext.deleteVertexArrayOES(vao as WebGLVertexArrayObjectOES)); + return webgl_util.callAndCheck( + gl, + () => ext.deleteVertexArrayOES(vao as WebGLVertexArrayObjectOES)); }; this.getVertexArray = () => { - return webgl_util.callAndCheck(gl, - () => gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES)); + return webgl_util.callAndCheck( + gl, () => gl.getParameter(ext.VERTEX_ARRAY_BINDING_OES)); }; } @@ -352,9 +351,9 @@ export class GPGPUContext { webgl_util.callAndCheck( gl, () => gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer)); console.assert( - gpgpu_util.bindVertexProgramAttributeStreams(gl, program2, - this.vertexBuffer), - 'gpgpu_util.bindVertexProgramAttributeStreams not fully successful.'); + gpgpu_util.bindVertexProgramAttributeStreams( + gl, program2, this.vertexBuffer), + 'gpgpu_util.bindVertexProgramAttributeStreams not fully successful.'); if (this.debug) { webgl_util.validateProgram(gl, program2); @@ -464,8 +463,9 @@ export class GPGPUContext { const gl = this.gl; if (this.debug) { const boundVao = this.getVertexArray(); - console.assert(boundVao === this.program.vao, - 'VAO changed between setProgram and executeProgram!'); + console.assert( + boundVao === this.program.vao, + 'VAO changed between setProgram and executeProgram!'); this.debugValidate(); } diff --git a/tfjs-core/src/flags.ts b/tfjs-core/src/flags.ts index 43e9bdc23e4..e6086f6ab6a 100644 --- a/tfjs-core/src/flags.ts +++ b/tfjs-core/src/flags.ts @@ -52,6 +52,12 @@ ENV.registerFlag( navigator.userAgent != null && /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor)); +/** Whether this browser is Safari. */ +ENV.registerFlag( + 'IS_SAFARI', + () => typeof navigator !== 'undefined' && navigator != null && + navigator.userAgent != null && /Safari/.test(navigator.userAgent) && + /Apple/.test(navigator.vendor)); /** * True when the environment is "production" where we disable safety checks * to gain performance.