Merge pull request #6725 from phaserjs/webgl-wrappers

Merge WebGL Context Loss work
This commit is contained in:
Richard Davey 2024-02-02 12:36:57 +00:00 committed by GitHub
commit 56f4c89938
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
39 changed files with 2119 additions and 536 deletions

View file

@ -3,6 +3,7 @@
# New Features # New Features
* The Scale Manager has a new scale mode called `EXPAND`. This is inspired by the Expand mode in Godot: "Keep aspect ratio when stretching the screen, but keep neither the base width nor height. Depending on the screen aspect ratio, the viewport will either be larger in the horizontal direction (if the screen is wider than the base size) or in the vertical direction (if the screen is taller than the original size)" (thanks @rexrainbow) * The Scale Manager has a new scale mode called `EXPAND`. This is inspired by the Expand mode in Godot: "Keep aspect ratio when stretching the screen, but keep neither the base width nor height. Depending on the screen aspect ratio, the viewport will either be larger in the horizontal direction (if the screen is wider than the base size) or in the vertical direction (if the screen is taller than the original size)" (thanks @rexrainbow)
* Phaser now performs a [WebGL Context Restore](WebGLContextRestore.md) to keep the game running after losing WebGL context. This affects many parts of the rendering system, but everything should work just the same unless you're doing something very technical. See the link for more details.
# New Features - Base64 Loader # New Features - Base64 Loader

View file

@ -0,0 +1,231 @@
# Phaser 3.80.0 Change Log
Return to the [Change Log index](CHANGELOG-v3.80.md).
## WebGL Context Restore
Phaser now performs a WebGL context restore.
WebGL can lose context when the browser wants to reclaim resources. This happens most often when a browser tab is inactive. When it happens is beyond the control of web developers.
When context is lost, the game canvas goes blank. A lost context loses all the data that was sent to the WebGL system. It cannot do anything until the browser restores the context, usually when the user returns to their tab.
Phaser now restores this data, with a few exceptions, allowing your games to seamlessly resume. For the most part, your WebGL games should now simply recover when the browser restores the WebGL context.
Key concepts:
- `WebGLRenderer` emits `LOSE_WEBGL` and `RESTORE_WEBGL` events.
- Dynamic textures are cleared.
- WebGL objects are now enclosed in wrappers.
- You can test WebGL context restore with WebGL extensions.
- Supporting changes were made to the rendering system.
### Events
`Phaser.Renderers.WebGL.WebGLRenderer` now emits events that you can use to stay informed about context loss.
- `Phaser.Renderer.Events#LOSE_WEBGL` is emitted when context is lost. This would be a good time to pause the game, or otherwise avoid making changes that the player cannot see.
- `Phaser.Renderer.Events#RESTORE_WEBGL` is emitted when context is restored. This would be a good time to restore dynamic textures, and start things moving again.
### Dynamic Textures
Dynamic textures and render textures are stored on the GPU. When context is lost, the texture is erased. When context is restored, the texture is re-enabled, but it remains blank.
A render texture which is redrawn every frame will naturally redraw itself.
Textures which are drawn once, however, will stay blank. You should listen for the `RESTORE_WEBGL` event to know when to redraw them.
### WebGL Object Wrappers
WebGL objects are now wrapped. The wrapper holds the necessary information to automatically recreate the object when context is restored.
This is only relevant if you need deep access to the WebGL renderer.
Wrappers are created and managed by the `WebGLRenderer`. They have the following qualities:
- A property for the wrapped WebGL object, for use in rendering. This property should only be accessed within a call to WebGL; it may be changed within the wrapper.
- `createResource()`, which will create a new WebGL object from stored information.
- `destroy()`, which will remove the object. Do not call this directly; it is managed by the `WebGLRenderer`.
The following wrappers are available in the `Phaser.Renderer.WebGL.Wrappers` namespace:
- `WebGLAttribLocationWrapper`
- `WebGLBufferWrapper`
- `WebGLFramebufferWrapper`
- `WebGLProgramWrapper`
- `WebGLTextureWrapper`
- `WebGLUniformLocationWrapper`
### Testing Context Restore
You can test context loss and restore with a built-in WebGL extension. The following code snippet should be useful for testing purposes. It shows how to get the built-in extension, and simulate losing and restoring the context after 1 and 2 seconds respectively.
```js
const webGLLoseContextExtension = game.renderer.getExtension('WEBGL_lose_context');
setTimeout(function () {
webGLLoseContextExtension.loseContext();
setTimeout(function () {
webGLLoseContextExtension.restoreContext();
}, 1000)
}, 1000);
```
### Supporting Changes
Several changes were made to the rendering system to support these improvements. In particular, many properties were changed to use wrappers instead of raw WebGL objects. The full list of changes is as follows:
- `Phaser.FX.Displacement`
- `glTexture` property type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `BatchChar`
- Constructor:
- `texture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `Phaser.GameObjects.Shader`
- `vertexBuffer` property type changed from `WebGLBuffer` to `WebGLBufferWrapper`
- `program` property type changed from `WebGLProgram` to `WebGLProgramWrapper`
- `framebuffer` property type changed from `WebGLFramebuffer` to `WebGLFramebufferWrapper`
- `glTexture` property type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `#initUniforms` method:
- `texture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `Phaser.GameObjects.TileSprite`
- `fillPattern` property type changed from `?(WebGLTexture|CanvasPattern)` to `?(WebGLTextureWrapper|CanvasPattern)`
- `Phaser.Renderer.WebGL.PipelineManager`
- Added property `postPipelineInstances` of type `PostFXPipeline[]`
- Added method `removePostPipeline(pipeline: PostFXPipeline)`
- Added method `restoreContext()`, used after context is restored
- `Phaser.Renderer.WebGL.RenderTarget`
- `framebuffer` property type changed from `WebGLFramebuffer` to `WebGLFramebufferWrapper`
- `texture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `#unbind` method:
- Return type changed from `WebGLFramebuffer` to `WebGLFramebufferWrapper`
- `Phaser.Renderer.WebGL.WebGLPipeline`
- `vertexBuffer` property type changed from `WebGLBuffer` to `WebGLBufferWrapper`
- `activeBuffer` property type changed from `WebGLBuffer` to `WebGLBufferWrapper`
- `currentTexture` property type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `activeTextures` property type changed from `WebGLTexture[]` to `WebGLTextureWrapper[]`
- `#setShader` method:
- `vertexBuffer` parameter type changed from `WebGLBuffer` to `WebGLBufferWrapper`
- `#createBatch` method:
- `texture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `#addTextureToBatch` method:
- `texture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `#pushBatch` method:
- `texture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- Added method `restoreContext()`, used after context is restored
- `#setVertexBuffer` method:
- `buffer` parameter type changed from `WebGLBuffer` to `WebGLBufferWrapper`
- `#batchQuad` method:
- `texture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `#batchTri` method:
- `texture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `#drawFillRect` method:
- `texture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `#setTexture2D` method:
- `texture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `#bindTexture` method:
- `texture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `Phaser.Renderer.WebGL.WebGLRenderer`
- Added property `glBufferWrappers` of type `WebGLBufferWrapper[]`
- Added property `glProgramWrappers` of type `WebGLProgramWrapper[]`
- Added property `glTextureWrappers` of type `WebGLTextureWrapper[]`
- Added property `glFramebufferWrappers` of type `WebGLFramebufferWrapper[]`
- Added property `glAttribLocationWrappers` of type `WebGLAttribLocationWrapper[]`
- Added property `glUniformLocationWrappers` of type `WebGLUniformLocationWrapper[]`
- `currentFramebuffer` property type changed from `WebGLFramebuffer` to `WebGLFramebufferWrapper`
- `fboStack` property type changed from `WebGLFramebuffer[]` to `WebGLFramebufferWrapper[]`
- `currentProgram` property type changed from `WebGLProgram` to `WebGLProgramWrapper`
- `blankTexture` property type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `whiteTexture` property type changed from `WebGLTexture` to `WebGLTextureWrapper`
- Added method `createTemporaryTextures()`, used when booting on MacOS
- `#pushFramebuffer` method:
- `framebuffer` parameter changed from `WebGLFramebuffer` to `WebGLFramebufferWrapper`
- `texture` parameter changed from `WebGLTexture` to `WebGLTextureWrapper`
- `#setFramebuffer` method:
- `framebuffer` parameter changed from `WebGLFramebuffer` to `WebGLFramebufferWrapper`
- `texture` parameter changed from `WebGLTexture` to `WebGLTextureWrapper`
- `#popFramebuffer` method:
- Return type changed from `WebGLFramebuffer` to `WebGLFramebufferWrapper`
- `#setProgram` method:
- `program` parameter changed from `WebGLProgram` to `WebGLFramebufferWrapper`
- `#createTextureFromSource` method:
- Return type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `#createTexture2D` method:
- `width` parameter made optional
- `height` parameter made optional
- Return type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `#createFramebuffer` method:
- `texture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- Return type changed from `WebGLFramebuffer` to `WebGLFramebufferWrapper`
- `#createProgram` method:
- Return type changed from `WebGLProgram` to `WebGLProgramWrapper`
- `#createVertexBuffer` method:
- Return type changed from `WebGLBuffer` to `WebGLBufferWrapper`
- Added method `createAttribLocation`
- Added method `createUniformLocation`
- `#createIndexBuffer` method:
- Return type changed from `WebGLBuffer` to `WebGLBufferWrapper`
- `#deleteTexture` method:
- `texture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `#deleteFramebuffer` method:
- `framebuffer` parameter type changed from `WebGLFramebuffer` to `WebGLFramebufferWrapper`
- `#deleteProgram` method:
- `program` parameter type changed from `WebGLProgram` to `WebGLProgramWrapper`
- Added method `deleteAttribLocation`
- Added method `deleteUniformLocation`
- `#deleteBuffer` method:
- `vertexBuffer` parameter type changed from `WebGLBuffer` to `WebGLBufferWrapper`
- `#snapshotFramebuffer` method:
- `framebuffer` parameter changed from `WebGLFramebuffer` to `WebGLFramebufferWrapper`
- `#canvasToTexture` method:
- `dstTexture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- Return type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `#createCanvasTexture` method:
- Return type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `#updateCanvasTexture` method:
- `dstTexture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- Return type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `#createVideoTexture` method:
- Return type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `#updateCanvasTexture` method:
- `dstTexture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- Return type changed from `WebGLTexture` to `WebGLTextureWrapper`
- Added method `createUint8ArrayTexture`
- `#setTextureFilter` method:
- `texture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `Phaser.Renderers.WebGL.WebGLShader`
- `program` property type changed from `WebGLProgram` to `WebGLProgramWrapper`
- Added method `syncUniforms` for use during context recovery
- `Phaser.Renderers.WebGL.Pipelines.MultiPipeline`
- `#batchTexture` method:
- `texture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `Phaser.Renderers.WebGL.Pipelines.PreFXPipeline`
- `quadVertexBuffer` property type changed from `WebGLBuffer` to `WebGLBufferWrapper`
- `#batchQuad` method:
- `texture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `Phaser.Renderers.WebGL.Pipelines.DisplacementFXPipeline`
- `glTexture` property type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `WebGLPipelineAttribute`
- `location` property changed from `number` to `-1|WebGLAttribLocationWrapper`
- `WebGLPipelineBatchEntry`
- `texture` property changed from `WebGLTexture` to `WebGLTextureWrapper`
- `WebGLPipelineUniformsConfig`
- Added property `setter` of type `?function` for use in restoring context
- `Phaser.Textures.DynamicTexture`
- `#getWebGLTexture` method:
- Return type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `Phaser.Textures.Frame`
- `glTexture` property type changed from `WebGLTexture` to `WebGLTextureWrapper`
- Property is now read-only
- `Phaser.Textures.Texture`
- Constructor
- `source` parameter type options added `WebGLTextureWrapper`
- `Phaser.Textures.TextureManager`
- `#addGLTexture` method:
- `glTexture` parameter type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `width` parameter removed
- `height` parameter removed
- Added method `addUint8Array` for creating textures from raw colour data
- `Phaser.Textures.TextureSource`
- `glTexture` property type changed from `WebGLTexture` to `WebGLTextureWrapper`
- `Phaser.Tilemaps.Tileset`
- `glTexture` property type changed from `WebGLTexture` to `WebGLTextureWrapper`

View file

