Skip to content

Commit

Permalink
Fix problems with destroying WebGL context; see #407
Browse files Browse the repository at this point in the history
  • Loading branch information
phoboslab committed Sep 20, 2022
1 parent 5ba2fb0 commit 924acfb
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 25 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,10 @@ A `JSMpeg.Player` instance supports the following methods and properties:
- `.pause()` – pause playback
- `.stop()` – stop playback and seek to the beginning
- `.nextFrame()` – advance playback by one video frame. This does not decode audio. Returns `true` on success, `false` when there's not enough data.
- `.destroy()` – stops playback, disconnects the source and cleans up WebGL and WebAudio state. The player can not be used afterwards.
- `.volume` – get or set the audio volume (0-1)
- `.currentTime` – get or set the current playback position in seconds
- `.paused` – read only, wether playback is paused
- `.destroy()` – stops playback, disconnects the source and cleans up WebGL and WebAudio state. The player can not be used afterwards. If the player created the canvas element it is removed from the document.


## Encoding Video/Audio for JSMpeg
Expand Down
2 changes: 1 addition & 1 deletion jsmpeg.min.js

Large diffs are not rendered by default.

13 changes: 11 additions & 2 deletions src/canvas2d.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
JSMpeg.Renderer.Canvas2D = (function(){ "use strict";

var CanvasRenderer = function(options) {
this.canvas = options.canvas || document.createElement('canvas');
if (options.canvas) {
this.canvas = options.canvas;
this.ownsCanvasElement = false;
}
else {
this.canvas = document.createElement('canvas');
this.ownsCanvasElement = true;
}
this.width = this.canvas.width;
this.height = this.canvas.height;
this.enabled = true;
Expand All @@ -10,7 +17,9 @@ var CanvasRenderer = function(options) {
};

CanvasRenderer.prototype.destroy = function() {
// Nothing to do here
if (this.ownsCanvasElement) {
this.canvas.remove();
}
};

CanvasRenderer.prototype.resize = function(width, height) {
Expand Down
39 changes: 18 additions & 21 deletions src/webgl.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
JSMpeg.Renderer.WebGL = (function(){ "use strict";

var WebGLRenderer = function(options) {
this.canvas = options.canvas || document.createElement('canvas');
if (options.canvas) {
this.canvas = options.canvas;
this.ownsCanvasElement = false;
}
else {
this.canvas = document.createElement('canvas');
this.ownsCanvasElement = true;
}
this.width = this.canvas.width;
this.height = this.canvas.height;
this.enabled = true;
this.contextLost = false;

this.hasTextureData = {};

Expand All @@ -26,16 +32,11 @@ var WebGLRenderer = function(options) {
throw new Error('Failed to get WebGL Context');
}

// WebGLRenderer.destroy() will explicitly lose the GL context. Calling
// .getContext('webgl') on a Canvas element whose GL context has previously
// been lost, will return an un-restored GL context. So we try to catch this
// case here and try restore the GL context.
if (this.gl.isContextLost()) {
this.gl.getExtension('WEBGL_lose_context').restoreContext();
}
this.handleContextLostBound = this.handleContextLost.bind(this);
this.handleContextRestoredBound = this.handleContextRestored.bind(this);

this.canvas.addEventListener('webglcontextlost', this.handleContextLost.bind(this), false);
this.canvas.addEventListener('webglcontextrestored', this.handleContextRestored.bind(this), false);
this.canvas.addEventListener('webglcontextlost', this.handleContextLostBound, false);
this.canvas.addEventListener('webglcontextrestored', this.handleContextRestoredBound, false);

this.initGL();
};
Expand Down Expand Up @@ -82,20 +83,13 @@ WebGLRenderer.prototype.initGL = function() {

WebGLRenderer.prototype.handleContextLost = function(ev) {
ev.preventDefault();
this.contextLost = true;
};

WebGLRenderer.prototype.handleContextRestored = function(ev) {
this.initGL();
this.contextLost = false;
};

WebGLRenderer.prototype.destroy = function() {
if (this.contextLost) {
// Nothing to do here
return;
}

var gl = this.gl;

this.deleteTexture(gl.TEXTURE0, this.textureY);
Expand All @@ -109,9 +103,12 @@ WebGLRenderer.prototype.destroy = function() {
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.deleteBuffer(this.vertexBuffer);

gl.getExtension('WEBGL_lose_context').loseContext();
this.canvas.remove();
this.contextLost = true;
this.canvas.removeEventListener('webglcontextlost', this.handleContextLostBound, false);
this.canvas.removeEventListener('webglcontextrestored', this.handleContextRestoredBound, false);

if (this.ownsCanvasElement) {
this.canvas.remove();
}
};

WebGLRenderer.prototype.resize = function(width, height) {
Expand Down

0 comments on commit 924acfb

Please sign in to comment.