OpenCL 和 OpenGL SL 有任何“未定义的行为”吗?
有人告诉我,C 和 C++ 具有“未定义的行为”,也就是说,如果我使用“某些构造”,相同的代码在不同平台或使用不同编译器上的行为可能会有所不同。
这同样适用于 OpenCL 和/或 OpenGL SL 吗?
I was told that C and C++ have "undefined behavior", that is, the same code might behave differently on different platforms, or using different compilers, if I use "certain constructs".
Does the same apply to OpenCL and/or OpenGL SL?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
是的。
Yes.
是的,根据 OpenCL 规范 1.1,该规范定义了未定义的行为前面的事情是:
为例:
CL_MEM_WRITE_ONLY
创建的缓冲区或图像对象中读取”CL_MEM_READ_ONLY
创建的缓冲区或图像对象”使用相同的 host_ptr 创建的缓冲区对象或
重叠的宿主区域”
使用同一缓冲区对象创建的子缓冲区对象”
clEnqueueReadBuffer
与使用缓冲区的其他命令clEnqueueReadBuffer
同时映射缓冲区不过,还有很多方法可以从 OpenCL 调用未定义的行为。
对于 OpenGL SL(规范),有很多很容易找到示例:
const
那么它是一个编译时错误)如果在写入之前读取顶点着色器,则返回未定义的值”
#pragma STDGL invariant(all)
]函数,那么行为不变的输出集是未定义的”
gl_PointSize
或gl_ClipVertex
] 会导致未定义的行为”Yes, according to the OpenCL specification 1.1 which defines undefined behaviour in the front matter as:
For example:
CL_MEM_WRITE_ONLY
inside a kernel"CL_MEM_READ_ONLY
inside a kernel"buffer objects created with the same host_ptr or
overlapping host regions"
sub-buffer objects created with the same buffer object"
clEnqueueReadBuffer
with other commands using the bufferclEnqueueReadBuffer
whilst the buffer is mappedThere's plenty more ways of invoking undefined behaviour from OpenCL though.
For OpenGL SL (specification) there are quite a few easy to find examples:
const
then it's a compile time error)vertex shader returns undefined values if it is read before being written"
#pragma STDGL invariant(all)
] is used after the declaration of any variables orfunctions, then the set of outputs that behave as invariant is undefined"
gl_PointSize
orgl_ClipVertex
] before writing them results in undefined behavior"这并不是未定义行为的实际含义。这是未定义行为的结果,但这不是它的目的。
规范就是定义当你做某事时会发生什么。它说明了哪些参数值是好的,哪些是坏的。如果您通过了错误的错误,它会告诉您遇到了哪些错误以及系统的状态。如果当前状态对于您尝试执行的操作无效,则规范会解释您遇到的其他类型的错误以及这对系统随后的状态意味着什么。
当您使用定义的行为时,您依赖于您自己和实现之间的契约;该合同称为 OpenGL 规范。您依靠实现来提供规范所需的有效性检查。并且您依赖于实现按照规范执行操作。如果实施没有正确实施某些内容,那么它就违反了合同。
当规范说某些事情将导致“未定义的行为”时,这意味着做这些事情就是你违反了合同。你已经离开了地图的边缘。您正在执行规范未提供定义行为的操作;你违反了协议中你的部分。
换句话说,只要您不依赖未定义的行为,您的代码就可以完美移植。这就是它的意思。
一般来说,如果测试会给实现带来繁重的负担,那么规范会标记一些未定义的东西。毕竟,OpenGL 确实需要相当快的速度。因此,他们试图避免通过强迫驾驶员测试几乎不可能检查的事情来增加驾驶员的负担。
然后,还有一些根本无法测试的测试。在 OpenGL 中,通过将图像绑定为纹理并从中采样,同时将该图像附加到 FBO 并对其进行渲染,来读取和写入同一图像是非法的。没有办法保证测试这种情况。
哦,大部分都可以测试一下。当相同的纹理绑定到 FBO 和采样器时,绘制调用可能会失败。但是这样的话,您将无法渲染到同一纹理的不同 mipmap;请记住:每个 mipmap 都是一个单独的图像。因此,您可以检查基本/最大级别范围是否允许从绑定到 FBO 的 mipmap 进行采样。但这给用户带来了沉重的负担,因为他们在渲染到不同的 mipmap 时必须不断调整基本/最大级别。对于他们来说,使用textureLOD 或类似函数从正确的 mipmap 中进行采样要容易得多。并且直到运行时您才能确定它们是否从该 mipmap 级别之外进行采样。
就像许多规范一样,OpenCL 和 OpenGL SL 具有未定义的行为。一般来说,由于同样的原因,它是未定义的:测试它会使实现速度慢得令人无法接受,或者测试根本不可能。
That's not what undefined behavior actually means. That is the result of undefined behavior, but that's not what it's for.
Specifications are all about defining what happens when you do something. It says what parameter values are good and which are bad. If you pass bad ones, it tells you what errors you get and what the state of the system will be. If the current state is invalid for an operation you attempt to perform, the specification explains what other kinds of errors you get and what that means for the state of the system afterwards.
When you use defined behavior, you are relying on a contract between yourself and the implementation; that contract is called the OpenGL specification. You rely on the implementation to provide the validity checks that the specification requires. And you rely on the implementation doing what the specification says. If the implementation doesn't implement something correctly, then it is breaking the contract.
When the specification says that a certain set of things will result in "undefined behavior", what that means is doing those things is you are breaking the contract. You are off the edge of the map. You are doing something for which the specification does not provide defined behavior; you broke your part of the deal.
To put it another way, your code will be perfectly portable as long as you don't rely on undefined behavior. That's what it means.
Generally, the spec marks something undefined if testing for it would be an onerous burden for implementations. OpenGL does need to be reasonably fast, after all. So burdening the driver by forcing it to test for things that would be nearly impossible to check for is something they try to avoid.
Then, there are tests which are flat-out impossible to test for. In OpenGL, it is illegal to read from and write to the same image, by binding an image as a texture and sampling from it, while simultaneously attaching that image to an FBO and rendering to it. There is no way to guaranteeably test for this scenario.
Oh, you can test for most of it. You could fail on draw calls when the same texture is bound to the FBO and to a sampler. But then, you wouldn't be able to render to different mipmaps of the same texture; remember: each mipmap is a separate image. So you could check to see if the base/max level range allows for the possibility to sample from the mipmap that is bound to the FBO. But that puts a hefty burden on the user, as they would have to be constantly adjusting the base/max level when rendering to different mipmaps. It's much easier for them to just sample from the correct mipmap with
textureLOD
or similar functions. And you can't determine until runtime whether they are sampling from outside that mipmap level.OpenCL and OpenGL SL have undefined behavior, just like many specifications. And generally, it's undefined for the same reasons: testing for it would make the implementation unacceptably slower, or testing is flat-out impossible.
是的,存在未定义的行为(您可以 grep 规范来查找一些);但要小心,因为这些并不是程序在不同系统上表现不同的唯一方法:并非所有 OpenGL 实现都是完全兼容的(事实上,很可能大多数都不是)。例如,Nvidia 的驱动程序允许在此处的核心配置文件中调用
texture2D
,而这会在其他平台上导致错误(后者是预期的行为)。了解其是否有效的最佳方法是在多个平台(操作系统、GPU 和驱动程序)上进行测试。Yes, there are undefined behaviours (you can grep the spec to find some); but be careful, because those are not the only way for a program to behave differently on different systems: not all OpenGL implementations are completely compilant (in fact, it is likely that most aren't). For instance, Nvidia's drivers allow
texture2D
to be called in a core profile here, while this causes an error on other platforms (and the latter is the expected behaviour). The best way to know if it will work is to test on several platforms (OSs, GPU, and drivers).