Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebGL detach and delete shaders after linking

Tags:

webgl

In OpenGL it is recommended to detach and delete shaders after linking the program ( Proper way to delete GLSL shader? ).

But when I do this in WebGL, it seems like both Safari and Firefox has problems (while Chrome behaves as expected). Does detach and delete shaders works different in WebGL or is it just the browser implementations that are not following the standard?

The problem happens when I use this function:

function setupShader(){
    var vertexShaderSrc = document.getElementById('vertexShader').textContent;
    var fragmentShaderSrc = document.getElementById('fragmentShader').textContent;
    var vertexShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vertexShader, vertexShaderSrc);
gl.compileShader(vertexShader);
    if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
        alert(gl.getShaderInfoLog(vertexShader));
    }
    var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fragmentShader, fragmentShaderSrc);
    gl.compileShader(fragmentShader);
    if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
        alert(gl.getShaderInfoLog(fragmentShader));
    }
    shaderProgram = gl.createProgram();
    gl.attachShader(shaderProgram, vertexShader);
    gl.attachShader(shaderProgram, fragmentShader);
    gl.linkProgram(shaderProgram);

    if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
        alert("Could not initialise shaders");
    }
    gl.useProgram(shaderProgram);
    gl.detachShader(shaderProgram, vertexShader);
    gl.detachShader(shaderProgram, fragmentShader);
    gl.deleteShader(vertexShader);
    gl.deleteShader(fragmentShader);    
}

A full running example can be found here: http://jsfiddle.net/mortennobel/vdgtg3fy/1/

Edit: A few more details: I'm running OS/X Yosemite. Safari 8.0, Chrome 39, Firefox 33.1. It turns out that if I call gl.getUniformLocation(xxx) and store the result before I detach and delete the shader, then everything works fine. I know this is probably a good thing to do - but I'm still curious if this is something I must do - or it is a browser bug.

like image 481
Mortennobel Avatar asked Dec 01 '14 21:12

Mortennobel


1 Answers

I don't think you can safely detach the shaders and continue to use the program. The spec reads kind of ambiguously to me, so I would appreciate feedback if others read it differently.

From what I found in the WebGL spec, it refers to the ES 2.0 spec for the exact behavior of these functions.

The key paragraph in the ES 2.0 spec (page 31, a couple of paragraphs under the UseProgram documentation) is:

While a valid program object is in use, applications are free to modify attached shader objects, compile attached shader objects, attach additional shader objects, and detach shader objects. These operations do not affect the link status or executable code of the program object.

This does indeed say that you can detach the shader objects. But the critical part is at the start of the sentence: "while a valid program object is in use". This suggests that the whole "detach shader obects" allowance does not apply if the program is not in use.

Now the question becomes what "in use" means. Particularly since this is part of the UseProgram documentation, I read this as the program that UseProgram was last called for. This interpretation of "in use" is also consistent with the language in the next paragraph:

... if the specified program object was already in use as a result of a previous call to UseProgram.

Based on this, my theory is that you can only safely detach the shaders if the program is already current, and you keep it current. The following illustrates this interpretation with a few examples.

Example 1

// Build shaders, create program.
AttachShader(prog1, vs1);
AttachShader(prog1, fs1);
LinkProgram(prog1);

UseProgram(prog1);
DetachShader(prog1, vs1);
DetachShader(prog1, fs1);
// Program is still valid, and can continue to be used.

The program is in use here, so it was ok to detach the shaders, and we can continue rendering with the program, based on the spec section copied above.

Example 2

// Build shaders, create program.
AttachShader(prog1, vs1);
AttachShader(prog1, fs1);
LinkProgram(prog1);
DetachShader(prog1, vs1);
DetachShader(prog1, fs1);

UseProgram(prog1);
// Program is NOT valid!

This time, the program was not in use when DetachShader was called. So the "program object is in use" condition did not apply, and the application was not "free to detach shader objects".

Example 3

// Build shaders, create program.
AttachShader(prog1, vs1);
AttachShader(prog1, fs1);
LinkProgram(prog1);

UseProgram(prog1);
DetachShader(prog1, vs1);
DetachShader(prog1, fs1);
// Program is still valid, and can continue to be used.

UseProgram(prog2);
// prog1 is now not "in use" anymore.
...

UseProgram(prog1);
// Is it valid? Probably not.

This is more interesting. prog1 was in use when DetachShader was called on it. But there was a time afterwards when it was not in use, so the question is if it can become invalid then. My feeling is that it can, but I don't think it's clearly specified.

like image 131
Reto Koradi Avatar answered Sep 19 '22 08:09

Reto Koradi