@ -73,10 +73,10 @@ var Displacement = new Class({
this.y = y; this.y = y;
/** /**
* The underlying WebGLTexture used for displacement. * The underlying texture used for displacement.
* *
* @name Phaser.FX.Displacement#glTexture * @name Phaser.FX.Displacement#glTexture
* @type {WebGLTexture} * @type {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper}
* @since 3.60.0 * @since 3.60.0
*/ */
this.glTexture; this.glTexture;

View file

@ -24,7 +24,7 @@
* @param {number} tintBL - Bottom-left tint value. * @param {number} tintBL - Bottom-left tint value.
* @param {number} tintBR - Bottom-right tint value. * @param {number} tintBR - Bottom-right tint value.
* @param {number} tintEffect - The tint effect mode. * @param {number} tintEffect - The tint effect mode.
* @param {WebGLTexture} texture - The WebGL texture. * @param {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper} texture - The texture.
* @param {number} textureUnit - The texture unit. * @param {number} textureUnit - The texture unit.
*/ */
var BatchChar = function (pipeline, src, char, glyph, offsetX, offsetY, calcMatrix, roundPixels, tintTL, tintTR, tintBL, tintBR, tintEffect, texture, textureUnit) var BatchChar = function (pipeline, src, char, glyph, offsetX, offsetY, calcMatrix, roundPixels, tintTL, tintTR, tintBL, tintBR, tintEffect, texture, textureUnit)

View file

@ -385,17 +385,6 @@ var Plane = new Class({
if (alpha2 === undefined) { alpha2 = 255; } if (alpha2 === undefined) { alpha2 = 255; }
if (height === undefined) { height = 128; } if (height === undefined) { height = 128; }
var gl = this.scene.sys.renderer.gl;
var glTexture = gl.createTexture();
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, glTexture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
// Let's assume 16x16 for our texture size and 8x8 cell size // Let's assume 16x16 for our texture size and 8x8 cell size
var c1 = IntegerToRGB(color1); var c1 = IntegerToRGB(color1);
@ -418,21 +407,10 @@ var Plane = new Class({
} }
} }
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(colors)); var texture = this.scene.sys.textures.addUint8Array(UUID(), new Uint8Array(colors), 16, 16);
glTexture.isAlphaPremultiplied = true;
glTexture.isRenderTexture = false;
glTexture.width = 16;
glTexture.height = 16;
var texture = this.scene.sys.textures.addGLTexture(UUID(), glTexture, 16, 16);
this.removeCheckerboard(); this.removeCheckerboard();
this._checkerboard = texture;
gl.bindTexture(gl.TEXTURE_2D, null);
this.setTexture(texture); this.setTexture(texture);
this.setSizeToFrame(); this.setSizeToFrame();

View file

@ -12,6 +12,7 @@ var Extend = require('../../utils/object/Extend');
var SetValue = require('../../utils/object/SetValue'); var SetValue = require('../../utils/object/SetValue');
var ShaderRender = require('./ShaderRender'); var ShaderRender = require('./ShaderRender');
var TransformMatrix = require('../components/TransformMatrix'); var TransformMatrix = require('../components/TransformMatrix');
var ArrayEach = require('../../utils/array/Each');
/** /**
* @classdesc * @classdesc
@ -160,7 +161,7 @@ var Shader = new Class({
* The WebGL vertex buffer object this shader uses. * The WebGL vertex buffer object this shader uses.
* *
* @name Phaser.GameObjects.Shader#vertexBuffer * @name Phaser.GameObjects.Shader#vertexBuffer
* @type {WebGLBuffer} * @type {Phaser.Renderer.WebGL.Wrappers.WebGLBufferWrapper}
* @since 3.17.0 * @since 3.17.0
*/ */
this.vertexBuffer = renderer.createVertexBuffer(this.vertexData.byteLength, this.gl.STREAM_DRAW); this.vertexBuffer = renderer.createVertexBuffer(this.vertexData.byteLength, this.gl.STREAM_DRAW);
@ -169,7 +170,7 @@ var Shader = new Class({
* The WebGL shader program this shader uses. * The WebGL shader program this shader uses.
* *
* @name Phaser.GameObjects.Shader#program * @name Phaser.GameObjects.Shader#program
* @type {WebGLProgram} * @type {Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper}
* @since 3.17.0 * @since 3.17.0
*/ */
this.program = null; this.program = null;
@ -306,17 +307,17 @@ var Shader = new Class({
* This property is only set if you have called `Shader.setRenderToTexture`. * This property is only set if you have called `Shader.setRenderToTexture`.
* *
* @name Phaser.GameObjects.Shader#framebuffer * @name Phaser.GameObjects.Shader#framebuffer
* @type {?WebGLFramebuffer} * @type {?Phaser.Renderer.WebGL.Wrappers.WebGLFramebufferWrapper}
* @since 3.19.0 * @since 3.19.0
*/ */
this.framebuffer = null; this.framebuffer = null;
/** /**
* A reference to the WebGLTexture this Shader is rendering to. * A reference to the WebGLTextureWrapper this Shader is rendering to.
* This property is only set if you have called `Shader.setRenderToTexture`. * This property is only set if you have called `Shader.setRenderToTexture`.
* *
* @name Phaser.GameObjects.Shader#glTexture * @name Phaser.GameObjects.Shader#glTexture
* @type {?WebGLTexture} * @type {?Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper}
* @since 3.19.0 * @since 3.19.0
*/ */
this.glTexture = null; this.glTexture = null;
@ -439,7 +440,7 @@ var Shader = new Class({
if (key) if (key)
{ {
this.texture = this.scene.sys.textures.addGLTexture(key, this.glTexture, width, height); this.texture = this.scene.sys.textures.addGLTexture(key, this.glTexture);
} }
} }
@ -498,15 +499,15 @@ var Shader = new Class({
if (this.program) if (this.program)
{ {
gl.deleteProgram(this.program); renderer.deleteProgram(this.program);
} }
var program = renderer.createProgram(this.shader.vertexSrc, this.shader.fragmentSrc); var program = renderer.createProgram(this.shader.vertexSrc, this.shader.fragmentSrc);
// The default uniforms available within the vertex shader // The default uniforms available within the vertex shader
gl.uniformMatrix4fv(gl.getUniformLocation(program, 'uViewMatrix'), false, this.viewMatrix); gl.uniformMatrix4fv(gl.getUniformLocation(program.webGLProgram, 'uViewMatrix'), false, this.viewMatrix);
gl.uniformMatrix4fv(gl.getUniformLocation(program, 'uProjectionMatrix'), false, this.projectionMatrix); gl.uniformMatrix4fv(gl.getUniformLocation(program.webGLProgram, 'uProjectionMatrix'), false, this.projectionMatrix);
gl.uniform2f(gl.getUniformLocation(program, 'uResolution'), this.width, this.height); gl.uniform2f(gl.getUniformLocation(program.webGLProgram, 'uResolution'), this.width, this.height);
this.program = program; this.program = program;
@ -607,7 +608,7 @@ var Shader = new Class({
renderer.setProgram(program); renderer.setProgram(program);
gl.uniformMatrix4fv(gl.getUniformLocation(program, 'uProjectionMatrix'), false, this.projectionMatrix); gl.uniformMatrix4fv(gl.getUniformLocation(program.webGLProgram, 'uProjectionMatrix'), false, this.projectionMatrix);
this._rendererWidth = right; this._rendererWidth = right;
this._rendererHeight = bottom; this._rendererHeight = bottom;
@ -625,7 +626,6 @@ var Shader = new Class({
*/ */
initUniforms: function () initUniforms: function ()
{ {
var gl = this.gl;
var map = this.renderer.glFuncMap; var map = this.renderer.glFuncMap;
var program = this.program; var program = this.program;
@ -638,7 +638,7 @@ var Shader = new Class({
var type = uniform.type; var type = uniform.type;
var data = map[type]; var data = map[type];
uniform.uniformLocation = gl.getUniformLocation(program, key); uniform.uniformLocation = this.renderer.createUniformLocation(program, key);
if (type !== 'sampler2D') if (type !== 'sampler2D')
{ {
@ -650,7 +650,7 @@ var Shader = new Class({
}, },
/** /**
* Sets a sampler2D uniform on this shader where the source texture is a WebGLTexture. * Sets a sampler2D uniform on this shader where the source texture is a WebGLTextureBuffer.
* *
* This allows you to feed the output from one Shader into another: * This allows you to feed the output from one Shader into another:
* *
@ -672,7 +672,7 @@ var Shader = new Class({
* @since 3.19.0 * @since 3.19.0
* *
* @param {string} uniformKey - The key of the sampler2D uniform to be updated, i.e. `iChannel0`. * @param {string} uniformKey - The key of the sampler2D uniform to be updated, i.e. `iChannel0`.
* @param {WebGLTexture} texture - A WebGLTexture reference. * @param {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper} texture - A texture reference.
* @param {number} width - The width of the texture. * @param {number} width - The width of the texture.
* @param {number} height - The height of the texture. * @param {number} height - The height of the texture.
* @param {number} [textureIndex=0] - The texture index. * @param {number} [textureIndex=0] - The texture index.
@ -908,7 +908,7 @@ var Shader = new Class({
var gl = this.gl; var gl = this.gl;
gl.activeTexture(gl.TEXTURE0 + this._textureCount); gl.activeTexture(gl.TEXTURE0 + this._textureCount);
gl.bindTexture(gl.TEXTURE_2D, uniform.value); gl.bindTexture(gl.TEXTURE_2D, uniform.value.webGLTexture);
// Extended texture data // Extended texture data
@ -916,6 +916,8 @@ var Shader = new Class({
if (data && !uniform.value.isRenderTexture) if (data && !uniform.value.isRenderTexture)
{ {
var wrapper = uniform.value;
// https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texImage2D // https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texImage2D
// mag / minFilter can be: gl.LINEAR, gl.LINEAR_MIPMAP_LINEAR or gl.NEAREST // mag / minFilter can be: gl.LINEAR, gl.LINEAR_MIPMAP_LINEAR or gl.NEAREST
@ -944,6 +946,8 @@ var Shader = new Class({
// texImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, ArrayBufferView? pixels) // texImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, ArrayBufferView? pixels)
gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, border, format, gl.UNSIGNED_BYTE, null); gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, border, format, gl.UNSIGNED_BYTE, null);
wrapper.width = width;
wrapper.height = height;
} }
else else
{ {
@ -955,12 +959,19 @@ var Shader = new Class({
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT);
// Update texture wrapper.
wrapper.magFilter = magFilter;
wrapper.minFilter = minFilter;
wrapper.wrapS = wrapS;
wrapper.wrapT = wrapT;
wrapper.format = format;
wrapper.flipY = !!data.flipY;
wrapper.pixels = uniform.source;
} }
this.renderer.setProgram(this.program); this.renderer.setProgram(this.program);
gl.uniform1i(uniform.uniformLocation, this._textureCount);
this._textureCount++; this._textureCount++;
}, },
@ -1002,32 +1013,32 @@ var Shader = new Class({
{ {
if (uniform.glMatrix) if (uniform.glMatrix)
{ {
glFunc.call(gl, location, uniform.transpose, value); glFunc.call(gl, location.webGLUniformLocation, uniform.transpose, value);
} }
else else
{ {
glFunc.call(gl, location, value); glFunc.call(gl, location.webGLUniformLocation, value);
} }
} }
else if (length === 2) else if (length === 2)
{ {
glFunc.call(gl, location, value.x, value.y); glFunc.call(gl, location.webGLUniformLocation, value.x, value.y);
} }
else if (length === 3) else if (length === 3)
{ {
glFunc.call(gl, location, value.x, value.y, value.z); glFunc.call(gl, location.webGLUniformLocation, value.x, value.y, value.z);
} }
else if (length === 4) else if (length === 4)
{ {
glFunc.call(gl, location, value.x, value.y, value.z, value.w); glFunc.call(gl, location.webGLUniformLocation, value.x, value.y, value.z, value.w);
} }
else if (uniform.type === 'sampler2D') else if (uniform.type === 'sampler2D')
{ {
gl.activeTexture(gl.TEXTURE0 + textureCount); gl.activeTexture(gl.TEXTURE0 + textureCount);
gl.bindTexture(gl.TEXTURE_2D, value); gl.bindTexture(gl.TEXTURE_2D, value.webGLTexture);
gl.uniform1i(location, textureCount); gl.uniform1i(location.webGLUniformLocation, textureCount);
textureCount++; textureCount++;
} }
@ -1074,10 +1085,11 @@ var Shader = new Class({
// Update vertex shader uniforms // Update vertex shader uniforms
gl.useProgram(program); gl.useProgram(program.webGLProgram);
gl.uniformMatrix4fv(gl.getUniformLocation(program, 'uViewMatrix'), false, vm); gl.uniformMatrix4fv(gl.getUniformLocation(program.webGLProgram, 'uViewMatrix'), false, vm);
gl.uniform2f(gl.getUniformLocation(program, 'uResolution'), this.width, this.height); gl.uniformMatrix4fv(gl.getUniformLocation(program.webGLProgram, 'uProjectionMatrix'), false, this.projectionMatrix);
gl.uniform2f(gl.getUniformLocation(program.webGLProgram, 'uResolution'), this.width, this.height);
// Update fragment shader uniforms // Update fragment shader uniforms
@ -1135,9 +1147,9 @@ var Shader = new Class({
gl.clear(gl.COLOR_BUFFER_BIT); gl.clear(gl.COLOR_BUFFER_BIT);
} }
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer.webGLBuffer);
var location = gl.getAttribLocation(program, 'inPosition'); var location = gl.getAttribLocation(program.webGLProgram, 'inPosition');
if (location !== -1) if (location !== -1)
{ {
@ -1204,14 +1216,14 @@ var Shader = new Class({
*/ */
preDestroy: function () preDestroy: function ()
{ {
var gl = this.gl; var renderer = this.renderer;
gl.deleteProgram(this.program); renderer.deleteProgram(this.program);
gl.deleteBuffer(this.vertexBuffer); renderer.deleteBuffer(this.vertexBuffer);
if (this.renderToTexture) if (this.renderToTexture)
{ {
this.renderer.deleteFramebuffer(this.framebuffer); renderer.deleteFramebuffer(this.framebuffer);
this.texture.destroy(); this.texture.destroy();
@ -1219,6 +1231,12 @@ var Shader = new Class({
this.glTexture = null; this.glTexture = null;
this.texture = null; this.texture = null;
} }
ArrayEach(this.uniforms, function (uniform)
{
renderer.deleteUniformLocation(uniform.uniformLocation);
uniform.uniformLocation = null;
});
} }
}); });

View file

@ -1437,8 +1437,7 @@ var Text = new Class({
if (typeof WEBGL_DEBUG) if (typeof WEBGL_DEBUG)
{ {
// eslint-disable-next-line camelcase this.frame.glTexture.spectorMetadata = { textureKey: 'Text Game Object' };
this.frame.glTexture.__SPECTOR_Metadata = { textureKey: 'Text Game Object' };
} }
} }

View file

@ -287,10 +287,10 @@ var TileSprite = new Class({
/** /**
* The texture that the Tile Sprite is rendered to, which is then rendered to a Scene. * The texture that the Tile Sprite is rendered to, which is then rendered to a Scene.
* In WebGL this is a WebGLTexture. In Canvas it's a Canvas Fill Pattern. * In WebGL this is a WebGLTextureWrapper. In Canvas it's a Canvas Fill Pattern.
* *
* @name Phaser.GameObjects.TileSprite#fillPattern * @name Phaser.GameObjects.TileSprite#fillPattern
* @type {?(WebGLTexture|CanvasPattern)} * @type {?(Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper|CanvasPattern)}
* @since 3.12.0 * @since 3.12.0
*/ */
this.fillPattern = null; this.fillPattern = null;
@ -471,8 +471,7 @@ var TileSprite = new Class({
if (typeof WEBGL_DEBUG) if (typeof WEBGL_DEBUG)
{ {
// eslint-disable-next-line camelcase this.fillPattern.spectorMetadata = { textureKey: 'TileSprite Game Object' };
this.fillPattern.__SPECTOR_Metadata = { textureKey: 'TileSprite Game Object' };
} }
} }
else else

View file

@ -0,0 +1,30 @@
/**
* @author Benjamin D. Richards <benjamindrichards@gmail.com>
* @copyright 2013-2023 Photon Storm Ltd.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
/**
* The Lose WebGL Event.
*
* This event is dispatched by the WebGLRenderer when the WebGL context
* is lost.
*
* Context can be lost for a variety of reasons, like leaving the browser tab.
* The game canvas DOM object will dispatch `webglcontextlost`.
* All WebGL resources get wiped, and the context is reset.
*
* While WebGL is lost, the game will continue to run, but all WebGL resources
* are lost, and new ones cannot be created.
*
* Once the context is restored and the renderer has automatically restored
* the state, the renderer will emit a `RESTORE_WEBGL` event. At that point,
* it is safe to continue.
*
* @event Phaser.Renderer.Events#LOSE_WEBGL
* @type {string}
* @since 3.80.0
*
* @param {Phaser.Renderer.WebGL.WebGLRenderer} renderer - the renderer that owns the WebGL context
*/
module.exports = 'losewebgl';

View file

@ -0,0 +1,33 @@
/**
* @author Benjamin D. Richards <benjamindrichards@gmail.com>
* @copyright 2013-2023 Photon Storm Ltd.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
/**
* The Restore WebGL Event.
*
* This event is dispatched by the WebGLRenderer when the WebGL context
* is restored.
*
* It is dispatched after all WebGL resources have been recreated.
* Most resources should come back automatically, but you will need to redraw
* dynamic textures that were GPU bound.
* Listen to this event to know when you can safely do that.
*
* Context can be lost for a variety of reasons, like leaving the browser tab.
* The game canvas DOM object will dispatch `webglcontextlost`.
* All WebGL resources get wiped, and the context is reset.
*
* Once the context is restored, the canvas will dispatch
* `webglcontextrestored`. Phaser uses this to re-create necessary resources.
* Please wait for Phaser to dispatch the `RESTORE_WEBGL` event before
* re-creating any resources of your own.
*
* @event Phaser.Renderer.Events#RESTORE_WEBGL
* @type {string}
* @since 3.80.0
*
* @param {Phaser.Renderer.WebGL.WebGLRenderer} renderer - the renderer that owns the WebGL context
*/
module.exports = 'restorewebgl';

View file

@ -10,9 +10,11 @@
module.exports = { module.exports = {
LOSE_WEBGL: require('./LOSE_WEBGL_EVENT'),
POST_RENDER: require('./POST_RENDER_EVENT'), POST_RENDER: require('./POST_RENDER_EVENT'),
PRE_RENDER: require('./PRE_RENDER_EVENT'), PRE_RENDER: require('./PRE_RENDER_EVENT'),
RENDER: require('./RENDER_EVENT'), RENDER: require('./RENDER_EVENT'),
RESIZE: require('./RESIZE_EVENT') RESIZE: require('./RESIZE_EVENT'),
RESTORE_WEBGL: require('./RESTORE_WEBGL_EVENT')
}; };

View file

@ -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.
* *
@ -1248,6 +1276,28 @@ var PipelineManager = new Class({
return this.set(this.FX_PIPELINE); return this.set(this.FX_PIPELINE);
}, },
/**
* Restore WebGL resources after context was lost.
*
* Calls `rebind` on this Pipeline Manager.
* Then calls `restoreContext` on each pipeline in turn.
*
* @method Phaser.Renderer.WebGL.PipelineManager#restoreContext
* @since 3.80.0
*/
restoreContext: function ()
{
this.rebind();
this.pipelines.each(function (_, pipeline)
{
pipeline.restoreContext();
});
ArrayEach(this.postPipelineInstances, function (pipeline)
{
pipeline.restoreContext();
});
},
/** /**
* Use this to reset the gl context to the state that Phaser requires to continue rendering. * Use this to reset the gl context to the state that Phaser requires to continue rendering.
* *

View file

@ -52,23 +52,23 @@ var RenderTarget = new Class({
this.renderer = renderer; this.renderer = renderer;
/** /**
* The WebGLFramebuffer of this Render Target. * The Framebuffer of this Render Target.
* *
* This is created in the `RenderTarget.resize` method. * This is created in the `RenderTarget.resize` method.
* *
* @name Phaser.Renderer.WebGL.RenderTarget#framebuffer * @name Phaser.Renderer.WebGL.RenderTarget#framebuffer
* @type {WebGLFramebuffer} * @type {Phaser.Renderer.WebGL.Wrappers.WebGLFramebufferWrapper}
* @since 3.50.0 * @since 3.50.0
*/ */
this.framebuffer = null; this.framebuffer = null;
/** /**
* The WebGLTexture of this Render Target. * The WebGLTextureWrapper of this Render Target.
* *
* This is created in the `RenderTarget.resize` method. * This is created in the `RenderTarget.resize` method.
* *
* @name Phaser.Renderer.WebGL.RenderTarget#texture * @name Phaser.Renderer.WebGL.RenderTarget#texture
* @type {WebGLTexture} * @type {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper}
* @since 3.50.0 * @since 3.50.0
*/ */
this.texture = null; this.texture = null;
@ -379,7 +379,7 @@ var RenderTarget = new Class({
* *
* @param {boolean} [flush=false] - Flush the WebGL Renderer before unbinding? * @param {boolean} [flush=false] - Flush the WebGL Renderer before unbinding?
* *
* @return {WebGLFramebuffer} The Framebuffer that was set, or `null` if there aren't any more in the stack. * @return {Phaser.Renderer.WebGL.Wrappers.WebGLFramebufferWrapper} The Framebuffer that was set, or `null` if there aren't any more in the stack.
*/ */
unbind: function (flush) unbind: function (flush)
{ {

View file

@ -178,7 +178,7 @@ var WebGLPipeline = new Class({
* is created. If not, a `DYNAMIC_DRAW` buffer is created. * is created. If not, a `DYNAMIC_DRAW` buffer is created.
* *
* @name Phaser.Renderer.WebGL.WebGLPipeline#vertexBuffer * @name Phaser.Renderer.WebGL.WebGLPipeline#vertexBuffer
* @type {WebGLBuffer} * @type {Phaser.Renderer.WebGL.Wrappers.WebGLBufferWrapper}
* @readonly * @readonly
* @since 3.0.0 * @since 3.0.0
*/ */
@ -188,7 +188,7 @@ var WebGLPipeline = new Class({
* The currently active WebGLBuffer. * The currently active WebGLBuffer.
* *
* @name Phaser.Renderer.WebGL.WebGLPipeline#activeBuffer * @name Phaser.Renderer.WebGL.WebGLPipeline#activeBuffer
* @type {WebGLBuffer} * @type {Phaser.Renderer.WebGL.Wrappers.WebGLBufferWrapper}
* @since 3.60.0 * @since 3.60.0
*/ */
this.activeBuffer; this.activeBuffer;
@ -412,14 +412,14 @@ var WebGLPipeline = new Class({
this.currentBatch = null; this.currentBatch = null;
/** /**
* The most recently bound WebGLTexture, used as part of the batch process. * The most recently bound texture, used as part of the batch process.
* *
* Reset to null as part of the flush method. * Reset to null as part of the flush method.
* *
* Treat this value as read-only. * Treat this value as read-only.
* *
* @name Phaser.Renderer.WebGL.WebGLPipeline#currentTexture * @name Phaser.Renderer.WebGL.WebGLPipeline#currentTexture
* @type {?WebGLTexture} * @type {?Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper}
* @since 3.60.0 * @since 3.60.0
*/ */
this.currentTexture = null; this.currentTexture = null;
@ -443,7 +443,7 @@ var WebGLPipeline = new Class({
* Treat this array as read-only. * Treat this array as read-only.
* *
* @name Phaser.Renderer.WebGL.WebGLPipeline#activeTextures * @name Phaser.Renderer.WebGL.WebGLPipeline#activeTextures
* @type {WebGLTexture[]} * @type {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper[]}
* @since 3.60.0 * @since 3.60.0
*/ */
this.activeTextures = []; this.activeTextures = [];
@ -621,7 +621,7 @@ var WebGLPipeline = new Class({
* *
* @param {Phaser.Renderer.WebGL.WebGLShader} shader - The shader to set as being current. * @param {Phaser.Renderer.WebGL.WebGLShader} shader - The shader to set as being current.
* @param {boolean} [setAttributes=false] - Should the vertex attribute pointers be set? * @param {boolean} [setAttributes=false] - Should the vertex attribute pointers be set?
* @param {WebGLBuffer} [vertexBuffer] - The vertex buffer to be set before the shader is bound. Defaults to the one owned by this pipeline. * @param {Phaser.Renderer.WebGL.Wrappers.WebGLBufferWrapper} [vertexBuffer] - The vertex buffer to be set before the shader is bound. Defaults to the one owned by this pipeline.
* *
* @return {this} This WebGLPipeline instance. * @return {this} This WebGLPipeline instance.
*/ */
@ -782,7 +782,7 @@ var WebGLPipeline = new Class({
* @method Phaser.Renderer.WebGL.WebGLPipeline#createBatch * @method Phaser.Renderer.WebGL.WebGLPipeline#createBatch
* @since 3.60.0 * @since 3.60.0
* *
* @param {WebGLTexture} texture - The WebGLTexture assigned to this batch entry. * @param {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper} texture - The texture assigned to this batch entry.
* *
* @return {number} The texture unit that was bound. * @return {number} The texture unit that was bound.
*/ */
@ -811,7 +811,7 @@ var WebGLPipeline = new Class({
* @method Phaser.Renderer.WebGL.WebGLPipeline#addTextureToBatch * @method Phaser.Renderer.WebGL.WebGLPipeline#addTextureToBatch
* @since 3.60.0 * @since 3.60.0
* *
* @param {WebGLTexture} texture - The WebGLTexture assigned to this batch entry. * @param {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper} texture - The texture assigned to this batch entry.
*/ */
addTextureToBatch: function (texture) addTextureToBatch: function (texture)
{ {
@ -826,7 +826,7 @@ var WebGLPipeline = new Class({
}, },
/** /**
* Takes the given WebGLTexture and determines what to do with it. * Takes the given WebGLTextureWrapper and determines what to do with it.
* *
* If there is no current batch (i.e. after a flush) it will create a new * If there is no current batch (i.e. after a flush) it will create a new
* batch from it. * batch from it.
@ -843,7 +843,7 @@ var WebGLPipeline = new Class({
* @method Phaser.Renderer.WebGL.WebGLPipeline#pushBatch * @method Phaser.Renderer.WebGL.WebGLPipeline#pushBatch
* @since 3.60.0 * @since 3.60.0
* *
* @param {WebGLTexture} texture - The WebGLTexture assigned to this batch entry. * @param {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper} texture - The texture assigned to this batch entry.
* *
* @return {number} The texture unit that was bound. * @return {number} The texture unit that was bound.
*/ */
@ -1130,7 +1130,7 @@ var WebGLPipeline = new Class({
if (gl.getParameter(gl.ARRAY_BUFFER_BINDING) !== this.vertexBuffer) if (gl.getParameter(gl.ARRAY_BUFFER_BINDING) !== this.vertexBuffer)
{ {
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer.webGLBuffer);
this.activeBuffer = this.vertexBuffer; this.activeBuffer = this.vertexBuffer;
@ -1195,6 +1195,43 @@ var WebGLPipeline = new Class({
return this; return this;
}, },
/**
* This method is called if the WebGL context is lost and restored.
* It ensures that uniforms are synced back to the GPU
* for all shaders in this pipeline.
*
* @method Phaser.Renderer.WebGL.WebGLPipeline#restoreContext
* @since 3.80.0
*/
restoreContext: function ()
{
var shaders = this.shaders;
var hasVertexBuffer = !!this.vertexBuffer;
// Deactivate all invalidated state.
this.activeBuffer = null;
this.activeTextures.length = 0;
this.batch.length = 0;
this.currentBatch = null;
this.currentTexture = null;
this.currentUnit = 0;
if (hasVertexBuffer)
{
this.setVertexBuffer();
}
for (var i = 0; i < shaders.length; i++)
{
var shader = shaders[i];
shader.syncUniforms();
if (hasVertexBuffer)
{
shader.rebind();
}
}
},
/** /**
* Binds the vertex buffer to be the active ARRAY_BUFFER on the WebGL context. * Binds the vertex buffer to be the active ARRAY_BUFFER on the WebGL context.
* *
@ -1204,7 +1241,7 @@ var WebGLPipeline = new Class({
* @method Phaser.Renderer.WebGL.WebGLPipeline#setVertexBuffer * @method Phaser.Renderer.WebGL.WebGLPipeline#setVertexBuffer
* @since 3.50.0 * @since 3.50.0
* *
* @param {WebGLBuffer} [buffer] - The Vertex Buffer to be bound. Defaults to the one owned by this pipeline. * @param {Phaser.Renderer.WebGL.Wrappers.WebGLBufferWrapper} [buffer] - The Vertex Buffer to be bound. Defaults to the one owned by this pipeline.
* *
* @return {boolean} `true` if the vertex buffer was bound, or `false` if it was already bound. * @return {boolean} `true` if the vertex buffer was bound, or `false` if it was already bound.
*/ */
@ -1216,7 +1253,7 @@ var WebGLPipeline = new Class({
{ {
var gl = this.gl; var gl = this.gl;
this.gl.bindBuffer(gl.ARRAY_BUFFER, buffer); this.gl.bindBuffer(gl.ARRAY_BUFFER, buffer.webGLBuffer);
this.activeBuffer = buffer; this.activeBuffer = buffer;
@ -1375,7 +1412,7 @@ var WebGLPipeline = new Class({
if (activeTextures[0] !== texture) if (activeTextures[0] !== texture)
{ {
gl.bindTexture(gl.TEXTURE_2D, texture); gl.bindTexture(gl.TEXTURE_2D, texture.webGLTexture);
activeTextures[0] = texture; activeTextures[0] = texture;
} }
@ -1396,7 +1433,7 @@ var WebGLPipeline = new Class({
if (activeTextures[t] !== texture) if (activeTextures[t] !== texture)
{ {
gl.activeTexture(gl.TEXTURE0 + t); gl.activeTexture(gl.TEXTURE0 + t);
gl.bindTexture(gl.TEXTURE_2D, texture); gl.bindTexture(gl.TEXTURE_2D, texture.webGLTexture);
activeTextures[t] = texture; activeTextures[t] = texture;
} }
@ -1686,7 +1723,7 @@ var WebGLPipeline = new Class({
* @param {number} tintBL - The bottom-left tint color value. * @param {number} tintBL - The bottom-left tint color value.
* @param {number} tintBR - The bottom-right tint color value. * @param {number} tintBR - The bottom-right tint color value.
* @param {(number|boolean)} tintEffect - The tint effect for the shader to use. * @param {(number|boolean)} tintEffect - The tint effect for the shader to use.
* @param {WebGLTexture} [texture] - WebGLTexture that will be assigned to the current batch if a flush occurs. * @param {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper} [texture] - Texture that will be assigned to the current batch if a flush occurs.
* @param {number} [unit=0] - Texture unit to which the texture needs to be bound. * @param {number} [unit=0] - Texture unit to which the texture needs to be bound.
* *
* @return {boolean} `true` if this method caused the batch to flush, otherwise `false`. * @return {boolean} `true` if this method caused the batch to flush, otherwise `false`.
@ -1804,7 +1841,7 @@ var WebGLPipeline = new Class({
* @param {number} tintTR - The top-right tint color value. * @param {number} tintTR - The top-right tint color value.
* @param {number} tintBL - The bottom-left tint color value. * @param {number} tintBL - The bottom-left tint color value.
* @param {(number|boolean)} tintEffect - The tint effect for the shader to use. * @param {(number|boolean)} tintEffect - The tint effect for the shader to use.
* @param {WebGLTexture} [texture] - WebGLTexture that will be assigned to the current batch if a flush occurs. * @param {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper} [texture] - Texture that will be assigned to the current batch if a flush occurs.
* @param {number} [unit=0] - Texture unit to which the texture needs to be bound. * @param {number} [unit=0] - Texture unit to which the texture needs to be bound.
* *
* @return {boolean} `true` if this method caused the batch to flush, otherwise `false`. * @return {boolean} `true` if this method caused the batch to flush, otherwise `false`.
@ -1883,7 +1920,7 @@ var WebGLPipeline = new Class({
* @param {number} height - Height of the rectangle. * @param {number} height - Height of the rectangle.
* @param {number} color - Color of the rectangle to draw. * @param {number} color - Color of the rectangle to draw.
* @param {number} alpha - Alpha value of the rectangle to draw. * @param {number} alpha - Alpha value of the rectangle to draw.
* @param {WebGLTexture} [texture] - WebGLTexture that will be assigned to the current batch if a flush occurs. * @param {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper} [texture] - texture that will be assigned to the current batch if a flush occurs.
* @param {boolean} [flipUV=true] - Flip the vertical UV coordinates of the texture before rendering? * @param {boolean} [flipUV=true] - Flip the vertical UV coordinates of the texture before rendering?
*/ */
drawFillRect: function (x, y, width, height, color, alpha, texture, flipUV) drawFillRect: function (x, y, width, height, color, alpha, texture, flipUV)
@ -1922,7 +1959,7 @@ var WebGLPipeline = new Class({
* @method Phaser.Renderer.WebGL.WebGLPipeline#setTexture2D * @method Phaser.Renderer.WebGL.WebGLPipeline#setTexture2D
* @since 3.50.0 * @since 3.50.0
* *
* @param {WebGLTexture} [texture] - WebGLTexture that will be assigned to the current batch. If not given uses `whiteTexture`. * @param {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper} [texture] - Texture that will be assigned to the current batch. If not given uses `whiteTexture`.
* *
* @return {number} The assigned texture unit. * @return {number} The assigned texture unit.
*/ */
@ -1939,7 +1976,7 @@ var WebGLPipeline = new Class({
* @method Phaser.Renderer.WebGL.WebGLPipeline#bindTexture * @method Phaser.Renderer.WebGL.WebGLPipeline#bindTexture
* @since 3.50.0 * @since 3.50.0
* *
* @param {WebGLTexture} [target] - The WebGLTexture to activate and bind. * @param {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper} [target] - Texture to activate and bind.
* @param {number} [unit=0] - The WebGL texture ID to activate. Defaults to `gl.TEXTURE0`. * @param {number} [unit=0] - The WebGL texture ID to activate. Defaults to `gl.TEXTURE0`.
* *
* @return {this} This WebGL Pipeline instance. * @return {this} This WebGL Pipeline instance.
@ -1952,7 +1989,7 @@ var WebGLPipeline = new Class({
gl.activeTexture(gl.TEXTURE0 + unit); gl.activeTexture(gl.TEXTURE0 + unit);
gl.bindTexture(gl.TEXTURE_2D, texture); gl.bindTexture(gl.TEXTURE_2D, texture.webGLTexture);
return this; return this;
}, },
@ -2578,9 +2615,9 @@ var WebGLPipeline = new Class({
targets[i].destroy(); targets[i].destroy();
} }
this.gl.deleteBuffer(this.vertexBuffer);
var renderer = this.renderer; var renderer = this.renderer;
renderer.deleteBuffer(this.vertexBuffer);
renderer.off(RendererEvents.RESIZE, this.resize, this); renderer.off(RendererEvents.RESIZE, this.resize, this);
renderer.off(RendererEvents.PRE_RENDER, this.onPreRender, this); renderer.off(RendererEvents.PRE_RENDER, this.onPreRender, this);

File diff suppressed because it is too large Load diff

View file

@ -5,6 +5,7 @@
*/ */
var Class = require('../../utils/Class'); var Class = require('../../utils/Class');
var ArrayEach = require('../../utils/array/Each');
var GetFastValue = require('../../utils/object/GetFastValue'); var GetFastValue = require('../../utils/object/GetFastValue');
var WEBGL_CONST = require('./const'); var WEBGL_CONST = require('./const');
@ -99,7 +100,7 @@ var WebGLShader = new Class({
* The WebGLProgram created from the vertex and fragment shaders. * The WebGLProgram created from the vertex and fragment shaders.
* *
* @name Phaser.Renderer.WebGL.WebGLShader#program * @name Phaser.Renderer.WebGL.WebGLShader#program
* @type {WebGLProgram} * @type {Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper}
* @since 3.50.0 * @since 3.50.0
*/ */
this.program = this.renderer.createProgram(vertexShader, fragmentShader); this.program = this.renderer.createProgram(vertexShader, fragmentShader);
@ -296,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;
@ -313,29 +315,33 @@ var WebGLShader = new Class({
if (reset) if (reset)
{ {
var attribLocation = gl.getAttribLocation(program, element.name); if (location !== -1)
if (attribLocation >= 0)
{ {
gl.enableVertexAttribArray(attribLocation); renderer.deleteAttribLocation(location);
}
var attribLocation = this.renderer.createAttribLocation(program, element.name);
gl.vertexAttribPointer(attribLocation, size, type, normalized, vertexSize, offset); if (attribLocation.webGLAttribLocation >= 0)
{
gl.enableVertexAttribArray(attribLocation.webGLAttribLocation);
gl.vertexAttribPointer(attribLocation.webGLAttribLocation, size, type, normalized, vertexSize, offset);
element.enabled = true; element.enabled = true;
element.location = attribLocation; element.location = attribLocation;
} }
else if (attribLocation !== -1) else if (attribLocation.webGLAttribLocation !== -1)
{ {
gl.disableVertexAttribArray(attribLocation); gl.disableVertexAttribArray(attribLocation.webGLAttribLocation);
} }
} }
else if (enabled) else if (enabled)
{ {
gl.vertexAttribPointer(location, size, type, normalized, vertexSize, offset); gl.vertexAttribPointer(location.webGLAttribLocation, size, type, normalized, vertexSize, offset);
} }
else if (!enabled && location > -1) else if (!enabled && location !== -1 && location.webGLAttribLocation > -1)
{ {
gl.disableVertexAttribArray(location); gl.disableVertexAttribArray(location.webGLAttribLocation);
element.location = -1; element.location = -1;
} }
@ -348,7 +354,7 @@ var WebGLShader = new Class({
* Sets up the `WebGLShader.uniforms` object, populating it with the names * Sets up the `WebGLShader.uniforms` object, populating it with the names
* and locations of the shader uniforms this shader requires. * and locations of the shader uniforms this shader requires.
* *
* It works by first calling `gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS)` to * It works by first calling `gl.getProgramParameter(program.webGLProgram, gl.ACTIVE_UNIFORMS)` to
* find out how many active uniforms this shader has. It then iterates through them, * find out how many active uniforms this shader has. It then iterates through them,
* calling `gl.getActiveUniform` to get the WebGL Active Info from each one. Finally, * calling `gl.getActiveUniform` to get the WebGL Active Info from each one. Finally,
* the name and location are stored in the local array. * the name and location are stored in the local array.
@ -372,17 +378,17 @@ var WebGLShader = new Class({
// Look-up all active uniforms // Look-up all active uniforms
var totalUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); var totalUniforms = gl.getProgramParameter(program.webGLProgram, gl.ACTIVE_UNIFORMS);
for (i = 0; i < totalUniforms; i++) for (i = 0; i < totalUniforms; i++)
{ {
var info = gl.getActiveUniform(program, i); var info = gl.getActiveUniform(program.webGLProgram, i);
if (info) if (info)
{ {
name = info.name; name = info.name;
location = gl.getUniformLocation(program, name); location = this.renderer.createUniformLocation(program, name);
if (location !== null) if (location !== null)
{ {
@ -390,6 +396,7 @@ var WebGLShader = new Class({
{ {
name: name, name: name,
location: location, location: location,
setter: null,
value1: null, value1: null,
value2: null, value2: null,
value3: null, value3: null,
@ -409,7 +416,7 @@ var WebGLShader = new Class({
if (!uniforms.hasOwnProperty(name)) if (!uniforms.hasOwnProperty(name))
{ {
location = gl.getUniformLocation(program, name); location = this.renderer.createUniformLocation(program, name);
if (location !== null) if (location !== null)
{ {
@ -417,6 +424,7 @@ var WebGLShader = new Class({
{ {
name: name, name: name,
location: location, location: location,
setter: null,
value1: null, value1: null,
value2: null, value2: null,
value3: null, value3: null,
@ -431,6 +439,33 @@ var WebGLShader = new Class({
return this; return this;
}, },
/**
* Repopulate uniforms on the GPU.
*
* This is called automatically by the pipeline when the context is
* lost and then recovered. By the time this method is called,
* the WebGL resources are already recreated, so we just need to
* re-populate them.
*
* @method Phaser.Renderer.WebGL.WebGLShader#syncUniforms
* @since 3.80.0
*/
syncUniforms: function ()
{
var gl = this.gl;
this.renderer.setProgram(this.program);
for (var name in this.uniforms)
{
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);
}
}
},
/** /**
* Checks to see if the given uniform name exists and is active in this shader. * Checks to see if the given uniform name exists and is active in this shader.
* *
@ -503,11 +538,16 @@ var WebGLShader = new Class({
if (skipCheck || uniform.value1 !== value1) if (skipCheck || uniform.value1 !== value1)
{ {
if (!uniform.setter)
{
uniform.setter = setter;
}
uniform.value1 = value1; uniform.value1 = value1;
this.renderer.setProgram(this.program); this.renderer.setProgram(this.program);
setter.call(this.gl, uniform.location, value1); setter.call(this.gl, uniform.location.webGLUniformLocation, value1);
this.pipeline.currentShader = this; this.pipeline.currentShader = this;
} }
@ -548,12 +588,17 @@ var WebGLShader = new Class({
if (skipCheck || uniform.value1 !== value1 || uniform.value2 !== value2) if (skipCheck || uniform.value1 !== value1 || uniform.value2 !== value2)
{ {
if (!uniform.setter)
{
uniform.setter = setter;
}
uniform.value1 = value1; uniform.value1 = value1;
uniform.value2 = value2; uniform.value2 = value2;
this.renderer.setProgram(this.program); this.renderer.setProgram(this.program);
setter.call(this.gl, uniform.location, value1, value2); setter.call(this.gl, uniform.location.webGLUniformLocation, value1, value2);
this.pipeline.currentShader = this; this.pipeline.currentShader = this;
} }
@ -595,13 +640,18 @@ var WebGLShader = new Class({
if (skipCheck || uniform.value1 !== value1 || uniform.value2 !== value2 || uniform.value3 !== value3) if (skipCheck || uniform.value1 !== value1 || uniform.value2 !== value2 || uniform.value3 !== value3)
{ {
if (!uniform.setter)
{
uniform.setter = setter;
}
uniform.value1 = value1; uniform.value1 = value1;
uniform.value2 = value2; uniform.value2 = value2;
uniform.value3 = value3; uniform.value3 = value3;
this.renderer.setProgram(this.program); this.renderer.setProgram(this.program);
setter.call(this.gl, uniform.location, value1, value2, value3); setter.call(this.gl, uniform.location.webGLUniformLocation, value1, value2, value3);
this.pipeline.currentShader = this; this.pipeline.currentShader = this;
} }
@ -644,6 +694,11 @@ var WebGLShader = new Class({
if (skipCheck || uniform.value1 !== value1 || uniform.value2 !== value2 || uniform.value3 !== value3 || uniform.value4 !== value4) if (skipCheck || uniform.value1 !== value1 || uniform.value2 !== value2 || uniform.value3 !== value3 || uniform.value4 !== value4)
{ {
if (!uniform.setter)
{
uniform.setter = setter;
}
uniform.value1 = value1; uniform.value1 = value1;
uniform.value2 = value2; uniform.value2 = value2;
uniform.value3 = value3; uniform.value3 = value3;
@ -651,7 +706,7 @@ var WebGLShader = new Class({
this.renderer.setProgram(this.program); this.renderer.setProgram(this.program);
setter.call(this.gl, uniform.location, value1, value2, value3, value4); setter.call(this.gl, uniform.location.webGLUniformLocation, value1, value2, value3, value4);
this.pipeline.currentShader = this; this.pipeline.currentShader = this;
} }
@ -1142,11 +1197,9 @@ var WebGLShader = new Class({
if (vertSrc === undefined) { vertSrc = this.vertSrc; } if (vertSrc === undefined) { vertSrc = this.vertSrc; }
if (fragSrc === undefined) { fragSrc = this.fragSrc; } if (fragSrc === undefined) { fragSrc = this.fragSrc; }
var gl = this.gl;
if (this.program) if (this.program)
{ {
gl.deleteProgram(this.program); this.renderer.deleteProgram(this.program);
} }
this.vertSrc = vertSrc; this.vertSrc = vertSrc;
@ -1169,14 +1222,25 @@ var WebGLShader = new Class({
*/ */
destroy: function () destroy: function ()
{ {
this.gl.deleteProgram(this.program); var renderer = this.renderer;
ArrayEach(this.uniforms, function (uniform)
{
renderer.deleteUniformLocation(uniform.location);
});
this.uniforms = null;
ArrayEach(this.attributes, function (attrib)
{
renderer.deleteAttribLocation(attrib.location);
});
this.attributes = null;
renderer.deleteProgram(this.program);
this.pipeline = null; this.pipeline = null;
this.renderer = null; this.renderer = null;
this.gl = null; this.gl = null;
this.program = null; this.program = null;
this.attributes = null;
this.uniforms = null;
} }
}); });

View file

@ -19,7 +19,8 @@ var WebGL = {
Utils: require('./Utils'), Utils: require('./Utils'),
WebGLPipeline: require('./WebGLPipeline'), WebGLPipeline: require('./WebGLPipeline'),
WebGLRenderer: require('./WebGLRenderer'), WebGLRenderer: require('./WebGLRenderer'),
WebGLShader: require('./WebGLShader') WebGLShader: require('./WebGLShader'),
Wrappers: require('./wrappers')
}; };

View file

@ -10,6 +10,7 @@ var GetFastValue = require('../../../utils/object/GetFastValue');
var LightShaderSourceFS = require('../shaders/Light-frag.js'); var LightShaderSourceFS = require('../shaders/Light-frag.js');
var MultiPipeline = require('./MultiPipeline'); var MultiPipeline = require('./MultiPipeline');
var TransformMatrix = require('../../../gameobjects/components/TransformMatrix'); var TransformMatrix = require('../../../gameobjects/components/TransformMatrix');
var UUID = require('../../../utils/string/UUID.js');
var Vec2 = require('../../../math/Vector2'); var Vec2 = require('../../../math/Vector2');
var WebGLPipeline = require('../WebGLPipeline'); var WebGLPipeline = require('../WebGLPipeline');
@ -158,15 +159,7 @@ var LightPipeline = new Class({
{ {
WebGLPipeline.prototype.boot.call(this); WebGLPipeline.prototype.boot.call(this);
var gl = this.gl; var tempTexture = this.renderer.game.textures.addUint8Array(UUID(), new Uint8Array([ 127, 127, 255, 255 ]), 1, 1);
var tempTexture = gl.createTexture();
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, tempTexture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([ 127, 127, 255, 255 ]));
this.defaultNormalMap = { glTexture: tempTexture }; this.defaultNormalMap = { glTexture: tempTexture };
}, },

View file

@ -430,7 +430,7 @@ var MultiPipeline = new Class({
* @since 3.0.0 * @since 3.0.0
* *
* @param {Phaser.GameObjects.GameObject} gameObject - Source GameObject. * @param {Phaser.GameObjects.GameObject} gameObject - Source GameObject.
* @param {WebGLTexture} texture - Raw WebGLTexture associated with the quad. * @param {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper} texture - Texture associated with the quad.
* @param {number} textureWidth - Real texture width. * @param {number} textureWidth - Real texture width.
* @param {number} textureHeight - Real texture height. * @param {number} textureHeight - Real texture height.
* @param {number} srcX - X coordinate of the quad. * @param {number} srcX - X coordinate of the quad.

View file

@ -353,12 +353,12 @@ var PostFXPipeline = new Class({
var gl = this.gl; var gl = this.gl;
gl.activeTexture(gl.TEXTURE0); gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, source.texture); gl.bindTexture(gl.TEXTURE_2D, source.texture.webGLTexture);
var currentFBO = gl.getParameter(gl.FRAMEBUFFER_BINDING); var currentFBO = gl.getParameter(gl.FRAMEBUFFER_BINDING);
gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer); gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer.webGLFramebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture, 0); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture.webGLTexture, 0);
gl.clearColor(0, 0, 0, 0); gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT); gl.clear(gl.COLOR_BUFFER_BIT);
@ -572,8 +572,8 @@ var PostFXPipeline = new Class({
if (target) if (target)
{ {
gl.viewport(0, 0, target.width, target.height); gl.viewport(0, 0, target.width, target.height);
gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer); gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer.webGLFramebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture, 0); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture.webGLTexture, 0);
if (clear) if (clear)
{ {
@ -602,7 +602,7 @@ var PostFXPipeline = new Class({
renderer.restoreStencilMask(); renderer.restoreStencilMask();
gl.activeTexture(gl.TEXTURE0); gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, source.texture); gl.bindTexture(gl.TEXTURE_2D, source.texture.webGLTexture);
gl.bufferData(gl.ARRAY_BUFFER, this.vertexData, gl.STATIC_DRAW); gl.bufferData(gl.ARRAY_BUFFER, this.vertexData, gl.STATIC_DRAW);
gl.drawArrays(gl.TRIANGLES, 0, 6); gl.drawArrays(gl.TRIANGLES, 0, 6);
@ -610,7 +610,7 @@ var PostFXPipeline = new Class({
if (target) if (target)
{ {
gl.bindTexture(gl.TEXTURE_2D, null); gl.bindTexture(gl.TEXTURE_2D, null);
gl.bindFramebuffer(gl.FRAMEBUFFER, renderer.currentFramebuffer); gl.bindFramebuffer(gl.FRAMEBUFFER, renderer.currentFramebuffer.webGLFramebuffer);
} }
}, },
@ -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;

View file

@ -161,7 +161,7 @@ var PreFXPipeline = new Class({
* The WebGLBuffer that holds the quadVertexData. * The WebGLBuffer that holds the quadVertexData.
* *
* @name Phaser.Renderer.WebGL.Pipelines.PreFXPipeline#quadVertexBuffer * @name Phaser.Renderer.WebGL.Pipelines.PreFXPipeline#quadVertexBuffer
* @type {WebGLBuffer} * @type {Phaser.Renderer.WebGL.Wrappers.WebGLBufferWrapper}
* @readonly * @readonly
* @since 3.60.0 * @since 3.60.0
*/ */
@ -330,7 +330,7 @@ var PreFXPipeline = new Class({
* @param {number} tintBL - The bottom-left tint color value. * @param {number} tintBL - The bottom-left tint color value.
* @param {number} tintBR - The bottom-right tint color value. * @param {number} tintBR - The bottom-right tint color value.
* @param {(number|boolean)} tintEffect - The tint effect for the shader to use. * @param {(number|boolean)} tintEffect - The tint effect for the shader to use.
* @param {WebGLTexture} [texture] - WebGLTexture that will be assigned to the current batch if a flush occurs. * @param {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper} [texture] - Texture that will be assigned to the current batch if a flush occurs.
* *
* @return {boolean} `true` if this method caused the batch to flush, otherwise `false`. * @return {boolean} `true` if this method caused the batch to flush, otherwise `false`.
*/ */
@ -386,8 +386,8 @@ var PreFXPipeline = new Class({
this.flush(); this.flush();
gl.viewport(0, 0, renderer.width, renderer.height); gl.viewport(0, 0, renderer.width, renderer.height);
gl.bindFramebuffer(gl.FRAMEBUFFER, fsTarget.framebuffer); gl.bindFramebuffer(gl.FRAMEBUFFER, fsTarget.framebuffer.webGLFramebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fsTarget.texture, 0); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fsTarget.texture.webGLTexture, 0);
gl.clearColor(0, 0, 0, 0); gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT); gl.clear(gl.COLOR_BUFFER_BIT);
@ -409,7 +409,7 @@ var PreFXPipeline = new Class({
// Now we've got the sprite drawn to our screen-sized fbo, copy the rect we need to our target // Now we've got the sprite drawn to our screen-sized fbo, copy the rect we need to our target
gl.activeTexture(gl.TEXTURE0); gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, target.texture); gl.bindTexture(gl.TEXTURE_2D, target.texture.webGLTexture);
gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, targetBounds.x, targetBounds.y, targetBounds.width, targetBounds.height); gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, targetBounds.x, targetBounds.y, targetBounds.width, targetBounds.height);
gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.bindFramebuffer(gl.FRAMEBUFFER, null);
@ -530,7 +530,7 @@ var PreFXPipeline = new Class({
} }
gl.activeTexture(gl.TEXTURE0); gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, source.texture); gl.bindTexture(gl.TEXTURE_2D, source.texture.webGLTexture);
if (source.height > target.height) if (source.height > target.height)
{ {
@ -547,8 +547,8 @@ var PreFXPipeline = new Class({
this.resetUVs(); this.resetUVs();
} }
gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer); gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer.webGLFramebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture, 0); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture.webGLTexture, 0);
if (clear) if (clear)
{ {
@ -598,15 +598,15 @@ var PreFXPipeline = new Class({
this.set1i('uMainSampler', 0); this.set1i('uMainSampler', 0);
gl.activeTexture(gl.TEXTURE0); gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, source.texture); gl.bindTexture(gl.TEXTURE_2D, source.texture.webGLTexture);
// source and target must always be the same size // source and target must always be the same size
gl.viewport(0, 0, source.width, source.height); gl.viewport(0, 0, source.width, source.height);
this.setUVs(0, 0, 0, 1, 1, 1, 1, 0); this.setUVs(0, 0, 0, 1, 1, 1, 1, 0);
gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer); gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer.webGLFramebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture, 0); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture.webGLTexture, 0);
gl.clearColor(0, 0, 0, 0); gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT); gl.clear(gl.COLOR_BUFFER_BIT);
@ -779,7 +779,7 @@ var PreFXPipeline = new Class({
// Clear the source framebuffer out, ready for the next pass // Clear the source framebuffer out, ready for the next pass
// gl.clearColor(0, 0, 0, 0); // gl.clearColor(0, 0, 0, 0);
// gl.bindFramebuffer(gl.FRAMEBUFFER, source.framebuffer); // gl.bindFramebuffer(gl.FRAMEBUFFER, source.framebuffer.webGLFramebuffer);
// gl.clear(gl.COLOR_BUFFER_BIT); // gl.clear(gl.COLOR_BUFFER_BIT);
// gl.bindFramebuffer(gl.FRAMEBUFFER, null); // gl.bindFramebuffer(gl.FRAMEBUFFER, null);
@ -899,7 +899,7 @@ var PreFXPipeline = new Class({
*/ */
destroy: function () destroy: function ()
{ {
this.gl.deleteBuffer(this.quadVertexBuffer); this.renderer.deleteBuffer(this.quadVertexBuffer);
this.drawSpriteShader = null; this.drawSpriteShader = null;
this.copyShader = null; this.copyShader = null;

View file

@ -291,13 +291,13 @@ var UtilityPipeline = new Class({
this.set1f('uBrightness', brightness); this.set1f('uBrightness', brightness);
gl.activeTexture(gl.TEXTURE0); gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, source.texture); gl.bindTexture(gl.TEXTURE_2D, source.texture.webGLTexture);
if (target) if (target)
{ {
gl.viewport(0, 0, target.width, target.height); gl.viewport(0, 0, target.width, target.height);
gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer); gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer.webGLFramebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture, 0); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture.webGLTexture, 0);
} }
else else
{ {
@ -361,7 +361,7 @@ var UtilityPipeline = new Class({
this.set1f('uBrightness', brightness); this.set1f('uBrightness', brightness);
gl.activeTexture(gl.TEXTURE0); gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, source.texture); gl.bindTexture(gl.TEXTURE_2D, source.texture.webGLTexture);
if (source.height > target.height) if (source.height > target.height)
{ {
@ -376,8 +376,8 @@ var UtilityPipeline = new Class({
gl.viewport(0, diff, source.width, source.height); gl.viewport(0, diff, source.width, source.height);
} }
gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer); gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer.webGLFramebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture, 0); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture.webGLTexture, 0);
if (clear) if (clear)
{ {
@ -447,8 +447,8 @@ var UtilityPipeline = new Class({
var gl = this.gl; var gl = this.gl;
gl.bindFramebuffer(gl.FRAMEBUFFER, source.framebuffer); gl.bindFramebuffer(gl.FRAMEBUFFER, source.framebuffer.webGLFramebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, source.texture, 0); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, source.texture.webGLTexture, 0);
if (clear) if (clear)
{ {
@ -465,7 +465,7 @@ var UtilityPipeline = new Class({
} }
gl.activeTexture(gl.TEXTURE0); gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, target.texture); gl.bindTexture(gl.TEXTURE_2D, target.texture.webGLTexture);
gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, x, y, width, height); gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, x, y, width, height);
@ -500,7 +500,7 @@ var UtilityPipeline = new Class({
this.renderer.popFramebuffer(); this.renderer.popFramebuffer();
gl.activeTexture(gl.TEXTURE0); gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, source.texture); gl.bindTexture(gl.TEXTURE_2D, source.texture.webGLTexture);
gl.bufferData(gl.ARRAY_BUFFER, this.vertexData, gl.STATIC_DRAW); gl.bufferData(gl.ARRAY_BUFFER, this.vertexData, gl.STATIC_DRAW);
gl.drawArrays(gl.TRIANGLES, 0, 6); gl.drawArrays(gl.TRIANGLES, 0, 6);
@ -537,13 +537,13 @@ var UtilityPipeline = new Class({
this.set1f('uAlpha', colorMatrix.alpha); this.set1f('uAlpha', colorMatrix.alpha);
gl.activeTexture(gl.TEXTURE0); gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, source.texture); gl.bindTexture(gl.TEXTURE_2D, source.texture.webGLTexture);
if (target) if (target)
{ {
gl.viewport(0, 0, target.width, target.height); gl.viewport(0, 0, target.width, target.height);
gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer); gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer.webGLFramebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture, 0); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture.webGLTexture, 0);
} }
else else
{ {
@ -597,15 +597,15 @@ var UtilityPipeline = new Class({
this.set1f('uStrength', strength); this.set1f('uStrength', strength);
gl.activeTexture(gl.TEXTURE0); gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, source1.texture); gl.bindTexture(gl.TEXTURE_2D, source1.texture.webGLTexture);
gl.activeTexture(gl.TEXTURE1); gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, source2.texture); gl.bindTexture(gl.TEXTURE_2D, source2.texture.webGLTexture);
if (target) if (target)
{ {
gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer); gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer.webGLFramebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture, 0); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture.webGLTexture, 0);
gl.viewport(0, 0, target.width, target.height); gl.viewport(0, 0, target.width, target.height);
} }
else else
@ -666,7 +666,7 @@ var UtilityPipeline = new Class({
gl.viewport(0, 0, target.width, target.height); gl.viewport(0, 0, target.width, target.height);
gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer); gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer.webGLFramebuffer);
if (clearAlpha) if (clearAlpha)
{ {
@ -681,7 +681,7 @@ var UtilityPipeline = new Class({
var fbo = this.renderer.currentFramebuffer; var fbo = this.renderer.currentFramebuffer;
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); gl.bindFramebuffer(gl.FRAMEBUFFER, fbo.webGLFramebuffer);
}, },
/** /**

View file

@ -66,10 +66,10 @@ var DisplacementFXPipeline = new Class({
this.y = 0.005; this.y = 0.005;
/** /**
* The underlying WebGLTexture used for displacement. * The underlying texture used for displacement.
* *
* @name Phaser.Renderer.WebGL.Pipelines.FX.DisplacementFXPipeline#glTexture * @name Phaser.Renderer.WebGL.Pipelines.FX.DisplacementFXPipeline#glTexture
* @type {WebGLTexture} * @type {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper}
* @since 3.60.0 * @since 3.60.0
*/ */
this.glTexture; this.glTexture;

View file

@ -8,5 +8,5 @@
* @property {number} offset - The offset, in bytes, of this attribute data in the vertex array. Equivalent to `offsetof(vertex, attrib)` in C. * @property {number} offset - The offset, in bytes, of this attribute data in the vertex array. Equivalent to `offsetof(vertex, attrib)` in C.
* @property {boolean} normalized - Should the attribute data be normalized? * @property {boolean} normalized - Should the attribute data be normalized?
* @property {boolean} enabled - You should set this to `false` by default. The pipeline will enable it on boot. * @property {boolean} enabled - You should set this to `false` by default. The pipeline will enable it on boot.
* @property {number} location - You should set this to `-1` by default. The pipeline will set it on boot. * @property {(-1|Phaser.Renderer.WebGL.Wrappers.WebGLAttribLocationWrapper)} location - You should set this to `-1` by default. The pipeline will set it on boot.
*/ */

View file

@ -6,5 +6,5 @@
* @property {number} count - The total number of vertices in this batch entry. * @property {number} count - The total number of vertices in this batch entry.
* @property {number} unit - The current texture unit of the batch entry. * @property {number} unit - The current texture unit of the batch entry.
* @property {number} maxUnit - The maximum number of texture units in this batch entry. * @property {number} maxUnit - The maximum number of texture units in this batch entry.
* @property {WebGLTexture[]} texture - An array of WebGLTexture references used in this batch entry. * @property {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper[]} texture - An array of WebGLTextureWrapper references used in this batch entry.
*/ */

View file

@ -4,6 +4,7 @@
* *
* @property {string} name - The name of the uniform as defined in the shader. * @property {string} name - The name of the uniform as defined in the shader.
* @property {number} location - The location of the uniform. * @property {number} location - The location of the uniform.
* @property {?function} setter - The setter function called on the WebGL context to set the uniform value.
* @property {number} [value1] - The first cached value of the uniform. * @property {number} [value1] - The first cached value of the uniform.
* @property {number} [value2] - The first cached value of the uniform. * @property {number} [value2] - The first cached value of the uniform.
* @property {number} [value3] - The first cached value of the uniform. * @property {number} [value3] - The first cached value of the uniform.

View file

@ -0,0 +1,101 @@
var Class = require('../../../utils/Class');
/**
* @classdesc
* Wrapper for a WebGL attribute location, containing all the information that was used to create it.
*
* A WebGLAttribLocation 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 WebGLAttribLocationWrapper instead.
*
* @class WebGLAttribLocationWrapper
* @memberof Phaser.Renderer.WebGL.Wrappers
* @constructor
* @since 3.80.0
*
* @param {WebGLRenderingContext} gl - The WebGLRenderingContext to create the WebGLAttribLocation for.
* @param {Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper} program - The WebGLProgram that this location refers to. This must be created first.
* @param {string} name - The name of this location, as defined in the shader source code.
*/
var WebGLAttribLocationWrapper = new Class({
initialize:
function WebGLAttribLocationWrapper (gl, program, name)
{
/**
* The WebGLAttribLocation being wrapped by this class.
*
* This property could change at any time.
* Therefore, you should never store a reference to this value.
* It should only be passed directly to the WebGL API for drawing.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLAttribLocationWrapper#webGLAttribLocation
* @type {WebGLAttribLocation}
* @default -1
* @since 3.80.0
*/
this.webGLAttribLocation = -1;
/**
* The WebGLRenderingContext that owns this location.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper#gl
* @type {WebGLRenderingContext}
* @since 3.80.0
*/
this.gl = gl;
/**
* The WebGLProgram that this location refers to.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLAttribLocationWrapper#program
* @type {Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper}
* @since 3.80.0
*/
this.program = program;
/**
* The name of this location, as defined in the shader source code.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLAttribLocationWrapper#name
* @type {string}
* @since 3.80.0
*/
this.name = name;
this.createResource();
},
/**
* Creates the WebGLAttribLocation.
*
* @method Phaser.Renderer.WebGL.Wrappers.WebGLAttribLocationWrapper#createResource
* @since 3.80.0
*/
createResource: function ()
{
if (this.program.webGLProgram === null)
{
this.webGLAttribLocation = -1;
return;
}
this.webGLAttribLocation = this.gl.getAttribLocation(this.program.webGLProgram, this.name);
},
/**
* Destroys this WebGLAttribLocationWrapper.
*
* @method Phaser.Renderer.WebGL.Wrappers.WebGLAttribLocationWrapper#destroy
* @since 3.80.0
*/
destroy: function ()
{
this.gl = null;
this.program = null;
this.name = null;
this.webGLAttribLocation = -1;
}
});
module.exports = WebGLAttribLocationWrapper;

View file

@ -0,0 +1,117 @@
var Class = require('../../../utils/Class');
/**
* @classdesc
* Wrapper for a WebGL buffer, containing all the information that was used
* to create it. This can be a VertexBuffer or IndexBuffer.
*
* A WebGLBuffer 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 WebGLBufferWrapper instead.
*
* @class WebGLBufferWrapper
* @memberof Phaser.Renderer.WebGL.Wrappers
* @constructor
* @since 3.80.0
*
* @param {WebGLRenderingContext} gl - The WebGLRenderingContext to create the WebGLBuffer for.
* @param {ArrayBuffer|number} initialDataOrSize - Either an ArrayBuffer of data, or the size of the buffer to create.
* @param {GLenum} bufferType - The type of the buffer being created.
* @param {GLenum} bufferUsage - The usage of the buffer being created. gl.DYNAMIC_DRAW, gl.STATIC_DRAW or gl.STREAM_DRAW.
*/
var WebGLBufferWrapper = new Class({
initialize:
function WebGLBufferWrapper (gl, initialDataOrSize, bufferType, bufferUsage)
{
/**
* The WebGLBuffer being wrapped by this class.
*
* This property could change at any time.
* Therefore, you should never store a reference to this value.
* It should only be passed directly to the WebGL API for drawing.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLBufferWrapper#webGLBuffer
* @type {?WebGLBuffer}
* @default null
* @since 3.80.0
*/
this.webGLBuffer = null;
/**
* The WebGLRenderingContext that owns this WebGLBuffer.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLBufferWrapper#gl
* @type {WebGLRenderingContext}
* @since 3.80.0
*/
this.gl = gl;
/**
* The initial data or size of the buffer.
*
* Note that this will be used to recreate the buffer if the WebGL context is lost.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLBufferWrapper#initialDataOrSize
* @type {ArrayBuffer|number}
* @since 3.80.0
*/
this.initialDataOrSize = initialDataOrSize;
/**
* The type of the buffer.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLBufferWrapper#bufferType
* @type {GLenum}
* @since 3.80.0
*/
this.bufferType = bufferType;
/**
* The usage of the buffer. gl.DYNAMIC_DRAW, gl.STATIC_DRAW or gl.STREAM_DRAW.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLBufferWrapper#bufferUsage
* @type {GLenum}
* @since 3.80.0
*/
this.bufferUsage = bufferUsage;
this.createResource();
},
/**
* Creates a WebGLBuffer for this WebGLBufferWrapper.
*
* This is called automatically by the constructor. It may also be
* called again if the WebGLBuffer needs re-creating.
*
* @method Phaser.Renderer.WebGL.Wrappers.WebGLBufferWrapper#createResource
* @since 3.80.0
*/
createResource: function ()
{
if (this.initialDataOrSize === null) { return; }
var gl = this.gl;
var bufferType = this.bufferType;
var webGLBuffer = gl.createBuffer();
this.webGLBuffer = webGLBuffer;
gl.bindBuffer(bufferType, this.webGLBuffer);
gl.bufferData(bufferType, this.initialDataOrSize, this.bufferUsage);
gl.bindBuffer(bufferType, null);
},
/**
* Remove this WebGLBufferWrapper from the GL context.
*
* @method Phaser.Renderer.WebGL.Wrappers.WebGLBufferWrapper#destroy
* @since 3.80.0
*/
destroy: function ()
{
this.gl.deleteBuffer(this.webGLBuffer);
this.webGLBuffer = null;
this.initialDataOrSize = null;
this.gl = null;
}
});
module.exports = WebGLBufferWrapper;

View file

@ -0,0 +1,186 @@
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 (gl, width, height, renderTexture, addDepthStencilBuffer)
{
/**
* The WebGLFramebuffer being wrapped by this class.
*
* This property could change at any time.
* Therefore, you should never store a reference to this value.
* It should only be passed directly to the WebGL API for drawing.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLFramebufferWrapper#webGLFramebuffer
* @type {?WebGLFramebuffer}
* @default null
* @since 3.80.0
*/
this.webGLFramebuffer = null;
/**
* The WebGL context this WebGLFramebuffer belongs to.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLFramebufferWrapper#gl
* @type {WebGLRenderingContext}
* @since 3.80.0
*/
this.gl = gl;
/**
* 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 gl = this.gl;
var renderTexture = this.renderTexture;
var complete = 0;
var framebuffer = gl.createFramebuffer();
this.webGLFramebuffer = framebuffer;
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
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);
}
gl.bindFramebuffer(gl.FRAMEBUFFER, 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.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;
this.gl = null;
}
});
module.exports = WebGLFramebufferWrapper;

View file

@ -0,0 +1,135 @@
var Class = require('../../../utils/Class');
/**
* @classdesc
* Wrapper for a WebGL program, containing all the information that was used to create it.
*
* A WebGLProgram 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 WebGLProgramWrapper instead.
*
* @class WebGLProgramWrapper
* @memberof Phaser.Renderer.WebGL.Wrappers
* @constructor
* @since 3.80.0
*
* @param {WebGLRenderingContext} gl - The WebGLRenderingContext to create the WebGLProgram for.
* @param {string} vertexSource - The vertex shader source code as a string.
* @param {string} fragmentShader - The fragment shader source code as a string.
*/
var WebGLProgramWrapper = new Class({
initialize:
function WebGLProgramWrapper (gl, vertexSource, fragmentSource)
{
/**
* The WebGLProgram being wrapped by this class.
*
* This property could change at any time.
* Therefore, you should never store a reference to this value.
* It should only be passed directly to the WebGL API for drawing.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper#webGLProgram
* @type {?WebGLProgram}
* @default null
* @since 3.80.0
*/
this.webGLProgram = null;
/**
* The WebGLRenderingContext that owns this WebGLProgram.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper#gl
* @type {WebGLRenderingContext}
* @since 3.80.0
*/
this.gl = gl;
/**
* The vertex shader source code as a string.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper#vertexSource
* @type {string}
* @since 3.80.0
*/
this.vertexSource = vertexSource;
/**
* The fragment shader source code as a string.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper#fragmentSource
* @type {string}
* @since 3.80.0
*/
this.fragmentSource = fragmentSource;
this.createResource();
},
/**
* Creates a WebGLProgram from the given vertex and fragment shaders.
*
* This is called automatically by the constructor. It may also be
* called again if the WebGLProgram needs re-creating.
*
* @method Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper#createResource
* @throws {Error} If the shaders failed to compile or link.
* @since 3.80.0
*/
createResource: function ()
{
var gl = this.gl;
var program = gl.createProgram();
var vs = gl.createShader(gl.VERTEX_SHADER);
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(vs, this.vertexSource);
gl.shaderSource(fs, this.fragmentSource);
gl.compileShader(vs);
gl.compileShader(fs);
var failed = 'Shader failed:\n';
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS))
{
throw new Error('Vertex ' + failed + gl.getShaderInfoLog(vs));
}
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS))
{
throw new Error('Fragment ' + failed + gl.getShaderInfoLog(fs));
}
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS))
{
throw new Error('Link ' + failed + gl.getProgramInfoLog(program));
}
gl.useProgram(program);
this.webGLProgram = program;
},
/**
* Remove this WebGLProgram from the GL context.
*
* @method Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper#destroy
* @since 3.80.0
*/
destroy: function ()
{
if (!this.webGLProgram) { return; }
this.gl.deleteProgram(this.webGLProgram);
this.webGLProgram = null;
this.gl = null;
}
});
module.exports = WebGLProgramWrapper;

View file

@ -0,0 +1,388 @@
/**
* @author Benjamin D. Richards <benjamindrichards@gmail.com>
* @copyright 2013-2023 Photon Storm Ltd.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var Class = require('../../../utils/Class');
var IsSizePowerOfTwo = require('../../../math/pow2/IsSizePowerOfTwo');
/**
* @classdesc
* Wrapper for a WebGL texture, containing all the information that was used
* to create it.
*
* A WebGLTexture 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 WebGLTextureWrapper instead.
*
* @class GLTextureWrapper
* @memberof Phaser.Renderer.WebGL.Wrappers
* @constructor
* @since 3.80.0
*
* @param {WebGLRenderingContext} gl - WebGL context the texture belongs to.
* @param {number} mipLevel - Mip level of the texture.
* @param {number} minFilter - Filtering of the texture.
* @param {number} magFilter - Filtering of the texture.
* @param {number} wrapT - Wrapping mode of the texture.
* @param {number} wrapS - Wrapping mode of the texture.
* @param {number} format - Which format does the texture use.
* @param {?object} pixels - pixel data.
* @param {number} width - Width of the texture in pixels.
* @param {number} height - Height of the texture in pixels.
* @param {boolean} [pma=true] - Does the texture have premultiplied alpha?
* @param {boolean} [forceSize=false] - If `true` it will use the width and height passed to this method, regardless of the pixels dimension.
* @param {boolean} [flipY=false] - Sets the `UNPACK_FLIP_Y_WEBGL` flag the WebGL Texture uses during upload.
*/
var WebGLTextureWrapper = new Class({
initialize:
function WebGLTextureWrapper (gl, mipLevel, minFilter, magFilter, wrapT, wrapS, format, pixels, width, height, pma, forceSize, flipY)
{
/**
* The WebGLTexture that this wrapper is wrapping.
*
* This property could change at any time.
* Therefore, you should never store a reference to this value.
* It should only be passed directly to the WebGL API for drawing.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#webGLTexture
* @type {?WebGLTexture}
* @default null
* @since 3.80.0
*/
this.webGLTexture = null;
/**
* Whether this is used as a RenderTexture.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#isRenderTexture
* @type {boolean}
* @default false
* @since 3.80.0
*/
this.isRenderTexture = false;
/**
* The WebGL context this WebGLTexture belongs to.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#gl
* @type {WebGLRenderingContext}
* @since 3.80.0
*/
this.gl = gl;
/**
* Mip level of the texture.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#mipLevel
* @type {number}
* @since 3.80.0
*/
this.mipLevel = mipLevel;
/**
* Filtering of the texture.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#minFilter
* @type {number}
* @since 3.80.0
*/
this.minFilter = minFilter;
/**
* Filtering of the texture.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#magFilter
* @type {number}
* @since 3.80.0
*/
this.magFilter = magFilter;
/**
* Wrapping mode of the texture.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#wrapT
* @type {number}
* @since 3.80.0
*/
this.wrapT = wrapT;
/**
* Wrapping mode of the texture.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#wrapS
* @type {number}
* @since 3.80.0
*/
this.wrapS = wrapS;
/**
* Which format does the texture use.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#format
* @type {number}
* @since 3.80.0
*/
this.format = format;
/**
* Pixel data. This is the source data used to create the WebGLTexture.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#pixels
* @type {?object}
* @since 3.80.0
*/
this.pixels = pixels;
/**
* Width of the texture in pixels.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#width
* @type {number}
* @since 3.80.0
*/
this.width = width;
/**
* Height of the texture in pixels.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#height
* @type {number}
* @since 3.80.0
*/
this.height = height;
/**
* Does the texture have premultiplied alpha?
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#pma
* @type {boolean}
* @since 3.80.0
*/
this.pma = (pma === undefined || pma === null) ? true : pma;
/**
* Whether to use the width and height properties, regardless of pixel dimensions.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#forceSize
* @type {boolean}
* @since 3.80.0
*/
this.forceSize = !!forceSize;
/**
* Sets the `UNPACK_FLIP_Y_WEBGL` flag the WebGL Texture uses during upload.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#flipY
* @type {boolean}
* @since 3.80.0
*/
this.flipY = !!flipY;
/**
* Metadata for the SpectorJS tool, set if debug is enabled.
* You should set this via the `spectorMetadata` property,
* which will update the `__SPECTOR_Metadata` property on the WebGLTexture.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#__SPECTOR_Metadata
* @type {object}
* @private
* @since 3.80.0
*/
// eslint-disable-next-line camelcase
this.__SPECTOR_Metadata = {};
this.createResource();
},
/**
* Creates a WebGLTexture from the given parameters.
*
* This is called automatically by the constructor. It may also be
* called again if the WebGLTexture needs re-creating.
*
* @method Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#createResource
* @since 3.80.0
*/
createResource: function ()
{
if (this.pixels instanceof WebGLTextureWrapper)
{
// Use the source texture directly.
this.webGLTexture = this.pixels.webGLTexture;
return;
}
var gl = this.gl;
var texture = gl.createTexture();
gl.activeTexture(gl.TEXTURE0);
var currentTexture = gl.getParameter(gl.TEXTURE_BINDING_2D);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, this.minFilter);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, this.magFilter);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, this.wrapS);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, this.wrapT);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.pma);
if (this.flipY)
{
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
}
var pixels = this.pixels;
var mipLevel = this.mipLevel;
var width = this.width;
var height = this.height;
var format = this.format;
var generateMipmap = false;
if (pixels === null || pixels === undefined)
{
gl.texImage2D(gl.TEXTURE_2D, mipLevel, format, width, height, 0, format, gl.UNSIGNED_BYTE, null);
generateMipmap = IsSizePowerOfTwo(width, height);
}
else if (pixels.compressed)
{
width = pixels.width;
height = pixels.height;
generateMipmap = pixels.generateMipmap;
for (var i = 0; i < pixels.mipmaps.length; i++)
{
gl.compressedTexImage2D(gl.TEXTURE_2D, i, pixels.internalFormat, pixels.mipmaps[i].width, pixels.mipmaps[i].height, 0, pixels.mipmaps[i].data);
}
}
else if (pixels instanceof Uint8Array)
{
gl.texImage2D(gl.TEXTURE_2D, mipLevel, format, width, height, 0, format, gl.UNSIGNED_BYTE, pixels);
}
else
{
if (!this.forceSize)
{
width = pixels.width;
height = pixels.height;
}
gl.texImage2D(gl.TEXTURE_2D, mipLevel, format, format, gl.UNSIGNED_BYTE, pixels);
generateMipmap = IsSizePowerOfTwo(width, height);
}
if (generateMipmap)
{
gl.generateMipmap(gl.TEXTURE_2D);
}
// Set Spector metadata.
// eslint-disable-next-line camelcase
texture.__SPECTOR_Metadata = this.__SPECTOR_Metadata;
// Restore previous texture bind.
if (currentTexture)
{
gl.bindTexture(gl.TEXTURE_2D, currentTexture);
}
// Assign the texture to our wrapper.
this.webGLTexture = texture;
},
/**
* Updates the WebGLTexture from an updated source.
*
* This should only be used when the source is a Canvas or Video element.
*
* @method Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#update
* @since 3.80.0
*
* @param {HTMLCanvasElement|HTMLVideoElement} source - The source to update the WebGLTexture with.
* @param {number} width - The new width of the WebGLTexture.
* @param {number} height - The new height of the WebGLTexture.
* @param {boolean} [flipY] - Should the WebGLTexture set `UNPACK_MULTIPLY_FLIP_Y`?
*/
update: function (source, width, height, flipY)
{
if (width === 0 || height === 0) { return; }
var gl = this.gl;
gl.activeTexture(gl.TEXTURE0);
var currentTexture = gl.getParameter(gl.TEXTURE_BINDING_2D);
gl.bindTexture(gl.TEXTURE_2D, this.webGLTexture);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.pma);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source);
// Assume that the source might change.
this.pixels = source;
this.width = width;
this.height = height;
this.flipY = flipY;
// Restore previous texture bind.
if (currentTexture)
{
gl.bindTexture(gl.TEXTURE_2D, currentTexture);
}
},
/**
* The `__SPECTOR_Metadata` property of the `WebGLTexture`,
* used to add extra data to the debug SpectorJS integration.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#spectorMetadata
* @type {object}
* @since 3.80.0
*/
spectorMetadata: {
get: function ()
{
return this.__SPECTOR_Metadata;
},
set: function (value)
{
// eslint-disable-next-line camelcase
this.__SPECTOR_Metadata = value;
// eslint-disable-next-line camelcase
this.webGLTexture.__SPECTOR_Metadata = value;
}
},
/**
* Deletes the WebGLTexture from the GPU, if it has not been already.
*
* @method Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper#destroy
* @since 3.80.0
*/
destroy: function ()
{
if (this.webGLTexture === null)
{
return;
}
if (!(this.pixels instanceof WebGLTextureWrapper))
{
// Do not delete a texture that belongs to another wrapper.
this.gl.deleteTexture(this.webGLTexture);
}
this.pixels = null;
this.webGLTexture = null;
this.gl = null;
}
});
module.exports = WebGLTextureWrapper;

View file

@ -0,0 +1,101 @@
var Class = require('../../../utils/Class');
/**
* @classdesc
* Wrapper for a WebGL uniform location, containing all the information that was used to create it.
*
* A WebGLUniformLocation 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 WebGLUniformLocationWrapper instead.
*
* @class WebGLUniformLocationWrapper
* @memberof Phaser.Renderer.WebGL.Wrappers
* @constructor
* @since 3.80.0
*
* @param {WebGLRenderingContext} gl - The WebGLRenderingContext to create the WebGLUniformLocation for.
* @param {Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper} program - The WebGLProgram that this location refers to. This must be created first.
* @param {string} name - The name of this location, as defined in the shader source code.
*/
var WebGLUniformLocationWrapper = new Class({
initialize:
function WebGLUniformLocationWrapper (gl, program, name)
{
/**
* The WebGLUniformLocation being wrapped by this class.
*
* This property could change at any time.
* Therefore, you should never store a reference to this value.
* It should only be passed directly to the WebGL API for drawing.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLUniformLocationWrapper#webGLUniformLocation
* @type {?WebGLUniformLocation}
* @default null
* @since 3.80.0
*/
this.webGLUniformLocation = null;
/**
* The WebGLRenderingContext that owns this location.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper#gl
* @type {WebGLRenderingContext}
* @since 3.80.0
*/
this.gl = gl;
/**
* The WebGLProgram that this location refers to.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLUniformLocationWrapper#program
* @type {Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper}
* @since 3.80.0
*/
this.program = program;
/**
* The name of this location, as defined in the shader source code.
*
* @name Phaser.Renderer.WebGL.Wrappers.WebGLUniformLocationWrapper#name
* @type {string}
* @since 3.80.0
*/
this.name = name;
this.createResource();
},
/**
* Creates the WebGLUniformLocation.
*
* @method Phaser.Renderer.WebGL.Wrappers.WebGLUniformLocationWrapper#createResource
* @since 3.80.0
*/
createResource: function ()
{
if (this.program.webGLProgram === null)
{
this.webGLUniformLocation = null;
return;
}
this.webGLUniformLocation = this.gl.getUniformLocation(this.program.webGLProgram, this.name);
},
/**
* Destroys this WebGLUniformLocationWrapper.
*
* @method Phaser.Renderer.WebGL.Wrappers.WebGLUniformLocationWrapper#destroy
* @since 3.80.0
*/
destroy: function ()
{
this.gl = null;
this.program = null;
this.name = null;
this.webGLUniformLocation = null;
}
});
module.exports = WebGLUniformLocationWrapper;

View file

@ -0,0 +1,20 @@
/**
* @author Benjamin D. Richards <benjamindrichards@gmail.com>
* @copyright 2013-2023 Photon Storm Ltd.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
/**
* @namespace Phaser.Renderer.WebGL.Wrappers
*/
var Wrappers = {
WebGLAttribLocationWrapper: require('./WebGLAttribLocationWrapper'),
WebGLBufferWrapper: require('./WebGLBufferWrapper'),
WebGLProgramWrapper: require('./WebGLProgramWrapper'),
WebGLTextureWrapper: require('./WebGLTextureWrapper'),
WebGLFramebufferWrapper: require('./WebGLFramebufferWrapper'),
WebGLUniformLocationWrapper: require('./WebGLUniformLocationWrapper')
};
module.exports = Wrappers;

View file

@ -273,7 +273,7 @@ var DynamicTexture = new Class({
if (renderTarget.texture !== source.glTexture) if (renderTarget.texture !== source.glTexture)
{ {
// The WebGLTexture has been resized, so is new, so we need to delete the old one // The texture has been resized, so is new, so we need to delete the old one
this.renderer.deleteTexture(source.glTexture); this.renderer.deleteTexture(source.glTexture);
} }
@ -328,9 +328,6 @@ var DynamicTexture = new Class({
var source = frame.source; var source = frame.source;
var renderTarget = this.renderTarget; var renderTarget = this.renderTarget;
// Then we can apply the new one
frame.glTexture = renderTarget.texture;
source.isRenderTexture = true; source.isRenderTexture = true;
source.isGLTexture = true; source.isGLTexture = true;
@ -1548,12 +1545,12 @@ var DynamicTexture = new Class({
}, },
/** /**
* Returns the underlying WebGLTexture, if not running in Canvas mode. * Returns the underlying WebGLTextureWrapper, if not running in Canvas mode.
* *
* @method Phaser.Textures.DynamicTexture#getWebGLTexture * @method Phaser.Textures.DynamicTexture#getWebGLTexture
* @since 3.60.0 * @since 3.60.0
* *
* @return {?WebGLTexture} The underlying WebGLTexture, if not running in Canvas mode. * @return {?Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper} The underlying WebGLTextureWrapper, if not running in Canvas mode.
*/ */
getWebGLTexture: function () getWebGLTexture: function ()
{ {

View file

@ -68,16 +68,6 @@ var Frame = new Class({
*/ */
this.sourceIndex = sourceIndex; this.sourceIndex = sourceIndex;
/**
* A reference to the Texture Source WebGL Texture that this Frame is using.
*
* @name Phaser.Textures.Frame#glTexture
* @type {?WebGLTexture}
* @default null
* @since 3.11.0
*/
this.glTexture = this.source.glTexture;
/** /**
* X position within the source image to cut from. * X position within the source image to cut from.
* *
@ -794,11 +784,26 @@ var Frame = new Class({
{ {
this.texture = null; this.texture = null;
this.source = null; this.source = null;
this.glTexture = null;
this.customData = null; this.customData = null;
this.data = null; this.data = null;
}, },
/**
* A reference to the Texture Source WebGL Texture that this Frame is using.
*
* @name Phaser.Textures.Frame#glTexture
* @type {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper}
* @readonly
* @since 3.11.0
*/
glTexture: {
get: function ()
{
return this.source.glTexture;
}
},
/** /**
* The width of the Frame in its un-trimmed, un-padded state, as prepared in the art package, * The width of the Frame in its un-trimmed, un-padded state, as prepared in the art package,
* before being packed. * before being packed.

View file

@ -32,7 +32,7 @@ var TEXTURE_MISSING_ERROR = 'Texture "%s" has no frame "%s"';
* *
* @param {Phaser.Textures.TextureManager} manager - A reference to the Texture Manager this Texture belongs to. * @param {Phaser.Textures.TextureManager} manager - A reference to the Texture Manager this Texture belongs to.
* @param {string} key - The unique string-based key of this Texture. * @param {string} key - The unique string-based key of this Texture.
* @param {(HTMLImageElement|HTMLCanvasElement|HTMLImageElement[]|HTMLCanvasElement[])} source - An array of sources that are used to create the texture. Usually Images, but can also be a Canvas. * @param {(HTMLImageElement|HTMLCanvasElement|HTMLImageElement[]|HTMLCanvasElement[]|Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper)} source - An array of sources that are used to create the texture. Usually Images, but can also be a Canvas.
* @param {number} [width] - The width of the Texture. This is optional and automatically derived from the source images. * @param {number} [width] - The width of the Texture. This is optional and automatically derived from the source images.
* @param {number} [height] - The height of the Texture. This is optional and automatically derived from the source images. * @param {number} [height] - The height of the Texture. This is optional and automatically derived from the source images.
*/ */

View file

@ -464,34 +464,33 @@ var TextureManager = new Class({
}, },
/** /**
* Takes a WebGL Texture and creates a Phaser Texture from it, which is added to the Texture Manager using the given key. * Takes a WebGLTextureWrapper and creates a Phaser Texture from it, which is added to the Texture Manager using the given key.
* *
* This allows you to then use the Texture as a normal texture for texture based Game Objects like Sprites. * This allows you to then use the Texture as a normal texture for texture based Game Objects like Sprites.
* *
* If the `width` and `height` arguments are omitted, but the WebGL Texture was created by Phaser's WebGL Renderer
* and has `glTexture.width` and `glTexture.height` properties, these values will be used instead.
*
* This is a WebGL only feature. * This is a WebGL only feature.
*
* Prior to Phaser 3.80.0, this method took a bare `WebGLTexture`
* as the `glTexture` parameter. You must now wrap the `WebGLTexture` in a
* `WebGLTextureWrapper` instance before passing it to this method.
* *
* @method Phaser.Textures.TextureManager#addGLTexture * @method Phaser.Textures.TextureManager#addGLTexture
* @fires Phaser.Textures.Events#ADD * @fires Phaser.Textures.Events#ADD
* @since 3.19.0 * @since 3.19.0
* *
* @param {string} key - The unique string-based key of the Texture. * @param {string} key - The unique string-based key of the Texture.
* @param {WebGLTexture} glTexture - The source Render Texture. * @param {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper} glTexture - The source Render Texture.
* @param {number} [width] - The new width of the Texture. Read from `glTexture.width` if omitted.
* @param {number} [height] - The new height of the Texture. Read from `glTexture.height` if omitted.
* *
* @return {?Phaser.Textures.Texture} The Texture that was created, or `null` if the key is already in use. * @return {?Phaser.Textures.Texture} The Texture that was created, or `null` if the key is already in use.
*/ */
addGLTexture: function (key, glTexture, width, height) addGLTexture: function (key, glTexture)
{ {
var texture = null; var texture = null;
if (this.checkKey(key)) if (this.checkKey(key))
{ {
if (width === undefined) { width = glTexture.width; } var width = glTexture.width;
if (height === undefined) { height = glTexture.height; } var height = glTexture.height;
texture = this.create(key, glTexture, width, height); texture = this.create(key, glTexture, width, height);
@ -1145,6 +1144,45 @@ var TextureManager = new Class({
} }
}, },
/**
* Creates a texture from an array of colour data.
*
* This is only available in WebGL mode.
*
* If the dimensions provided are powers of two, the resulting texture
* will be automatically set to wrap by the WebGL Renderer.
*
* @method Phaser.Textures.TextureManager#addUint8Array
* @fires Phaser.Textures.Events#ADD
* @since 3.80.0
*
* @param {string} key - The unique string-based key of the Texture.
* @param {Uint8Array} data - The color data for the texture.
* @param {number} width - The width of the texture.
* @param {number} height - The height of the texture.
*
* @return {?Phaser.Textures.Texture} The Texture that was created, or `null` if the key is already in use.
*/
addUint8Array: function (key, data, width, height)
{
if (
!this.checkKey(key) ||
data.length / 4 !== width * height
)
{
return null;
}
var texture = this.create(key, data, width, height);
texture.add('__BASE', 0, 0, 0, width, height);
this.emit(Events.ADD, key, texture);
this.emit(Events.ADD_KEY + key, texture);
return texture;
},
/** /**
* Creates a new Texture using the given source and dimensions. * Creates a new Texture using the given source and dimensions.
* *
@ -1152,7 +1190,7 @@ var TextureManager = new Class({
* @since 3.0.0 * @since 3.0.0
* *
* @param {string} key - The unique string-based key of the Texture. * @param {string} key - The unique string-based key of the Texture.
* @param {(HTMLImageElement|HTMLCanvasElement|HTMLImageElement[]|HTMLCanvasElement[])} source - An array of sources that are used to create the texture. Usually Images, but can also be a Canvas. * @param {(HTMLImageElement|HTMLCanvasElement|HTMLImageElement[]|HTMLCanvasElement[]|Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper)} source - An array of sources that are used to create the texture. Usually Images, but can also be a Canvas.
* @param {number} [width] - The width of the Texture. This is optional and automatically derived from the source images. * @param {number} [width] - The width of the Texture. This is optional and automatically derived from the source images.
* @param {number} [height] - The height of the Texture. This is optional and automatically derived from the source images. * @param {number} [height] - The height of the Texture. This is optional and automatically derived from the source images.
* *

View file

@ -8,6 +8,7 @@ var CanvasPool = require('../display/canvas/CanvasPool');
var Class = require('../utils/Class'); var Class = require('../utils/Class');
var IsSizePowerOfTwo = require('../math/pow2/IsSizePowerOfTwo'); var IsSizePowerOfTwo = require('../math/pow2/IsSizePowerOfTwo');
var ScaleModes = require('../renderer/ScaleModes'); var ScaleModes = require('../renderer/ScaleModes');
var WebGLTextureWrapper = require('../renderer/webgl/wrappers/WebGLTextureWrapper');
/** /**
* @classdesc * @classdesc
@ -23,7 +24,7 @@ var ScaleModes = require('../renderer/ScaleModes');
* @since 3.0.0 * @since 3.0.0
* *
* @param {Phaser.Textures.Texture} texture - The Texture this TextureSource belongs to. * @param {Phaser.Textures.Texture} texture - The Texture this TextureSource belongs to.
* @param {(HTMLImageElement|HTMLCanvasElement|HTMLVideoElement|Phaser.GameObjects.RenderTexture|WebGLTexture|Phaser.Types.Textures.CompressedTextureData|Phaser.Textures.DynamicTexture)} source - The source image data. * @param {(HTMLImageElement|HTMLCanvasElement|HTMLVideoElement|Phaser.GameObjects.RenderTexture|Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper|Phaser.Types.Textures.CompressedTextureData|Phaser.Textures.DynamicTexture)} source - The source image data.
* @param {number} [width] - Optional width of the source image. If not given it's derived from the source itself. * @param {number} [width] - Optional width of the source image. If not given it's derived from the source itself.
* @param {number} [height] - Optional height of the source image. If not given it's derived from the source itself. * @param {number} [height] - Optional height of the source image. If not given it's derived from the source itself.
* @param {boolean} [flipY=false] - Sets the `UNPACK_FLIP_Y_WEBGL` flag the WebGL Texture uses during upload. * @param {boolean} [flipY=false] - Sets the `UNPACK_FLIP_Y_WEBGL` flag the WebGL Texture uses during upload.
@ -59,12 +60,12 @@ var TextureSource = new Class({
/** /**
* The source of the image data. * The source of the image data.
* *
* This is either an Image Element, a Canvas Element, a Video Element, a RenderTexture or a WebGLTexture. * This is either an Image Element, a Canvas Element, a Video Element, a RenderTexture or a WebGLTextureWrapper.
* *
* In Phaser 3.60 and above it can also be a Compressed Texture data object. * In Phaser 3.60 and above it can also be a Compressed Texture data object.
* *
* @name Phaser.Textures.TextureSource#source * @name Phaser.Textures.TextureSource#source
* @type {(HTMLImageElement|HTMLCanvasElement|HTMLVideoElement|Phaser.GameObjects.RenderTexture|WebGLTexture|Phaser.Types.Textures.CompressedTextureData|Phaser.Textures.DynamicTexture)} * @type {(HTMLImageElement|HTMLCanvasElement|HTMLVideoElement|Phaser.GameObjects.RenderTexture|Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper|Phaser.Types.Textures.CompressedTextureData|Phaser.Textures.DynamicTexture)}
* @since 3.12.0 * @since 3.12.0
*/ */
this.source = source; this.source = source;
@ -72,10 +73,10 @@ var TextureSource = new Class({
/** /**
* The image data. * The image data.
* *
* This is either an Image element, Canvas element or a Video Element. * This is either an Image element, Canvas element, Video Element, or Uint8Array.
* *
* @name Phaser.Textures.TextureSource#image * @name Phaser.Textures.TextureSource#image
* @type {(HTMLImageElement|HTMLCanvasElement|HTMLVideoElement)} * @type {(HTMLImageElement|HTMLCanvasElement|HTMLVideoElement|Uint8Array)}
* @since 3.0.0 * @since 3.0.0
*/ */
this.image = (source.compressed) ? null : source; this.image = (source.compressed) ? null : source;
@ -160,13 +161,13 @@ var TextureSource = new Class({
this.isRenderTexture = (source.type === 'RenderTexture' || source.type === 'DynamicTexture'); this.isRenderTexture = (source.type === 'RenderTexture' || source.type === 'DynamicTexture');
/** /**
* Is the source image a WebGLTexture? * Is the source image a WebGLTextureWrapper?
* *
* @name Phaser.Textures.TextureSource#isGLTexture * @name Phaser.Textures.TextureSource#isGLTexture
* @type {boolean} * @type {boolean}
* @since 3.19.0 * @since 3.19.0
*/ */
this.isGLTexture = (window.hasOwnProperty('WebGLTexture') && source instanceof WebGLTexture); this.isGLTexture = source instanceof WebGLTextureWrapper;
/** /**
* Are the source image dimensions a power of two? * Are the source image dimensions a power of two?
@ -178,11 +179,12 @@ var TextureSource = new Class({
this.isPowerOf2 = IsSizePowerOfTwo(this.width, this.height); this.isPowerOf2 = IsSizePowerOfTwo(this.width, this.height);
/** /**
* The WebGL Texture of the source image. If this TextureSource is driven from a WebGLTexture * The wrapped WebGL Texture of the source image.
* already, then this is a reference to that WebGLTexture. * If this TextureSource is driven from a WebGLTexture already,
* then this wrapper contains a reference to that WebGLTexture.
* *
* @name Phaser.Textures.TextureSource#glTexture * @name Phaser.Textures.TextureSource#glTexture
* @type {?WebGLTexture} * @type {?Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper}
* @default null * @default null
* @since 3.0.0 * @since 3.0.0
*/ */
@ -244,6 +246,10 @@ var TextureSource = new Class({
{ {
this.glTexture = renderer.createTextureFromSource(source); this.glTexture = renderer.createTextureFromSource(source);
} }
else if (source instanceof Uint8Array)
{
this.glTexture = renderer.createUint8ArrayTexture(source, width, height, scaleMode);
}
else else
{ {
this.glTexture = renderer.createTextureFromSource(image, width, height, scaleMode); this.glTexture = renderer.createTextureFromSource(image, width, height, scaleMode);
@ -251,8 +257,7 @@ var TextureSource = new Class({
if (typeof WEBGL_DEBUG) if (typeof WEBGL_DEBUG)
{ {
// eslint-disable-next-line camelcase this.glTexture.spectorMetadata = { textureKey: this.texture.key };
this.glTexture.__SPECTOR_Metadata = { textureKey: this.texture.key };
} }
} }
else if (this.isRenderTexture) else if (this.isRenderTexture)
@ -322,11 +327,11 @@ var TextureSource = new Class({
if (gl && this.isCanvas) if (gl && this.isCanvas)
{ {
this.glTexture = renderer.updateCanvasTexture(image, this.glTexture, flipY); renderer.updateCanvasTexture(image, this.glTexture, flipY);
} }
else if (gl && this.isVideo) else if (gl && this.isVideo)
{ {
this.glTexture = renderer.updateVideoTexture(image, this.glTexture, flipY); renderer.updateVideoTexture(image, this.glTexture, flipY);
} }
}, },

View file

@ -148,7 +148,7 @@ var Tileset = new Class({
* The gl texture used by the WebGL renderer. * The gl texture used by the WebGL renderer.
* *
* @name Phaser.Tilemaps.Tileset#glTexture * @name Phaser.Tilemaps.Tileset#glTexture
* @type {?WebGLTexture} * @type {?Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper}
* @readonly * @readonly
* @since 3.11.0 * @since 3.11.0
*/ */