Texture batching during the batch flush has been implemented in the TextureTintPipeline which resolves the issues of very low frame rates, especially on iOS devices, when using non-batched textures such as those used by Text or TileSprites.

This commit is contained in:
Richard Davey 2018-10-12 15:06:10 +01:00
parent 8faafc2ceb
commit 4beffe842a
2 changed files with 150 additions and 7 deletions

View file

@ -15,6 +15,7 @@
* `TileSprite.setFrame` has had both the `updateSize` and `updateOrigin` arguments removed as they didn't do anything for TileSprites and were misleading.
* `CameraManager.remove` has a new argument `runDestroy` which, if set, will automatically call `Camera.destroy` on the Cameras removed from the Camera Manager. You should nearly always allow this to happen (thanks jamespierce)
* Device.OS has been restructured to allow fake UAs from Chrome dev tools to register iOS devices.
* Texture batching during the batch flush has been implemented in the TextureTintPipeline which resolves the issues of very low frame rates, especially on iOS devices, when using non-batched textures such as those used by Text or TileSprites. Fix #4110 #4086 (thanks @ivan @sachinhosmani @maximtsai @alexeymolchan)
### Bug Fixes
@ -22,6 +23,7 @@
* If you set `pixelArt` to true in your game config (or `antialias` to false) then TileSprites will now respect this when using the Canvas Renderer and disable smoothing on the internal fill canvas.
* TileSprites that were set to be interactive before they had rendered once wouldn't receive a valid input hit area, causing input to fail. They now define their size immediately, allowing them to be made interactive without having rendered. Fix #4085 (thanks @DotTheGreat)
* The Particle Emitter Manager has been given a NOOP method called `setBlendMode` to stop warnings from being thrown if you added an emitter to a Container in the Canvas renderer. Fix #4083 (thanks @maximtsai)
*
### Examples and TypeScript

View file

@ -121,6 +121,15 @@ var TextureTintPipeline = new Class({
*/
this.maxQuads = rendererConfig.batchSize;
/**
* Collection of batch information
*
* @name Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline#batches
* @type {array}
* @since 3.1.0
*/
this.batches = [];
/**
* A temporary Transform Matrix, re-used internally during batching.
*
@ -269,6 +278,11 @@ var TextureTintPipeline = new Class({
this.mvpUpdate();
if (this.batches.length === 0)
{
this.pushBatch();
}
return this;
},
@ -307,11 +321,65 @@ var TextureTintPipeline = new Class({
*/
setTexture2D: function (texture, unit)
{
this.renderer.setTexture2D(texture, unit);
if (!texture)
{
texture = this.renderer.blankTexture.glTexture;
unit = 0;
}
var batches = this.batches;
if (batches.length === 0)
{
this.pushBatch();
}
var batch = batches[batches.length - 1];
if (unit > 0)
{
if (batch.textures[unit - 1] &&
batch.textures[unit - 1] !== texture)
{
this.pushBatch();
}
batches[batches.length - 1].textures[unit - 1] = texture;
}
else
{
if (batch.texture !== null &&
batch.texture !== texture)
{
this.pushBatch();
}
batches[batches.length - 1].texture = texture;
}
return this;
},
/**
* Creates a new batch object and pushes it to a batch array.
* The batch object contains information relevant to the current
* vertex batch like the offset in the vertex buffer, vertex count and
* the textures used by that batch.
*
* @method Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline#pushBatch
* @since 3.1.0
*/
pushBatch: function ()
{
var batch = {
first: this.vertexCount,
texture: null,
textures: []
};
this.batches.push(batch);
},
/**
* Uploads the vertex data and emits a draw call for the current batch of vertices.
*
@ -322,7 +390,10 @@ var TextureTintPipeline = new Class({
*/
flush: function ()
{
if (this.flushLocked) { return this; }
if (this.flushLocked)
{
return this;
}
this.flushLocked = true;
@ -332,18 +403,88 @@ var TextureTintPipeline = new Class({
var vertexSize = this.vertexSize;
var renderer = this.renderer;
if (vertexCount === 0)
var batches = this.batches;
var batchCount = batches.length;
var batchVertexCount = 0;
var batch = null;
var batchNext;
var textureIndex;
var nTexture;
if (batchCount === 0 || vertexCount === 0)
{
this.flushLocked = false;
return;
return this;
}
renderer.setBlankTexture();
gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.bytes.subarray(0, vertexCount * vertexSize));
gl.drawArrays(topology, 0, vertexCount);
for (var index = 0; index < batches.length - 1; index++)
{
batch = batches[index];
batchNext = batches[index + 1];
if (batch.textures.length > 0)
{
for (textureIndex = 0; textureIndex < batch.textures.length; ++textureIndex)
{
nTexture = batch.textures[textureIndex];
if (nTexture)
{
renderer.setTexture2D(nTexture, 1 + textureIndex);
}
}
gl.activeTexture(gl.TEXTURE0);
}
batchVertexCount = batchNext.first - batch.first;
if (batch.texture === null || batchVertexCount <= 0)
{
continue;
}
renderer.setTexture2D(batch.texture, 0);
gl.drawArrays(topology, batch.first, batchVertexCount);
}
// Left over data
batch = batches[batches.length - 1];
if (batch.textures.length > 0)
{
for (textureIndex = 0; textureIndex < batch.textures.length; ++textureIndex)
{
nTexture = batch.textures[textureIndex];
if (nTexture)
{
renderer.setTexture2D(nTexture, 1 + textureIndex);
}
}
gl.activeTexture(gl.TEXTURE0);
}
batchVertexCount = vertexCount - batch.first;
if (batch.texture && batchVertexCount > 0)
{
renderer.setTexture2D(batch.texture, 0);
gl.drawArrays(topology, batch.first, batchVertexCount);
}
this.vertexCount = 0;
batches.length = 0;
this.pushBatch();
this.flushLocked = false;
return this;