Skip to content
Snippets Groups Projects
Commit b1755604 authored by Alexander Rose's avatar Alexander Rose
Browse files

fix webgl context loss handling

parent e58da9b5
No related branches found
No related tags found
No related merge requests found
...@@ -129,7 +129,8 @@ namespace Canvas3DContext { ...@@ -129,7 +129,8 @@ namespace Canvas3DContext {
if (isDebugMode) { if (isDebugMode) {
const loseContextExt = gl.getExtension('WEBGL_lose_context'); const loseContextExt = gl.getExtension('WEBGL_lose_context');
if (loseContextExt) { 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 => { canvas.addEventListener('mousedown', e => {
if (webgl.isContextLost) return; if (webgl.isContextLost) return;
if (!e.shiftKey || !e.ctrlKey || !e.altKey) return; if (!e.shiftKey || !e.ctrlKey || !e.altKey) return;
...@@ -159,7 +160,9 @@ namespace Canvas3DContext { ...@@ -159,7 +160,9 @@ namespace Canvas3DContext {
const handlewWebglContextRestored = () => { const handlewWebglContextRestored = () => {
if (!webgl.isContextLost) return; if (!webgl.isContextLost) return;
webgl.handleContextRestored(); webgl.handleContextRestored(() => {
passes.draw.reset();
});
if (isDebugMode) console.log('context restored'); if (isDebugMode) console.log('context restored');
}; };
...@@ -599,6 +602,10 @@ namespace Canvas3D { ...@@ -599,6 +602,10 @@ namespace Canvas3D {
const contextRestoredSub = contextRestored.subscribe(() => { const contextRestoredSub = contextRestored.subscribe(() => {
pickHelper.dirty = true; pickHelper.dirty = true;
draw(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); const resized = new BehaviorSubject<any>(0);
......
...@@ -95,6 +95,10 @@ export class DrawPass { ...@@ -95,6 +95,10 @@ export class DrawPass {
this.wboit = enableWboit ? new WboitPass(webgl, width, height) : undefined; this.wboit = enableWboit ? new WboitPass(webgl, width, height) : undefined;
} }
reset() {
this.wboit?.reset();
}
setSize(width: number, height: number) { setSize(width: number, height: number) {
const w = this.colorTarget.getWidth(); const w = this.colorTarget.getWidth();
const h = this.colorTarget.getHeight(); const h = this.colorTarget.getHeight();
......
...@@ -89,13 +89,37 @@ export class WboitPass { ...@@ -89,13 +89,37 @@ export class WboitPass {
} }
} }
constructor(private webgl: WebGLContext, width: number, height: number) { reset() {
const { resources, extensions } = webgl; if (this._enabled) this._init();
const { drawBuffers, textureFloat, colorBufferFloat, depthTexture } = extensions; }
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 (!textureFloat || !colorBufferFloat || !depthTexture || !drawBuffers) {
if (isDebugMode) console.log('Missing extensions required for "wboit"'); 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 = resources.texture('image-float32', 'rgba', 'float', 'nearest');
this.textureA.define(width, height); this.textureA.define(width, height);
...@@ -104,17 +128,8 @@ export class WboitPass { ...@@ -104,17 +128,8 @@ export class WboitPass {
this.textureB.define(width, height); this.textureB.define(width, height);
this.renderable = getEvaluateWboitRenderable(webgl, this.textureA, this.textureB); this.renderable = getEvaluateWboitRenderable(webgl, this.textureA, this.textureB);
this.framebuffer = resources.framebuffer(); this.framebuffer = resources.framebuffer();
this.framebuffer.bind(); this._init();
drawBuffers.drawBuffers([
drawBuffers.COLOR_ATTACHMENT0,
drawBuffers.COLOR_ATTACHMENT1,
]);
this.textureA.attachFramebuffer(this.framebuffer, 'color0');
this.textureB.attachFramebuffer(this.framebuffer, 'color1');
this._enabled = true; this._enabled = true;
} }
} }
\ No newline at end of file
...@@ -193,7 +193,7 @@ export interface WebGLContext { ...@@ -193,7 +193,7 @@ export interface WebGLContext {
readonly isContextLost: boolean readonly isContextLost: boolean
readonly contextRestored: BehaviorSubject<now.Timestamp> readonly contextRestored: BehaviorSubject<now.Timestamp>
setContextLost: () => void setContextLost: () => void
handleContextRestored: () => void handleContextRestored: (extraResets?: () => void) => void
/** Cache for compute renderables, managed by consumers */ /** Cache for compute renderables, managed by consumers */
readonly namedComputeRenderables: { [name: string]: ComputeRenderable<any> } readonly namedComputeRenderables: { [name: string]: ComputeRenderable<any> }
...@@ -302,7 +302,7 @@ export function createContext(gl: GLRenderingContext, props: Partial<{ pixelScal ...@@ -302,7 +302,7 @@ export function createContext(gl: GLRenderingContext, props: Partial<{ pixelScal
setContextLost: () => { setContextLost: () => {
isContextLost = true; isContextLost = true;
}, },
handleContextRestored: () => { handleContextRestored: (extraResets?: () => void) => {
Object.assign(extensions, createExtensions(gl)); Object.assign(extensions, createExtensions(gl));
state.reset(); state.reset();
...@@ -312,6 +312,7 @@ export function createContext(gl: GLRenderingContext, props: Partial<{ pixelScal ...@@ -312,6 +312,7 @@ export function createContext(gl: GLRenderingContext, props: Partial<{ pixelScal
resources.reset(); resources.reset();
renderTargets.forEach(rt => rt.reset()); renderTargets.forEach(rt => rt.reset());
extraResets?.();
isContextLost = false; isContextLost = false;
contextRestored.next(now()); contextRestored.next(now());
......
...@@ -329,7 +329,9 @@ export function createTexture(gl: GLRenderingContext, extensions: WebGLExtension ...@@ -329,7 +329,9 @@ export function createTexture(gl: GLRenderingContext, extensions: WebGLExtension
texture = getTexture(gl); texture = getTexture(gl);
init(); 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); if (loadedData) load(loadedData);
}, },
destroy: () => { destroy: () => {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment