链接后WebGL分离和删除着色器

时间:2014-12-01 21:30:46

标签: webgl

在OpenGL中,建议在链接程序(Proper way to delete GLSL shader?)后分离和删除着色器。

但是当我在WebGL中执行此操作时,似乎Safari和Firefox都存在问题(而Chrome的行为与预期一致)。分离和删除着色器在WebGL中的工作方式是否不同,还是只是不符合标准的浏览器实现?

使用此功能时会出现问题:

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);    
}

可在此处找到完整运行的示例: http://jsfiddle.net/mortennobel/vdgtg3fy/1/

编辑:更多细节:我正在运行OS / X Yosemite。 Safari 8.0,Chrome 39,Firefox 33.1。 事实证明,如果我调用gl.getUniformLocation(xxx)并在分离和删除着色器之前存储结果,那么一切正常。我知道这可能是一件好事 - 但我仍然很好奇这是否是我必须做的事情 - 或者它是一个浏览器错误。

1 个答案:

答案 0 :(得分:6)

我认为你不能安全地分离着色器并继续使用该程序。该规范对我来说含糊不清,所以如果其他人以不同方式阅读,我会很感激反馈。

根据我在WebGL规范中的内容,它引用了这些函数的确切行为的ES 2.0规范。

ES 2.0规范中的关键段落(第31页,UseProgram文档下的几段)是:

  

在使用有效的程序对象时,应用程序可以自由修改附加的着色器对象,编译附加的着色器对象,附加其他着色器对象以及分离着色器对象。这些操作不会影响程序对象的链接状态或可执行代码。

确实可以说你可以分离着色器对象。但关键部分是句子的开头:“正在使用有效的程序对象”。这表明,如果该程序未被使用,整个“分离着色器对象”允许适用。

现在问题变成了“使用中”的含义。特别是因为这是UseProgram文档的一部分,所以我将其视为最后一次调用UseProgram的程序。对“使用中”的这种解释也与下一段中的语言一致:

  

...如果指定的程序对象由于之前调用UseProgram而已被使用。

基于此,我的理论是,如果程序已经是最新的,你只能安全地分离着色器,并保持最新状态。以下通过几个例子说明了这种解释。

示例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.

程序在这里使用,所以可以分离着色器,我们可以根据上面复制的spec部分继续使用该程序进行渲染。

示例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!

这一次,调用DetachShader时程序未被使用。因此“程序对象正在使用”条件不适用,并且应用程序“可以自由分离着色器对象”。

示例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.

这更有趣。在prog1被调用时,DetachShader正在使用中。但是之后有一段时间它没有被使用,所以问题是它是否会变得无效。我的感觉是它可以,但我认为它没有明确规定。