在OpenGL中,建议在链接程序后分离和删除着色器(正确的方法是删除GLSL着色器?).
但是当我在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);
}
Run Code Online (Sandbox Code Playgroud)
可以在此处找到完整的示例:http: //jsfiddle.net/mortennobel/vdgtg3fy/1/
编辑:更多细节:我正在运行OS/X Yosemite.Safari 8.0,Chrome 39,Firefox 33.1.事实证明,如果我调用gl.getUniformLocation(xxx)并在分离和删除着色器之前存储结果,那么一切正常.我知道这可能是一件好事 - 但我仍然很好奇这是否是我必须做的事情 - 或者它是一个浏览器错误.
我不认为您可以安全地分离着色器并继续使用该程序.该规范对我来说含糊不清,所以如果其他人以不同的方式阅读,我会很感激.
根据我在WebGL规范中的内容,它引用了ES 2.0规范来确定这些函数的确切行为.
ES 2.0规范中的关键段落(第31页,UseProgram文档下的几个段落)是:
在使用有效的程序对象时,应用程序可以自由修改附加的着色器对象,编译附加的着色器对象,附加其他着色器对象以及分离着色器对象.这些操作不会影响程序对象的链接状态或可执行代码.
这确实说你可以分离着色器对象.但关键部分是句子的开头:"正在使用有效的程序对象".这表明,整个"分离着色器obects"津贴并没有如果程序不使用申请.
现在问题变成"使用中"意味着什么.特别是因为这是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.
Run Code Online (Sandbox Code Playgroud)
这个程序在这里使用,所以可以分离着色器,我们可以根据上面复制的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!
Run Code Online (Sandbox Code Playgroud)
这一次,程序在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.
Run Code Online (Sandbox Code Playgroud)
这更有趣.prog1在DetachShader被召唤时正在使用.但是之后有一段时间它没有被使用,所以问题是它是否会变得无效.我的感觉是它可以,但我认为它没有明确规定.