Webgl:不同格式的颜色附件在 windows 上不起作用
Webgl: color attachments with different formats do not work on windows
我正在尝试将 WEBGL_draw_buffers 与 OES_texture_float 一起使用,效果很好。但是,当使用两个不同类型的渲染目标时,这在我的 windows 机器 (amd) 上不起作用。但是,它确实适用于我的 linux 机器(开源 radeon 驱动程序)。
因此具有以下颜色附件的帧缓冲区不适用于 windows:
attachment 0 : rgb * unsigned byte
attachment 1 : rgb * float
但以下布局确实有效:
attachment 0 : rgb * float
attachment 1 : rgb * float
我写了一个小测试程序来说明这个问题:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script type="text/javascript">
var canvas = document.createElement('canvas');
var gl = canvas.getContext("webgl");
var WEBGL_draw_buffers = gl.getExtension("WEBGL_draw_buffers") || gl.getExtension("GL_EXT_draw_buffers") || gl.getExtension("EXT_draw_buffers");
gl.getExtension("OES_texture_float");
gl.getExtension("WEBGL_depth_texture");
var result = "";
result += "UNSIGNED_BYTE, FLOAT: " + test(gl.UNSIGNED_BYTE, gl.FLOAT) + "<br />";
result += "FLOAT, FLOAT: " + test(gl.FLOAT, gl.FLOAT);
var div = document.createElement('div');
div.innerHTML = result;
document.body.appendChild(div);
function setParams() {
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
}
function test(type1, type2) {
var w = 2, h = 2;
var t1 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, t1);
setParams();
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, w, h, 0, gl.RGB, type1, null);
var t2 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, t2);
setParams();
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, w, h, 0, gl.RGB, type2, null);
var framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
WEBGL_draw_buffers.drawBuffersWEBGL([WEBGL_draw_buffers.COLOR_ATTACHMENT0_WEBGL, WEBGL_draw_buffers.COLOR_ATTACHMENT1_WEBGL]);
gl.framebufferTexture2D(gl.FRAMEBUFFER, WEBGL_draw_buffers.COLOR_ATTACHMENT0_WEBGL, gl.TEXTURE_2D, t1, 0);
gl.framebufferTexture2D(gl.FRAMEBUFFER, WEBGL_draw_buffers.COLOR_ATTACHMENT1_WEBGL, gl.TEXTURE_2D, t2, 0);
var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
switch (status) {
case gl.FRAMEBUFFER_COMPLETE:
return "FRAMEBUFFER_COMPLETE";
case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
return "FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
return "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
return "FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
case gl.FRAMEBUFFER_UNSUPPORTED:
return "FRAMEBUFFER_UNSUPPORTED";
default:
return "Error: " + status;
}
}
</script>
</body>
</html>
在 windows 上输出:
UNSIGNED_BYTE, FLOAT: FRAMEBUFFER_UNSUPPORTED
FLOAT, FLOAT: FRAMEBUFFER_COMPLETE
在 linux 上输出:
UNSIGNED_BYTE, FLOAT: FRAMEBUFFER_COMPLETE
FLOAT, FLOAT: FRAMEBUFFER_COMPLETE
我想知道为什么。请注意,我的结果在 firefox 和 chrome.
中是相同的
更新:当 windows 上禁用 angle
时,它将表现得像 linux。
我在 reddit 上回复了,但我会在这里复制相同的内容:
据我所知,'correct' 驱动程序拒绝所有颜色的位平面数量不同的多个颜色缓冲区(参见 https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_buffers.txt 问题 5),并且根据 OpenGLES2 规范的第 4.0 节:
"all color buffers attached to an application-created framebuffer object must have the same number of bitplanes"
我读到,因为附加到片段输出的所有颜色都应该具有相同的位深度,如果一些有 8 位(无符号字节)而另一些有 32 位(浮点),情况就不一样了。
Linux 驱动程序可能不严格符合规范,或者实施了放宽此限制的扩展。换句话说 - 您不能依赖支持不同位深度的多种颜色输出的驱动程序。
WebGL 只需要 3 种附件组合即可工作。
The following combinations of framebuffer object attachments, when all of the attachments are framebuffer attachment complete, non-zero, and have the same width and height, must result in the framebuffer being framebuffer complete:
- COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture
- COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_ATTACHMENT = DEPTH_COMPONENT16 renderbuffer
- COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL renderbuffer
WEBGL_draw_buffers
扩展增加了一些。 From that spec.
If:
A framebuffer's color attachments are all textures allocated with format RGBA
and type UNSIGNED_BYTE
, and
The framebuffer has either:
No depth or stencil attachment
A valid DEPTH
or DEPTH_STENCIL
attachment
Then a call to checkFramebufferStatus against this framebuffer must not return FRAMEBUFFER_UNSUPPORTED
. (In other words, the implementation must support the use of RGBA
/UNSIGNED_BYTE
textures as color attachments, plus either a DEPTH
or DEPTH_STENCIL
attachment.)
Attaching n consecutive color attachments starting at COLOR_ATTACHMENT0_WEBGL
, where n is between 1 and MAX_DRAW_BUFFERS_WEBGL
, must not return FRAMEBUFFER_UNSUPPORTED
from a call to checkFramebufferStatus. In other words, if MAX_DRAW_BUFFERS_WEBGL
is 4, then the implementation is required to support the following combinations of color attachments:
COLOR_ATTACHMENT0_WEBGL = RGBA/UNSIGNED_BYTE
COLOR_ATTACHMENT0_WEBGL = RGBA/UNSIGNED_BYTE
COLOR_ATTACHMENT1_WEBGL = RGBA/UNSIGNED_BYTE
COLOR_ATTACHMENT0_WEBGL = RGBA/UNSIGNED_BYTE
COLOR_ATTACHMENT1_WEBGL = RGBA/UNSIGNED_BYTE
COLOR_ATTACHMENT2_WEBGL = RGBA/UNSIGNED_BYTE
COLOR_ATTACHMENT0_WEBGL = RGBA/UNSIGNED_BYTE
COLOR_ATTACHMENT1_WEBGL = RGBA/UNSIGNED_BYTE
COLOR_ATTACHMENT2_WEBGL = RGBA/UNSIGNED_BYTE
COLOR_ATTACHMENT3_WEBGL = RGBA/UNSIGNED_BYTE
ALL 其他组合取决于驱动程序。
正如@Kimixa 提到的规范列出了不起作用的组合,但相反,规范还说哪些组合起作用是 100% 依赖于驱动程序的。事实上,在 OpenGL ES 2.0 中,甚至上面提到的那些都不需要工作。 WebGL 在 OpenGL ES 2.0
之上添加了该要求
这也是某些 GPU 未启用 WEBGL_draw_buffers
的原因之一。 Chrome 在第一次初始化 WebGL 时测试所有必需的组合。如果驱动程序没有为每个需要的组合 return FRAMEBUFFER_COMPLETE
则 Chrome 不会启用 WEBGL_draw_buffers
扩展。
除了必需的组合之外,了解特定组合是否有效的唯一方法是设置它们,然后使用 gl.checkFramebufferStatus
进行检查。
我正在尝试将 WEBGL_draw_buffers 与 OES_texture_float 一起使用,效果很好。但是,当使用两个不同类型的渲染目标时,这在我的 windows 机器 (amd) 上不起作用。但是,它确实适用于我的 linux 机器(开源 radeon 驱动程序)。
因此具有以下颜色附件的帧缓冲区不适用于 windows:
attachment 0 : rgb * unsigned byte
attachment 1 : rgb * float
但以下布局确实有效:
attachment 0 : rgb * float
attachment 1 : rgb * float
我写了一个小测试程序来说明这个问题:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script type="text/javascript">
var canvas = document.createElement('canvas');
var gl = canvas.getContext("webgl");
var WEBGL_draw_buffers = gl.getExtension("WEBGL_draw_buffers") || gl.getExtension("GL_EXT_draw_buffers") || gl.getExtension("EXT_draw_buffers");
gl.getExtension("OES_texture_float");
gl.getExtension("WEBGL_depth_texture");
var result = "";
result += "UNSIGNED_BYTE, FLOAT: " + test(gl.UNSIGNED_BYTE, gl.FLOAT) + "<br />";
result += "FLOAT, FLOAT: " + test(gl.FLOAT, gl.FLOAT);
var div = document.createElement('div');
div.innerHTML = result;
document.body.appendChild(div);
function setParams() {
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
}
function test(type1, type2) {
var w = 2, h = 2;
var t1 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, t1);
setParams();
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, w, h, 0, gl.RGB, type1, null);
var t2 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, t2);
setParams();
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, w, h, 0, gl.RGB, type2, null);
var framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
WEBGL_draw_buffers.drawBuffersWEBGL([WEBGL_draw_buffers.COLOR_ATTACHMENT0_WEBGL, WEBGL_draw_buffers.COLOR_ATTACHMENT1_WEBGL]);
gl.framebufferTexture2D(gl.FRAMEBUFFER, WEBGL_draw_buffers.COLOR_ATTACHMENT0_WEBGL, gl.TEXTURE_2D, t1, 0);
gl.framebufferTexture2D(gl.FRAMEBUFFER, WEBGL_draw_buffers.COLOR_ATTACHMENT1_WEBGL, gl.TEXTURE_2D, t2, 0);
var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
switch (status) {
case gl.FRAMEBUFFER_COMPLETE:
return "FRAMEBUFFER_COMPLETE";
case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
return "FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
return "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
return "FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
case gl.FRAMEBUFFER_UNSUPPORTED:
return "FRAMEBUFFER_UNSUPPORTED";
default:
return "Error: " + status;
}
}
</script>
</body>
</html>
在 windows 上输出:
UNSIGNED_BYTE, FLOAT: FRAMEBUFFER_UNSUPPORTED
FLOAT, FLOAT: FRAMEBUFFER_COMPLETE
在 linux 上输出:
UNSIGNED_BYTE, FLOAT: FRAMEBUFFER_COMPLETE
FLOAT, FLOAT: FRAMEBUFFER_COMPLETE
我想知道为什么。请注意,我的结果在 firefox 和 chrome.
中是相同的更新:当 windows 上禁用 angle
时,它将表现得像 linux。
我在 reddit 上回复了,但我会在这里复制相同的内容:
据我所知,'correct' 驱动程序拒绝所有颜色的位平面数量不同的多个颜色缓冲区(参见 https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_buffers.txt 问题 5),并且根据 OpenGLES2 规范的第 4.0 节: "all color buffers attached to an application-created framebuffer object must have the same number of bitplanes"
我读到,因为附加到片段输出的所有颜色都应该具有相同的位深度,如果一些有 8 位(无符号字节)而另一些有 32 位(浮点),情况就不一样了。
Linux 驱动程序可能不严格符合规范,或者实施了放宽此限制的扩展。换句话说 - 您不能依赖支持不同位深度的多种颜色输出的驱动程序。
WebGL 只需要 3 种附件组合即可工作。
The following combinations of framebuffer object attachments, when all of the attachments are framebuffer attachment complete, non-zero, and have the same width and height, must result in the framebuffer being framebuffer complete:
- COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture
- COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_ATTACHMENT = DEPTH_COMPONENT16 renderbuffer
- COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL renderbuffer
WEBGL_draw_buffers
扩展增加了一些。 From that spec.
If: A framebuffer's color attachments are all textures allocated with format
RGBA
and typeUNSIGNED_BYTE
, and The framebuffer has either:
No depth or stencil attachment
A valid
DEPTH
orDEPTH_STENCIL
attachmentThen a call to checkFramebufferStatus against this framebuffer must not return
FRAMEBUFFER_UNSUPPORTED
. (In other words, the implementation must support the use ofRGBA
/UNSIGNED_BYTE
textures as color attachments, plus either aDEPTH
orDEPTH_STENCIL
attachment.)Attaching n consecutive color attachments starting at
COLOR_ATTACHMENT0_WEBGL
, where n is between 1 andMAX_DRAW_BUFFERS_WEBGL
, must not returnFRAMEBUFFER_UNSUPPORTED
from a call to checkFramebufferStatus. In other words, ifMAX_DRAW_BUFFERS_WEBGL
is 4, then the implementation is required to support the following combinations of color attachments:
COLOR_ATTACHMENT0_WEBGL = RGBA/UNSIGNED_BYTE
COLOR_ATTACHMENT0_WEBGL = RGBA/UNSIGNED_BYTE COLOR_ATTACHMENT1_WEBGL = RGBA/UNSIGNED_BYTE
COLOR_ATTACHMENT0_WEBGL = RGBA/UNSIGNED_BYTE COLOR_ATTACHMENT1_WEBGL = RGBA/UNSIGNED_BYTE COLOR_ATTACHMENT2_WEBGL = RGBA/UNSIGNED_BYTE
COLOR_ATTACHMENT0_WEBGL = RGBA/UNSIGNED_BYTE COLOR_ATTACHMENT1_WEBGL = RGBA/UNSIGNED_BYTE COLOR_ATTACHMENT2_WEBGL = RGBA/UNSIGNED_BYTE COLOR_ATTACHMENT3_WEBGL = RGBA/UNSIGNED_BYTE
ALL 其他组合取决于驱动程序。
正如@Kimixa 提到的规范列出了不起作用的组合,但相反,规范还说哪些组合起作用是 100% 依赖于驱动程序的。事实上,在 OpenGL ES 2.0 中,甚至上面提到的那些都不需要工作。 WebGL 在 OpenGL ES 2.0
之上添加了该要求这也是某些 GPU 未启用 WEBGL_draw_buffers
的原因之一。 Chrome 在第一次初始化 WebGL 时测试所有必需的组合。如果驱动程序没有为每个需要的组合 return FRAMEBUFFER_COMPLETE
则 Chrome 不会启用 WEBGL_draw_buffers
扩展。
除了必需的组合之外,了解特定组合是否有效的唯一方法是设置它们,然后使用 gl.checkFramebufferStatus
进行检查。