在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)并在分离和删除着色器之前存储结果,那么一切正常。我知道这可能是一件好事 - 但我仍然很好奇这是否是我必须做的事情 - 或者它是一个浏览器错误。
答案 0 :(得分:6)
我认为你不能安全地分离着色器并继续使用该程序。该规范对我来说含糊不清,所以如果其他人以不同方式阅读,我会很感激反馈。
根据我在WebGL规范中的内容,它引用了这些函数的确切行为的ES 2.0规范。
ES 2.0规范中的关键段落(第31页,UseProgram
文档下的几段)是:
在使用有效的程序对象时,应用程序可以自由修改附加的着色器对象,编译附加的着色器对象,附加其他着色器对象以及分离着色器对象。这些操作不会影响程序对象的链接状态或可执行代码。
确实可以说你可以分离着色器对象。但关键部分是句子的开头:“正在使用有效的程序对象”。这表明,如果该程序未被使用,整个“分离着色器对象”允许不适用。
现在问题变成了“使用中”的含义。特别是因为这是UseProgram
文档的一部分,所以我将其视为最后一次调用UseProgram
的程序。对“使用中”的这种解释也与下一段中的语言一致:
...如果指定的程序对象由于之前调用UseProgram而已被使用。
基于此,我的理论是,如果程序已经是最新的,你只能安全地分离着色器,并保持最新状态。以下通过几个例子说明了这种解释。
// 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部分继续使用该程序进行渲染。
// 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
时程序未被使用。因此“程序对象正在使用”条件不适用,并且应用程序不“可以自由分离着色器对象”。
// 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
正在使用中。但是之后有一段时间它没有被使用,所以问题是它是否会变得无效。我的感觉是它可以,但我认为它没有明确规定。