Working through start of gl texture management for context-loss recovery

This commit is contained in:
Richard Davey 2023-10-13 16:52:48 +01:00
parent 059ff984a2
commit b4b364f183
7 changed files with 179 additions and 27 deletions

View file

@ -136,7 +136,7 @@ var Plane = new Class({
this.setViewHeight();
},
/**
/**
* Do not change this value. It has no effect other than to break things.
*
* @name Phaser.GameObjects.Plane#originX
@ -154,7 +154,7 @@ var Plane = new Class({
},
/**
/**
* Do not change this value. It has no effect other than to break things.
*
* @name Phaser.GameObjects.Plane#originY
@ -385,7 +385,8 @@ var Plane = new Class({
if (alpha2 === undefined) { alpha2 = 255; }
if (height === undefined) { height = 128; }
var gl = this.scene.sys.renderer.gl;
var renderer = this.scene.sys.renderer;
var gl = renderer.gl;
var glTexture = gl.createTexture();
@ -420,10 +421,12 @@ var Plane = new Class({
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(colors));
glTexture.isAlphaPremultiplied = true;
glTexture.isRenderTexture = false;
glTexture.width = 16;
glTexture.height = 16;
renderer.addToTextureCache(glTexture, 16, 16, 'Plane');
// glTexture.isAlphaPremultiplied = true;
// glTexture.isRenderTexture = false;
// glTexture.width = 16;
// glTexture.height = 16;
var texture = this.scene.sys.textures.addGLTexture(UUID(), glTexture, 16, 16);

View file

@ -225,12 +225,14 @@ var RenderTarget = new Class({
if (this.autoResize && (scaledWidth !== this.width || scaledHeight !== this.height))
{
console.log('RenderTarget.resize', width, height);
var renderer = this.renderer;
renderer.deleteFramebuffer(this.framebuffer);
renderer.deleteTexture(this.texture);
renderer.deleteFramebuffer(this.framebuffer);
width *= this.scale;
height *= this.scale;
@ -386,9 +388,12 @@ var RenderTarget = new Class({
renderer.off(Events.RESIZE, this.resize, this);
renderer.deleteFramebuffer(this.framebuffer);
console.log('RT.destroy');
renderer.deleteTexture(this.texture);
renderer.deleteFramebuffer(this.framebuffer);
this.renderer = null;
this.framebuffer = null;
this.texture = null;

View file

@ -636,6 +636,9 @@ var WebGLRenderer = new Class({
*/
this._debugCapture = false;
this.textureCache = [];
this.framebufferCache = [];
this.init(this.config);
},
@ -807,6 +810,8 @@ var WebGLRenderer = new Class({
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.addToTextureCache(tempTexture, 1, 1, 'MacFix' + index);
}
this.pipelines = new PipelineManager(this);
@ -1864,6 +1869,40 @@ var WebGLRenderer = new Class({
return this;
},
addToTextureCache: function (texture, width, height, source, isAlphaPremultiplied, isRenderTexture)
{
if (source === undefined) { source = 'Unknown'; }
if (isAlphaPremultiplied === undefined) { isAlphaPremultiplied = true; }
if (isRenderTexture === undefined) { isRenderTexture = false; }
this.textureCache.push({
texture: texture,
source: source,
width: width,
height: height,
isAlphaPremultiplied: isAlphaPremultiplied,
isRenderTexture: isRenderTexture
});
console.log('addToTextureCache', width, height, source, this.textureCache.length);
return this;
},
getTextureCacheEntry: function (texture)
{
// Find the entry in the textureCache
var index = this.textureCache.findIndex(function (element)
{
return (element.texture === texture);
});
if (index !== -1)
{
return this.textureCache[index];
}
},
/**
* Creates a texture from an image source. If the source is not valid it creates an empty texture.
*
@ -2013,10 +2052,14 @@ var WebGLRenderer = new Class({
gl.bindTexture(gl.TEXTURE_2D, currentTexture);
}
texture.isAlphaPremultiplied = pma;
texture.isRenderTexture = false;
texture.width = width;
texture.height = height;
this.addToTextureCache(texture, width, height, 'Unknown', pma, false);
// These properties used to be directly on the WebGLTexture, but now they're stored in the cache:
// texture.isAlphaPremultiplied = pma;
// texture.isRenderTexture = false;
// texture.width = width;
// texture.height = height;
return texture;
},
@ -2044,8 +2087,10 @@ var WebGLRenderer = new Class({
this.setFramebuffer(framebuffer);
renderTexture.isRenderTexture = true;
renderTexture.isAlphaPremultiplied = false;
var entry = this.getTextureCacheEntry(renderTexture);
entry.isRenderTexture = true;
entry.isAlphaPremultiplied = false;
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, renderTexture, 0);
@ -2063,6 +2108,7 @@ var WebGLRenderer = new Class({
throw new Error('Framebuffer status: ' + (errors[complete] || complete));
}
// TODO - REMOVE THIS
framebuffer.renderTexture = renderTexture;
if (addDepthStencilBuffer)
@ -2265,15 +2311,34 @@ var WebGLRenderer = new Class({
* @method Phaser.Renderer.WebGL.WebGLRenderer#deleteTexture
* @since 3.0.0
*
* @param {WebGLTexture} texture - The WebGL Texture to be deleted.
* @param {WebGLTexture} glTexture - The WebGL Texture to be deleted.
*
* @return {this} This WebGLRenderer instance.
*/
deleteTexture: function (texture)
deleteTexture: function (glTexture)
{
if (texture)
if (glTexture)
{
this.gl.deleteTexture(texture);
// Find the entry in the textureCache
var index = this.textureCache.findIndex(function (element)
{
return (element.texture === glTexture);
});
if (index !== -1)
{
var entry = this.textureCache[index];
this.textureCache.splice(index, 1);
this.gl.deleteTexture(entry.texture);
console.log('Texture Deleted from index', index);
}
else
{
console.warn('Texture not found in cache', glTexture);
}
}
return this;
@ -2296,6 +2361,8 @@ var WebGLRenderer = new Class({
return this;
}
console.log('deleteFramebuffer', framebuffer);
var gl = this.gl;
if (this.currentFramebuffer === framebuffer)
@ -2307,6 +2374,8 @@ var WebGLRenderer = new Class({
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
framebuffer.renderTexture = undefined;
// Check for a color attachment and remove it
var colorAttachment = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
@ -2314,8 +2383,14 @@ var WebGLRenderer = new Class({
{
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, null, 0);
// TODO: Check if this texture is used elsewhere. If not, delete it:
gl.deleteTexture(colorAttachment);
var colorEntry = this.getTextureCacheEntry(colorAttachment);
if (colorEntry)
{
this.deleteTexture(colorAttachment);
}
// gl.deleteTexture(colorAttachment);
}
// Check for a depth-stencil attachment and delete it
@ -2324,6 +2399,8 @@ var WebGLRenderer = new Class({
if (depthStencilAttachment !== null)
{
gl.deleteRenderbuffer(depthStencilAttachment);
console.log('deleteFramebuffer - delete render buffer', depthStencilAttachment);
}
gl.bindFramebuffer(gl.FRAMEBUFFER, null);

View file

@ -168,6 +168,8 @@ var LightPipeline = new Class({
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([ 127, 127, 255, 255 ]));
this.renderer.addToTextureCache(tempTexture, 1, 1, 'LightPipeline');
this.defaultNormalMap = { glTexture: tempTexture };
},

View file

@ -224,16 +224,20 @@ var PostFXPipeline = new Class({
*/
this.halfFrame2;
if (this.renderer.isBooted)
{
this.manager = this.renderer.pipelines;
this.pendingBoot = true;
this.boot();
}
// if (this.renderer.isBooted)
// {
// this.manager = this.renderer.pipelines;
// this.boot();
// }
},
boot: function ()
{
this.manager = this.renderer.pipelines;
WebGLPipeline.prototype.boot.call(this);
var utility = this.manager.UTILITY_PIPELINE;
@ -251,6 +255,34 @@ var PostFXPipeline = new Class({
{
targets[i].autoResize = true;
}
this.pendingBoot = false;
},
/**
* This method is called every time the Pipeline Manager makes this pipeline the currently active one.
*
* It binds the resources and shader needed for this pipeline, including setting the vertex buffer
* and attribute pointers.
*
* @method Phaser.Renderer.WebGL.WebGLPipeline#bind
* @fires Phaser.Renderer.WebGL.Pipelines.Events#BIND
* @since 3.0.0
*
* @param {Phaser.Renderer.WebGL.WebGLShader} [currentShader] - The shader to set as being current.
*
* @return {this} This WebGLPipeline instance.
*/
bind: function (currentShader)
{
if (this.pendingBoot)
{
console.log('PostFXPipeline booting');
this.boot();
}
WebGLPipeline.prototype.bind.call(this, currentShader);
},
onDraw: function (renderTarget)

View file

@ -99,6 +99,28 @@ var DynamicTexture = new Class({
*/
this.renderer = renderer;
/**
* The width of this Dynamic Texture.
*
* Treat this property as read-only. Use the `setSize` method to change the size.
*
* @name Phaser.Textures.DynamicTexture#width
* @type {number}
* @since 3.60.0
*/
this.width = width;
/**
* The height of this Dynamic Texture.
*
* Treat this property as read-only. Use the `setSize` method to change the size.
*
* @name Phaser.Textures.DynamicTexture#height
* @type {number}
* @since 3.60.0
*/
this.height = height;
/**
* This flag is set to 'true' during `beginDraw` and reset to 'false` in `endDraw`,
* allowing you to determine if this Dynamic Texture is batch drawing, or not.
@ -232,6 +254,8 @@ var DynamicTexture = new Class({
var frame = this.get();
var source = frame.source;
console.log('DT.setSize >>>', width, height, 'from', this.width, this.height);
if (width !== this.width || height !== this.height)
{
if (this.canvas)
@ -246,10 +270,17 @@ var DynamicTexture = new Class({
{
renderTarget.resize(width, height);
var e = this.renderer.getTextureCacheEntry(frame.glTexture);
console.log('DT.setSize e', e);
console.log('DT.setSize rt', frame, frame.glTexture);
console.log('DT.setSize 2', frame.glTexture === renderTarget.texture);
frame.glTexture = renderTarget.texture;
source.isRenderTexture = true;
source.isGLTexture = true;
source.glTexture = renderTarget.texture;
source.glTexture.flipY = true;
}

View file

@ -224,6 +224,8 @@ var TextureSource = new Class({
var height = this.height;
var scaleMode = this.scaleMode;
console.log('TextureSource', this.texture.key);
if (this.isCanvas)
{
this.glTexture = renderer.createCanvasTexture(image, false, flipY);