Create WebGLFramebufferWrapper to encapsulate state.

This commit is contained in:
Ben Richards 2024-01-29 14:48:28 +13:00
parent b591c3674a
commit 68671f0d8a

View file

@ -0,0 +1,184 @@
var Class = require('../../../utils/Class');
/**
* Possible errors that can be thrown by `gl.checkFramebufferStatus()`.
*/
var errors = {
36054: 'Incomplete Attachment',
36055: 'Missing Attachment',
36057: 'Incomplete Dimensions',
36061: 'Framebuffer Unsupported'
};
/**
* @classdesc
* Wrapper for a WebGL frame buffer,
* containing all the information that was used to create it.
*
* A WebGLFramebuffer should never be exposed outside the WebGLRenderer,
* so the WebGLRenderer can handle context loss and other events
* without other systems having to be aware of it.
* Always use WebGLFramebufferWrapper instead.
*
* @method Phaser.Renderer.WebGL.WebGLRenderer#createFramebuffer
* @since 3.80.0
*
* @param {WebGLRenderingContext} gl - The WebGLRenderingContext to create the WebGLFramebuffer for.
* @param {number} width - If `addDepthStencilBuffer` is true, this controls the width of the depth stencil.
* @param {number} height - If `addDepthStencilBuffer` is true, this controls the height of the depth stencil.
* @param {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper} renderTexture - The color texture where the color pixels are written.
* @param {boolean} [addDepthStencilBuffer=false] - Create a Renderbuffer for the depth stencil?
*/
var WebGLFramebufferWrapper = new Class({
initialize: function WebGLFramebufferWrapper (renderer, width, height, renderTexture, addDepthStencilBuffer)
{
/**
* The WebGLFramebuffer being wrapped by this class.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLFramebufferWrapper#webGLFramebuffer
* @type {?WebGLFramebuffer}
* @default null
* @since 3.80.0
*/
this.webGLFramebuffer = null;
/**
* The WebGLRenderer instance that owns this WebGLFramebufferWrapper.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLFramebufferWrapper#renderer
* @type {Phaser.Renderer.WebGL.WebGLRenderer}
* @since 3.80.0
*/
this.renderer = renderer;
/**
* Width of the depth stencil.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLFramebufferWrapper#width
* @type {number}
* @since 3.80.0
*/
this.width = width;
/**
* Height of the depth stencil.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLFramebufferWrapper#height
* @type {number}
* @since 3.80.0
*/
this.height = height;
/**
* The color texture where the color pixels are written.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLFramebufferWrapper#renderTexture
* @type {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper}
* @since 3.80.0
*/
this.renderTexture = renderTexture;
/**
* Create a Renderbuffer for the depth stencil?
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLFramebufferWrapper#addDepthStencilBuffer
* @type {boolean}
* @default false
* @since 3.80.0
*/
this.addDepthStencilBuffer = !!addDepthStencilBuffer;
this.createResource();
},
/**
* Creates a WebGLFramebuffer from the given parameters.
*
* This is called automatically by the constructor. It may also be
* called again if the WebGLFramebuffer needs re-creating.
*
* @method Phaser.Renderer.WebGL.Wrappers.WebGLFramebufferWrapper#createResource
* @since 3.80.0
*/
createResource: function ()
{
var renderer = this.renderer;
var gl = renderer.gl;
var renderTexture = this.renderTexture;
var complete = 0;
var framebuffer = gl.createFramebuffer();
// This property must exist before calling `setFramebuffer`.
this.webGLFramebuffer = framebuffer;
renderer.setFramebuffer(this);
renderTexture.isRenderTexture = true;
renderTexture.isAlphaPremultiplied = false;
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, renderTexture.webGLTexture, 0);
complete = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if (complete !== gl.FRAMEBUFFER_COMPLETE)
{
throw new Error('Framebuffer status: ' + (errors[complete] || complete));
}
if (this.addDepthStencilBuffer)
{
var depthStencilBuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, depthStencilBuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, this.width, this.height);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer);
}
renderer.setFramebuffer(null);
},
/**
* Destroys this WebGLFramebufferWrapper.
*
* @method Phaser.Renderer.WebGL.Wrappers.WebGLFramebufferWrapper#destroy
* @since 3.80.0
*/
destroy: function ()
{
if (this.webGLFramebuffer === null)
{
return;
}
var gl = this.renderer.gl;
gl.bindFramebuffer(gl.FRAMEBUFFER, this.webGLFramebuffer);
this.renderTexture = null;
// Check for a color attachment and remove it
var colorAttachment = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
if (colorAttachment !== null)
{
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, null, 0);
gl.deleteTexture(colorAttachment);
}
// Check for a depth-stencil attachment and remove it
var depthStencilAttachment = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
if (depthStencilAttachment !== null)
{
gl.deleteRenderbuffer(depthStencilAttachment);
}
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.deleteFramebuffer(this.webGLFramebuffer);
this.webGLFramebuffer = null;
}
});
module.exports = WebGLFramebufferWrapper;