mirror of
https://github.com/photonstorm/phaser
synced 2024-11-10 07:04:31 +00:00
Restore WebGL context.
All textures and shaders should automatically recover from WebGL context loss. Dynamic textures will lose their contents, unfortunately, as the texture was stored on the GPU. Frame buffers still have some bugs to work out.
This commit is contained in:
parent
587b6e7bcd
commit
a0f066c543
5 changed files with 139 additions and 17 deletions
|
@ -24,6 +24,8 @@ var PointLightPipeline = require('./pipelines/PointLightPipeline');
|
||||||
var RopePipeline = require('./pipelines/RopePipeline');
|
var RopePipeline = require('./pipelines/RopePipeline');
|
||||||
var SinglePipeline = require('./pipelines/SinglePipeline');
|
var SinglePipeline = require('./pipelines/SinglePipeline');
|
||||||
var UtilityPipeline = require('./pipelines/UtilityPipeline');
|
var UtilityPipeline = require('./pipelines/UtilityPipeline');
|
||||||
|
var ArrayEach = require('../../utils/array/Each');
|
||||||
|
var ArrayRemove = require('../../utils/array/Remove');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @classdesc
|
* @classdesc
|
||||||
|
@ -143,6 +145,14 @@ var PipelineManager = new Class({
|
||||||
*/
|
*/
|
||||||
this.pipelines = new CustomMap();
|
this.pipelines = new CustomMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of all post-pipelines that are created by this manager.
|
||||||
|
*
|
||||||
|
* @name Phaser.Renderer.WebGL.PipelineManager#postPipelineInstances
|
||||||
|
* @type {Phaser.Renderer.WebGL.Pipelines.PostFXPipeline[]}
|
||||||
|
*/
|
||||||
|
this.postPipelineInstances = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default Game Object pipeline.
|
* The default Game Object pipeline.
|
||||||
*
|
*
|
||||||
|
@ -742,10 +752,28 @@ var PipelineManager = new Class({
|
||||||
newPipeline.gameObject = gameObject;
|
newPipeline.gameObject = gameObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.postPipelineInstances.push(newPipeline);
|
||||||
|
|
||||||
return newPipeline;
|
return newPipeline;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a PostFXPipeline instance from this Pipeline Manager.
|
||||||
|
*
|
||||||
|
* Note that the pipeline will not be flushed or destroyed, it's simply removed from
|
||||||
|
* this manager.
|
||||||
|
*
|
||||||
|
* @method Phaser.Renderer.WebGL.PipelineManager#removePostPipeline
|
||||||
|
* @since 3.80.0
|
||||||
|
*
|
||||||
|
* @param {Phaser.Renderer.WebGL.Pipelines.PostFXPipeline} pipeline - The pipeline instance to be removed.
|
||||||
|
*/
|
||||||
|
removePostPipeline: function (pipeline)
|
||||||
|
{
|
||||||
|
ArrayRemove(this.postPipelineInstances, pipeline);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a pipeline instance based on the given name.
|
* Removes a pipeline instance based on the given name.
|
||||||
*
|
*
|
||||||
|
@ -1264,6 +1292,10 @@ var PipelineManager = new Class({
|
||||||
{
|
{
|
||||||
pipeline.restoreContext();
|
pipeline.restoreContext();
|
||||||
});
|
});
|
||||||
|
ArrayEach(this.postPipelineInstances, function (pipeline)
|
||||||
|
{
|
||||||
|
pipeline.restoreContext();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* @license {@link https://opensource.org/licenses/MIT|MIT License}
|
* @license {@link https://opensource.org/licenses/MIT|MIT License}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var ArrayEach = require('../../utils/array/Each');
|
||||||
var ArrayRemove = require('../../utils/array/Remove');
|
var ArrayRemove = require('../../utils/array/Remove');
|
||||||
var CameraEvents = require('../../cameras/2d/events');
|
var CameraEvents = require('../../cameras/2d/events');
|
||||||
var Class = require('../../utils/Class');
|
var Class = require('../../utils/Class');
|
||||||
|
@ -758,6 +759,69 @@ var WebGLRenderer = new Class({
|
||||||
|
|
||||||
canvas.addEventListener('webglcontextlost', this.contextLostHandler, false);
|
canvas.addEventListener('webglcontextlost', this.contextLostHandler, false);
|
||||||
|
|
||||||
|
this.contextRestoredHandler = function (event)
|
||||||
|
{
|
||||||
|
if (gl.isContextLost())
|
||||||
|
{
|
||||||
|
if (console)
|
||||||
|
{
|
||||||
|
console.log('WebGL Context restored, but context is still lost');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear "current" settings so they can be set again.
|
||||||
|
_this.currentProgram = null;
|
||||||
|
_this.currentFramebuffer = null;
|
||||||
|
_this.setBlendMode(CONST.BlendModes.NORMAL);
|
||||||
|
|
||||||
|
// Settings we DON'T need to reset:
|
||||||
|
// Scissor is set during preRender.
|
||||||
|
// Mask is set during preRender.
|
||||||
|
// Camera mask is set during preRenderCamera.
|
||||||
|
|
||||||
|
// Restore GL flags.
|
||||||
|
gl.disable(gl.BLEND);
|
||||||
|
gl.disable(gl.DEPTH_TEST);
|
||||||
|
gl.enable(gl.CULL_FACE);
|
||||||
|
|
||||||
|
// Restore wrapped GL objects.
|
||||||
|
// Order matters, as some wrappers depend on others.
|
||||||
|
var wrapperCreateResource = function (wrapper)
|
||||||
|
{
|
||||||
|
wrapper.createResource();
|
||||||
|
};
|
||||||
|
ArrayEach(_this.glTextureWrappers, wrapperCreateResource);
|
||||||
|
ArrayEach(_this.glBufferWrappers, wrapperCreateResource);
|
||||||
|
ArrayEach(_this.glFramebufferWrappers, wrapperCreateResource);
|
||||||
|
ArrayEach(_this.glProgramWrappers, wrapperCreateResource);
|
||||||
|
ArrayEach(_this.glAttribLocationWrappers, wrapperCreateResource);
|
||||||
|
ArrayEach(_this.glUniformLocationWrappers, wrapperCreateResource);
|
||||||
|
|
||||||
|
// Create temporary textures.
|
||||||
|
_this.createTemporaryTextures();
|
||||||
|
|
||||||
|
// Restore pipelines.
|
||||||
|
// _this.pipelines.rebind();
|
||||||
|
_this.pipelines.restoreContext();
|
||||||
|
|
||||||
|
// Apply resize.
|
||||||
|
_this.resize(_this.width, _this.height);
|
||||||
|
|
||||||
|
// Context has been restored.
|
||||||
|
|
||||||
|
_this.contextLost = false;
|
||||||
|
|
||||||
|
if (console)
|
||||||
|
{
|
||||||
|
console.warn('WebGL Context restored. Renderer running again.');
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
canvas.addEventListener('webglcontextrestored', this.contextRestoredHandler, false);
|
||||||
|
|
||||||
// Set it back into the Game, so developers can access it from there too
|
// Set it back into the Game, so developers can access it from there too
|
||||||
game.context = gl;
|
game.context = gl;
|
||||||
|
|
||||||
|
@ -855,19 +919,7 @@ var WebGLRenderer = new Class({
|
||||||
|
|
||||||
this.textureIndexes = [];
|
this.textureIndexes = [];
|
||||||
|
|
||||||
// Create temporary WebGL textures to stop WebGL errors on mac os
|
this.createTemporaryTextures();
|
||||||
for (var index = 0; index < this.maxTextures; index++)
|
|
||||||
{
|
|
||||||
var tempTexture = gl.createTexture();
|
|
||||||
|
|
||||||
gl.activeTexture(gl.TEXTURE0 + index);
|
|
||||||
|
|
||||||
gl.bindTexture(gl.TEXTURE_2D, tempTexture);
|
|
||||||
|
|
||||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([ 0, 0, 255, 255 ]));
|
|
||||||
|
|
||||||
this.textureIndexes.push(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.pipelines = new PipelineManager(this);
|
this.pipelines = new PipelineManager(this);
|
||||||
|
|
||||||
|
@ -928,6 +980,27 @@ var WebGLRenderer = new Class({
|
||||||
this.resize(width, height);
|
this.resize(width, height);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create temporary WebGL textures to stop WebGL errors on mac os
|
||||||
|
*/
|
||||||
|
createTemporaryTextures: function ()
|
||||||
|
{
|
||||||
|
var gl = this.gl;
|
||||||
|
|
||||||
|
for (var index = 0; index < this.maxTextures; index++)
|
||||||
|
{
|
||||||
|
var tempTexture = gl.createTexture();
|
||||||
|
|
||||||
|
gl.activeTexture(gl.TEXTURE0 + index);
|
||||||
|
|
||||||
|
gl.bindTexture(gl.TEXTURE_2D, tempTexture);
|
||||||
|
|
||||||
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([ 0, 0, 255, 255 ]));
|
||||||
|
|
||||||
|
this.textureIndexes.push(index);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is only available in the Debug Build of Phaser, or a build with the
|
* This method is only available in the Debug Build of Phaser, or a build with the
|
||||||
* `WEBGL_DEBUG` flag set in the Webpack Config.
|
* `WEBGL_DEBUG` flag set in the Webpack Config.
|
||||||
|
|
|
@ -297,6 +297,7 @@ var WebGLShader = new Class({
|
||||||
if (reset === undefined) { reset = false; }
|
if (reset === undefined) { reset = false; }
|
||||||
|
|
||||||
var gl = this.gl;
|
var gl = this.gl;
|
||||||
|
var renderer = this.renderer;
|
||||||
var vertexSize = this.vertexSize;
|
var vertexSize = this.vertexSize;
|
||||||
var attributes = this.attributes;
|
var attributes = this.attributes;
|
||||||
var program = this.program;
|
var program = this.program;
|
||||||
|
@ -314,6 +315,10 @@ var WebGLShader = new Class({
|
||||||
|
|
||||||
if (reset)
|
if (reset)
|
||||||
{
|
{
|
||||||
|
if (location !== -1)
|
||||||
|
{
|
||||||
|
renderer.deleteAttribLocation(location);
|
||||||
|
}
|
||||||
var attribLocation = this.renderer.createAttribLocation(program, element.name);
|
var attribLocation = this.renderer.createAttribLocation(program, element.name);
|
||||||
|
|
||||||
if (attribLocation.webGLAttribLocation >= 0)
|
if (attribLocation.webGLAttribLocation >= 0)
|
||||||
|
@ -447,10 +452,18 @@ var WebGLShader = new Class({
|
||||||
*/
|
*/
|
||||||
syncUniforms: function ()
|
syncUniforms: function ()
|
||||||
{
|
{
|
||||||
ArrayEach(this.uniforms, function (uniform)
|
var gl = this.gl;
|
||||||
|
this.renderer.setProgram(this.program);
|
||||||
|
for (var name in this.uniforms)
|
||||||
{
|
{
|
||||||
uniform.setter.call(this.gl, uniform.location.webGLUniformLocation, uniform.value1, uniform.value2, uniform.value3, uniform.value4);
|
var uniform = this.uniforms[name];
|
||||||
});
|
|
||||||
|
// A uniform that hasn't been set doesn't need to be synced.
|
||||||
|
if (uniform.setter)
|
||||||
|
{
|
||||||
|
uniform.setter.call(gl, uniform.location.webGLUniformLocation, uniform.value1, uniform.value2, uniform.value3, uniform.value4);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -637,6 +637,8 @@ var PostFXPipeline = new Class({
|
||||||
this.halfFrame1 = null;
|
this.halfFrame1 = null;
|
||||||
this.halfFrame2 = null;
|
this.halfFrame2 = null;
|
||||||
|
|
||||||
|
this.manager.removePostPipeline(this);
|
||||||
|
|
||||||
WebGLPipeline.prototype.destroy.call(this);
|
WebGLPipeline.prototype.destroy.call(this);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -9,10 +9,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Wrappers = {
|
var Wrappers = {
|
||||||
|
WebGLAttribLocationWrapper: require('./WebGLAttribLocationWrapper'),
|
||||||
WebGLBufferWrapper: require('./WebGLBufferWrapper'),
|
WebGLBufferWrapper: require('./WebGLBufferWrapper'),
|
||||||
WebGLProgramWrapper: require('./WebGLProgramWrapper'),
|
WebGLProgramWrapper: require('./WebGLProgramWrapper'),
|
||||||
WebGLTextureWrapper: require('./WebGLTextureWrapper'),
|
WebGLTextureWrapper: require('./WebGLTextureWrapper'),
|
||||||
WebGLFramebufferWrapper: require('./WebGLFramebufferWrapper')
|
WebGLFramebufferWrapper: require('./WebGLFramebufferWrapper'),
|
||||||
|
WebGLUniformLocationWrapper: require('./WebGLUniformLocationWrapper')
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Wrappers;
|
module.exports = Wrappers;
|
||||||
|
|
Loading…
Reference in a new issue