diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts index 0b342296361ca794eb5fbc8dec65e3b5ebf3d2e7..1ac30e8b34a482afc7b98323994e9fae80d61758 100644 --- a/src/mol-canvas3d/canvas3d.ts +++ b/src/mol-canvas3d/canvas3d.ts @@ -129,7 +129,8 @@ namespace Canvas3DContext { if (isDebugMode) { const loseContextExt = gl.getExtension('WEBGL_lose_context'); if (loseContextExt) { - /** Hold down shift+ctrl+alt and press any mouse button to trigger lose context */ + // Hold down shift+ctrl+alt and press any mouse button to call `loseContext`. + // After 1 second `restoreContext` will be called. canvas.addEventListener('mousedown', e => { if (webgl.isContextLost) return; if (!e.shiftKey || !e.ctrlKey || !e.altKey) return; @@ -159,7 +160,9 @@ namespace Canvas3DContext { const handlewWebglContextRestored = () => { if (!webgl.isContextLost) return; - webgl.handleContextRestored(); + webgl.handleContextRestored(() => { + passes.draw.reset(); + }); if (isDebugMode) console.log('context restored'); }; @@ -599,6 +602,10 @@ namespace Canvas3D { const contextRestoredSub = contextRestored.subscribe(() => { pickHelper.dirty = true; draw(true); + // Unclear why, but in Chrome with wboit enabled the first `draw` only clears + // the drawingBuffer. Note that in Firefox the drawingBuffer is preserved after + // context loss so it is unclear if it behaves the same. + draw(true); }); const resized = new BehaviorSubject<any>(0); diff --git a/src/mol-canvas3d/passes/draw.ts b/src/mol-canvas3d/passes/draw.ts index 69f5c531e07aff6e835193f055314bd8a947d6f2..59cb04b2f610812f18311d08cf297c068aee3378 100644 --- a/src/mol-canvas3d/passes/draw.ts +++ b/src/mol-canvas3d/passes/draw.ts @@ -95,6 +95,10 @@ export class DrawPass { this.wboit = enableWboit ? new WboitPass(webgl, width, height) : undefined; } + reset() { + this.wboit?.reset(); + } + setSize(width: number, height: number) { const w = this.colorTarget.getWidth(); const h = this.colorTarget.getHeight(); diff --git a/src/mol-canvas3d/passes/wboit.ts b/src/mol-canvas3d/passes/wboit.ts index 48effde2c863dfbccb8c638e181c32fef1733715..93e403c69cfe20fac1a53efcd42f81c9c62041b5 100644 --- a/src/mol-canvas3d/passes/wboit.ts +++ b/src/mol-canvas3d/passes/wboit.ts @@ -89,13 +89,37 @@ export class WboitPass { } } - constructor(private webgl: WebGLContext, width: number, height: number) { - const { resources, extensions } = webgl; - const { drawBuffers, textureFloat, colorBufferFloat, depthTexture } = extensions; + reset() { + if (this._enabled) this._init(); + } + + private _init() { + const { extensions: { drawBuffers } } = this.webgl; + + this.framebuffer.bind(); + drawBuffers!.drawBuffers([ + drawBuffers!.COLOR_ATTACHMENT0, + drawBuffers!.COLOR_ATTACHMENT1, + ]); + + this.textureA.attachFramebuffer(this.framebuffer, 'color0'); + this.textureB.attachFramebuffer(this.framebuffer, 'color1'); + } + + static isSupported(webgl: WebGLContext) { + const { extensions: { drawBuffers, textureFloat, colorBufferFloat, depthTexture } } = webgl; if (!textureFloat || !colorBufferFloat || !depthTexture || !drawBuffers) { if (isDebugMode) console.log('Missing extensions required for "wboit"'); - return; + return false; + } else { + return true; } + } + + constructor(private webgl: WebGLContext, width: number, height: number) { + if (!WboitPass.isSupported(webgl)) return; + + const { resources } = webgl; this.textureA = resources.texture('image-float32', 'rgba', 'float', 'nearest'); this.textureA.define(width, height); @@ -104,17 +128,8 @@ export class WboitPass { this.textureB.define(width, height); this.renderable = getEvaluateWboitRenderable(webgl, this.textureA, this.textureB); - this.framebuffer = resources.framebuffer(); - this.framebuffer.bind(); - drawBuffers.drawBuffers([ - drawBuffers.COLOR_ATTACHMENT0, - drawBuffers.COLOR_ATTACHMENT1, - ]); - - this.textureA.attachFramebuffer(this.framebuffer, 'color0'); - this.textureB.attachFramebuffer(this.framebuffer, 'color1'); - + this._init(); this._enabled = true; } } \ No newline at end of file diff --git a/src/mol-gl/webgl/context.ts b/src/mol-gl/webgl/context.ts index ce523b7dadcb8418fa677f30f0b6cdd42659f1f6..be8a7098f33ae52ce8da6f46bd11e9d13e6f7715 100644 --- a/src/mol-gl/webgl/context.ts +++ b/src/mol-gl/webgl/context.ts @@ -193,7 +193,7 @@ export interface WebGLContext { readonly isContextLost: boolean readonly contextRestored: BehaviorSubject<now.Timestamp> setContextLost: () => void - handleContextRestored: () => void + handleContextRestored: (extraResets?: () => void) => void /** Cache for compute renderables, managed by consumers */ readonly namedComputeRenderables: { [name: string]: ComputeRenderable<any> } @@ -302,7 +302,7 @@ export function createContext(gl: GLRenderingContext, props: Partial<{ pixelScal setContextLost: () => { isContextLost = true; }, - handleContextRestored: () => { + handleContextRestored: (extraResets?: () => void) => { Object.assign(extensions, createExtensions(gl)); state.reset(); @@ -312,6 +312,7 @@ export function createContext(gl: GLRenderingContext, props: Partial<{ pixelScal resources.reset(); renderTargets.forEach(rt => rt.reset()); + extraResets?.(); isContextLost = false; contextRestored.next(now()); diff --git a/src/mol-gl/webgl/texture.ts b/src/mol-gl/webgl/texture.ts index a7972d3cc87513a742eaf57223c4688e2a322440..06236359db366bbdef44296e4cbf5c0d1b8109f4 100644 --- a/src/mol-gl/webgl/texture.ts +++ b/src/mol-gl/webgl/texture.ts @@ -329,7 +329,9 @@ export function createTexture(gl: GLRenderingContext, extensions: WebGLExtension texture = getTexture(gl); init(); - define(width, height, depth); + const [_width, _height, _depth] = [width, height, depth]; + width = 0, height = 0, depth = 0; // set to zero to trigger resize + define(_width, _height, _depth); if (loadedData) load(loadedData); }, destroy: () => {