phaserjs / phaser-ce

Phaser CE is a fun, free and fast 2D game framework for making HTML5 games for desktop and mobile web browsers, supporting Canvas and WebGL rendering.
http://phaser.io
MIT License
1.34k stars 491 forks source link

WebGL: INVALID_VALUE: vertexAttribPointer: index out of range (Ubuntu) #194

Open ColaColin opened 7 years ago

ColaColin commented 7 years ago

A bug in the API:

I am getting WebGL: INVALID_VALUE: vertexAttribPointer: index out of range spam on Firefox as well as on Chromium, running Ubuntu.

There is no condition for it to happen. It just happens always. A "code example" therefore simply is the empty example codepen: https://codepen.io/pen?template=vyKJvw

There is nothing obvious wrong, except those errors being spammed.

Here is the stacktrace from chromium, referencing lines in phaser-arcade-physics.js of 2.7.7:

PIXI.WebGLSpriteBatch.flush @ phaser.js:5153 PIXI.WebGLSpriteBatch.end @ phaser.js:4806 PIXI.WebGLRenderer.renderDisplayObject @ phaser.js:3742 PIXI.WebGLRenderer.render @ phaser.js:3705 updateRender @ phaser.js:21403 update @ phaser.js:21325 updateRAF @ phaser.js:49064 _onLoop @ phaser.js:49047

It happens due to shader.aTextureIndex in the line gl.vertexAttribPointer(shader.aTextureIndex, 1, gl.FLOAT, false, stride, 20); being -1

It is -1 because the getAttributeLocation earlier does indeed seem to return -1 I have no idea why that is however. It reminds me of an issue I had in other WebGL code that was due to some attributes being optimized away since they were not used, but the shader code of the respective shader here does seem to at least superficially use the attribute.

The minimal code to create the issue is to have Phaser in your namespace and start it with:

new Phaser.Game({width: 10, height: 10, renderer: Phaser.AUTO, resolution: 1})

From that point on it spams the warning.

I tested 2.7.7 and 2.7.3, both show the error. 2.6.2 is unaffected

samme commented 7 years ago

new Phaser.Game({width: 10, height: 10, renderer: Phaser.AUTO, resolution: 1})

I don't see the warning in my Firefox (https://codepen.io/samme/pen/eWWWdz) so it may be platform-specific.

v2.7.7/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js#L58

samme commented 7 years ago

Can you try

new Phaser.Game({enableDebug: false});

?

softmixt commented 7 years ago

I get the same error here too

phaser.js:18791 WebGL: INVALID_VALUE: vertexAttribPointer: index out of range

I use chrome debug console tool , ubuntu 16.4 LTS

samme commented 7 years ago

@softmixt Which platform/OS?

softmixt commented 7 years ago

Ubuntu 16.4 LTS

softmixt commented 7 years ago

seleccion_031

ColaColin commented 7 years ago

My problem system also runs Ubuntu 16.4 LTS, with a Nvidia GTX 960.

The same machine on Windows 7 does not show the error, neither in Chrome nor in Firefox.

I can try new Phaser.Game({enableDebug: false}); later, as in within 24h.

samme commented 7 years ago

Here is enableDebug: false: https://codepen.io/samme/pen/EmmwGo

softmixt commented 7 years ago

I get back to version v2.6.2 for now I'm going to check it later v2.7.7 using {enableDebug: false} and my g. card is GeForce GTX 1060 6GB/PCIe/SSE2 and I tried all available versions after 2.6.2 and all gave me same error .

ColaColin commented 7 years ago

Running https://codepen.io/samme/pen/EmmwGo does not show any errors anywhere, whatever enableDebug does, setting it to false makes the errors go away.

softmixt commented 7 years ago

Error show when I bind a new state like this :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <title>Hello Phaser</title>
    <script src="phaser.min.js"></script>
    <script>
    window.onload = function() {

            var StateExample = function ( game ){};

            /**
            * @type {{init: Boot.init, preload: Boot.preload, create: Boot.create}}
            */
            StateExample.prototype = {

                    /**
                     * Set Game initialization settings
                     */
                    init: function ()
                    {
                        //this.input.maxPointers = 1;
                        //this.game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
                    },
                    preload: function ()
                    {
                         // Example Assets
                         this.game.load.image( 'phaser_logo', 'img.png' );

                    },
                    create: function ()
                    {
                        // Set background for our game
                        this.phaser_logo        = this.game.add.sprite( 100, 150, 'phaser_logo' );
                    }

            };

            var game = new Phaser.Game( {
                                enableDebug: false,
                                width: 800,
                                height: 600,
                                renderer: Phaser.AUTO,
                                parent: "game",
                                transparent: true,
                                antialias: true,
                                        } );

              game.state.add( "StateExample", StateExample );

              game.state.start( "StateExample" );
    };

    </script>
</head>
<body>
<div id="game"></div>
</body>
</html>

this use v2.7.7 if I use v2.6.2 error doesn't show up anymore :(

the result of that code in chrome is this : seleccion_037

and result same code in firefox is this : seleccion_038

samme commented 7 years ago

The debug canvas is drawn each frame unless it's disabled (via enableDebug: false) so that's probably what's causing it in an "empty" game.

If you set a breakpoint on the line that's emitting the warning (INVALID_VALUE…) you should be able to see which render object it's linked to.

TheSuspiciousWombat commented 7 years ago

I have the same issue under Arch Linux in chrome and i get errors in firefox aswell

softmixt commented 7 years ago

Even with enableDebug: false still shows the error, so checking a bit what line comes that i doscover it comming from this part :

PIXI.WebGLSpriteBatch.prototype.flush = function () {
    // If the batch is length 0 then return as there is nothing to draw
    if (this.currentBatchSize === 0) {
        return;
    }

    var gl = this.gl;
    var shader;

    if (this.dirty) {
        this.dirty = false;

        shader = this.defaultShader.shaders[gl.id];

        // bind the main texture
        gl.activeTexture(gl.TEXTURE0);

        // bind the buffers
        gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
        // this is the same for each shader?
        var stride = this.vertexSize; //this.vertSize * 4;
        gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, stride, 0);
        gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, stride, 8);

        // color attributes will be interpreted as unsigned bytes and normalized
        gl.vertexAttribPointer(shader.colorAttribute, 4, gl.UNSIGNED_BYTE, true, stride, 16);

        // Texture index
        gl.vertexAttribPointer(shader.aTextureIndex, 1, gl.FLOAT, false, stride, 20);
    }

for this function : gl.vertexAttribPointer(shader.aTextureIndex, 1, gl.FLOAT, false, stride, 20); parametet value for shader.aTextureIndex it is -1 so what i did is that i add a conditional check for shader.aTextureIndex hope solve that console info annoying alert seleccion_002

Leprosy commented 7 years ago

Same issue on Ubuntu, on FF and Chrome. Both using phaser 2.7.7 and 2.7.10

MariusAlch commented 7 years ago

Getting same issue. Chrome, Ubuntu GNOME.

kidasov commented 7 years ago

Ubuntu 17.04, Chrome 59.0.3071.115. Still having this issue. Using phaser 2.8.5. Do exist a workaround to make it work properly?

samme commented 7 years ago

Ultimately someone needs to figure out why the aTextureIndex attribute value is missing.

If you just want to silence the error, you can overwrite PIXI.WebGLSpriteBatch#flush: https://gist.github.com/samme/c4d0928c94a345976ee022884b2bce58

oskude commented 6 years ago

found something. assuming this is the latest non ce version of phaser: https://github.com/photonstorm/phaser/blob/master/v2/src/pixi/renderers/webgl/shaders/PixiShader.js#L102-L118

// get and store the attributes
this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition');
this.aTextureCoord = gl.getAttribLocation(program, 'aTextureCoord');
this.colorAttribute = gl.getAttribLocation(program, 'aColor');

// Begin worst hack eva //

// WHY??? ONLY on my chrome pixel the line above returns -1 when using filters?
// maybe its something to do with the current state of the gl context.
// I'm convinced this is a bug in the chrome browser as there is NO reason why this should be returning -1 especially as it only manifests on my chrome pixel
// If theres any webGL people that know why could happen please help :)
if(this.colorAttribute === -1)
{
     this.colorAttribute = 2;
}

this.attributes = [this.aVertexPosition, this.aTextureCoord, this.colorAttribute];

there is a comment about "line above returns -1", and in that repo the direct line above the comment is:

this.colorAttribute = gl.getAttribLocation(program, 'aColor');

comparing with current ce master: https://github.com/photonstorm/phaser-ce/blob/master/src/pixi/renderers/webgl/shaders/PixiShader.js#L191-L209

// get and store the attributes
this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition');
this.aTextureCoord = gl.getAttribLocation(program, 'aTextureCoord');
this.colorAttribute = gl.getAttribLocation(program, 'aColor');
this.aTextureIndex = gl.getAttribLocation(program, 'aTextureIndex');

// Begin worst hack eva //

// WHY??? ONLY on my chrome pixel the line above returns -1 when using filters?
// maybe its something to do with the current state of the gl context.
// I'm convinced this is a bug in the chrome browser as there is NO reason why this should be returning -1 especially as it only manifests on my chrome pixel
// If theres any webGL people that know why could happen please help :)
if(this.colorAttribute === -1)
{
     this.colorAttribute = 2;
}

this.attributes = [this.aVertexPosition, this.aTextureCoord, this.colorAttribute, this.aTextureIndex];

the direct line above would be:

this.aTextureIndex = gl.getAttribLocation(program, 'aTextureIndex');

but thats probably irrelevant, but interestingly on my linux chromium 61.0.3163.100 this.colorAttribute is always 2 (before the if), but this.aTextureIndex is always -1, hmmm...

after some trial and error, this seems to work for me:

diff --git a/src/pixi/renderers/webgl/shaders/PixiShader.js b/src/pixi/renderers/webgl/shaders/PixiShader.js
index 92197a766..7161ce7d3 100644
--- a/src/pixi/renderers/webgl/shaders/PixiShader.js
+++ b/src/pixi/renderers/webgl/shaders/PixiShader.js
@@ -206,10 +206,16 @@ PIXI.PixiShader.prototype.initDefaultShader = function () {
         this.colorAttribute = 2;
     }

-    this.attributes = [this.aVertexPosition, this.aTextureCoord, this.colorAttribute, this.aTextureIndex];
-
     // End worst hack eva //

+    // this might be related to above `this.colorAttribute === -1` bug?
+    if(this.aTextureIndex === -1)
+    {
+        this.aTextureIndex = 3;
+    }
+
+    this.attributes = [this.aVertexPosition, this.aTextureCoord, this.colorAttribute, this.aTextureIndex];
+
     // add those custom shaders!
     for (var key in this.uniforms)
     {
makryl commented 6 years ago

I found discussion about same issue https://www.gamedev.net/forums/topic/524172-glgetattriblocation-and-a--1-return-value/ Looks like compiler optimizes shader code, and removes unused variable. If you look at shader code that used for NON-multi-textured case Vertex shader:

PIXI.PixiShader.defaultVertexSrc = [
    '// PixiShader Vertex Shader',
    '// With multi-texture rendering',
    'attribute vec2 aVertexPosition;',
    'attribute vec2 aTextureCoord;',
    'attribute vec4 aColor;',
    'attribute float aTextureIndex;',

    'uniform vec2 projectionVector;',
    'uniform vec2 offsetVector;',

    'varying vec2 vTextureCoord;',
    'varying vec4 vColor;',
    'varying float vTextureIndex;',

    'const vec2 center = vec2(-1.0, 1.0);',

    'void main(void) {',
    '   if (aTextureIndex > 0.0) gl_Position = vec4(0.0);',
    '   gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);',
    '   vTextureCoord = aTextureCoord;',
    '   vColor = vec4(aColor.rgb * aColor.a, aColor.a);',
    '   vTextureIndex = aTextureIndex;',
    '}'
];

aTextureIndex attribute used only to assigns value to vTextureIndex and vTextureIndex is not used in fragment shader

this.fragmentSrc = [
            'precision lowp float;',
            'varying vec2 vTextureCoord;',
            'varying vec4 vColor;',
            'varying float vTextureIndex;',
            'uniform sampler2D uSampler;',
            'void main(void) {',
            '   gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;',
            '}'
        ];

This variable used only in multi-textured shader, and in non-multi-textured shader compiler just removes vTextureIndex and aTextureIndex to optimize code. Thats why

this.aTextureIndex = gl.getAttribLocation(program, 'aTextureIndex');

returns -1 We should make check as it already done for aColor attribute:

if(this.colorAttribute === -1)
    {
        this.colorAttribute = 2;
    }

right after that I suggest to add a check, same as patch in previous comment

if(this.aTextureIndex === -1)
    {
        this.aTextureIndex = 3;
    }

So, this is not "worst hack eva", this is workaround for compiler optimizations :D

samme commented 6 years ago

this.aTextureIndex = 3;

Why 3?

makryl commented 6 years ago

shader has 4 attributes

    'attribute vec2 aVertexPosition;',
    'attribute vec2 aTextureCoord;',
    'attribute vec4 aColor;',
    'attribute float aTextureIndex;',

aVertexPosition - index 0 aTextureCoord - index 1 aColor - index 2 aTextureIndex - index 3 atrtributes should have this indexes usually

makryl commented 6 years ago

actually we dont know what indexes compiler will set to attributes may be it would be cleaner way to check if attribute exists in flush method of WebGLSpriteBatch https://github.com/photonstorm/phaser-ce/blob/9192c3d085bd3a412cd40633fcdda5da59a2864a/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js#L584

gl.vertexAttribPointer(shader.aTextureIndex, 1, gl.FLOAT, false, stride, 20);

change to

if (shader.aTextureIndex !== -1) {
    gl.vertexAttribPointer(shader.aTextureIndex, 1, gl.FLOAT, false, stride, 20);
}

and may be it should be same for colorAttribute https://github.com/photonstorm/phaser-ce/blob/9192c3d085bd3a412cd40633fcdda5da59a2864a/src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js#L581

aTextureIndex used also in WebGLFastSpriteBatch.start https://github.com/photonstorm/phaser-ce/blob/9192c3d085bd3a412cd40633fcdda5da59a2864a/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js#L442 but i dont know is it affected by this issue