Skip to content

Commit 73aa39a

Browse files
committed
Handle context loss a little better
Main point is to at least ensure animations are stopped and that we do as little work as possible (context is normally lost for resource reasons).
1 parent 0f0c3fe commit 73aa39a

File tree

5 files changed

+49
-7
lines changed

5 files changed

+49
-7
lines changed

js/src/_base/Preview.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,16 @@ var PreviewView = RenderableView.extend({
157157
renderScene: function() {
158158
this.log('renderScene');
159159

160-
// TODO: check renderer.domElement.isContextLost()
161-
162160
if (this.isFrozen) {
163161
this.unfreeze();
164162
}
163+
164+
if (this.renderer.context.isContextLost()) {
165+
// Context is invalid, freeze for now (stops animation etc)
166+
this.freeze();
167+
return;
168+
}
169+
165170
if (this._rebuildNeeded) {
166171
this.constructScene();
167172
}

js/src/_base/Renderable.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,16 @@ var RenderableView = widgets.DOMWidgetView.extend({
9696
scene = scene || this.scene;
9797
camera = camera || this.camera;
9898

99-
// TODO: check renderer.domElement.isContextLost()
100-
10199
if (this.isFrozen) {
102100
this.unfreeze();
103101
}
104102

103+
if (this.renderer.context.isContextLost()) {
104+
// Context is invalid, freeze for now (stops animation etc)
105+
this.freeze();
106+
return;
107+
}
108+
105109
this.renderer.render(scene, camera);
106110
},
107111

@@ -119,7 +123,6 @@ var RenderableView = widgets.DOMWidgetView.extend({
119123
}
120124

121125
this.acquireRenderer();
122-
this.updateSize();
123126

124127
if (this.controls) {
125128
this.enableControls();
@@ -137,6 +140,8 @@ var RenderableView = widgets.DOMWidgetView.extend({
137140

138141
this.$el.css('margin-bottom', '-5px');
139142

143+
this.updateSize();
144+
140145
this.log('ThreeView.acquireRenderer(' + this.renderer.poolId + ')');
141146
},
142147

@@ -216,6 +221,7 @@ var RenderableView = widgets.DOMWidgetView.extend({
216221

217222
onRendererReclaimed: function() {
218223
this.log('ThreeView WebGL context is being reclaimed: ' + this.renderer.poolId);
224+
219225
this.freeze();
220226
},
221227

js/src/_base/RendererPool.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ _.extend(RendererPool.prototype, {
3333
// required for converting canvas to png
3434
preserveDrawingBuffer: true,
3535
});
36+
renderer.context.canvas.addEventListener("webglcontextlost", this.onContextLost.bind(this), false);
3637
renderer.poolId = this.numCreated;
3738
this.numCreated++;
3839

@@ -79,6 +80,24 @@ _.extend(RendererPool.prototype, {
7980

8081
},
8182

83+
onContextLost: function(event) {
84+
// Find the relevant renderer:
85+
var claim = _.find(this.claimedPool, function(claimToken) {
86+
return claimToken.renderer.domElement === event.target;
87+
});
88+
if (!claim) {
89+
console.warn('Could not find lost context');
90+
return;
91+
}
92+
93+
// remove claim token
94+
this.claimedPool = _.without(this.claimedPool, claim);
95+
this.freePool.push(renderer);
96+
97+
// notify holder
98+
claim.onReclaim();
99+
},
100+
82101
});
83102

84103
module.exports = new RendererPool();

js/src/core/Renderer.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ var RendererView = RenderableView.extend({
128128
this.tick();
129129
},
130130

131-
unfreeze: function() {
132-
RenderableView.prototype.unfreeze.call(this);
131+
acquireRenderer: function() {
132+
RenderableView.prototype.acquireRenderer.call(this);
133133

134134
// We need to ensure that renderer properties are applied
135135
// (we have no idea where the renderer has been...)

js/src/renderers/WebGLRenderer.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ var Promise = require('bluebird');
99

1010
var RenderableModel = require('../_base/Renderable').RenderableModel;
1111
var RenderableView = require('../_base/Renderable').RenderableView;
12+
var ThreeModel = require('../_base/Three').ThreeModel;
1213

1314
var WebGLRendererModel = RenderableModel.extend({
1415

@@ -69,6 +70,17 @@ var WebGLRendererView = RenderableView.extend({
6970
console.log('WGLR(' + this.id + '): ' + str);
7071
},
7172

73+
acquireRenderer: function() {
74+
RenderableView.prototype.acquireRenderer.call(this);
75+
76+
// We need to ensure that renderer properties are applied
77+
// (we have no idea where the renderer has been...)
78+
var clearColor = ThreeModel.prototype.convertColorModelToThree(this.model.get('clearColor'));
79+
var clearOpacity = ThreeModel.prototype.convertFloatModelToThree(this.model.get('clearOpacity'));
80+
this.renderer.setClearColor(clearColor, clearOpacity);
81+
// TODO: Apply other model attributes
82+
},
83+
7284
//
7385
// Handlers
7486
//

0 commit comments

Comments
 (0)