在编写非平凡的着色器时(就像在编写其他任何非平凡的代码时一样),人们会犯错。还是Visual Studio调试器。您甚至无法进行printf调试,因为没有任何形式的控制台输出。我通常要做的是将要查看的数据呈现为彩色,但这是一个非常初级的业余解决方案。我确定人们已经提出了更好的解决方案。

那么我该如何实际调试着色器?有没有一种方法可以遍历着色器?我可以看看着色器在特定顶点/基元/片段上的执行情况吗?调试状态更改之类的东西。)

评论

您是否研究过gDEBugger?引用网站的内容:“ gDEBugger是高级OpenGL和OpenCL调试器,探查器和内存分析器。gDEBugger可以做其他工具无法做的事情-使您可以在OpenGL和OpenCL API之上跟踪应用程序活动,并查看系统实现中发生了什么。 ”当然,没有VS风格的调试/单步执行代码,但是它可能使您对着色器的工作(或应做的工作)有所了解。 Crytec为Direct着色器“调试”发布了一个类似的工具,称为RenderDoc(免费,但严格用于HLSL着色器,因此可能与您无关)。

@Bert嗯,我想gDEBugger与WebGL-Inspector等效吗?我用了后者。它非常有用,但是比执行着色器肯定要调试更多OpenGL调用和状态更改。

我从未做过任何WebGL编程,因此对WebGL- Inspector不熟悉。使用gDEBugger,您至少可以检查着色器管道的整个状态,包括纹理内存,顶点数据等。但是,实际上并没有真正遍历代码afaik。

gDEBugger的版本非常老,一段时间以来不受支持。如果您从框架和GPU状态分析中查看,则这是另一个与之密切相关的问题:computergraphics.stackexchange.com/questions/23/…

这是我建议的一个相关问题的调试方法:stackoverflow.com/a/29816231/758666

#1 楼

据我所知,没有工具可让您逐步完成着色器中的代码(此外,在这种情况下,您将只能选择要“调试”的像素/顶点,执行可能会视情况而定)。

我个人所做的是一个非常笨拙的“色彩缤纷的调试”。因此,我在#if DEBUG / #endif防护上撒了一堆动态分支,这些防护基本上说了

#if DEBUG
if( condition ) 
    outDebugColour = aColorSignal;
#endif

.. rest of code .. 

// Last line of the pixel shader
#if DEBUG
OutColor = outDebugColour;
#endif


,所以您可以通过这种方式“观察”调试信息。我通常会做各种技巧,例如在各种“颜色代码”之间进行标记或混合,以测试各种更复杂的事件或非二进制的东西。

在这个“框架”中,我还发现为常见情况设置一套固定的约定很有用,这样,如果我不必经常回去检查与什么颜色相关联的颜色。
重要的是对着色器代码的热重装提供良好的支持,因此您几乎可以交互方式更改跟踪的数据/事件,并轻松地打开/关闭调试可视化。

如果需要调试一些您无法轻松显示在屏幕上的内容,则可以始终执行相同操作,并使用一个帧分析器工具检查结果。我列出了其中几个作为其他问题的答案。

Obv,不用说,如果我不“调试”像素着色器或计算着色器,则可以传递此“ debugColor”同样,整个管道中的信息都不会插值(在带有 flat 关键字的GLSL中)

再次,这非常hacky,远未进行适当的调试,但是我一直不知道任何适当的选择。 >

评论


$ \ begingroup $
当它们可用时,您可以使用SSBO来获得更灵活的输出格式,而无需使用颜色进行编码。但是,这种方法的最大缺点是,它更改了可以隐藏/更改错误的代码,尤其是在涉及UB时。 +1不过,因为它是可用的最直接的方法。
$ \ endgroup $
–没人远离SE
16 Jan 22 '15:10



#2 楼

还有GLSL-Debugger。它曾经是一个调试器,被称为“ GLSL Devil”。

调试器本身不仅对GLSL代码而且对OpenGL本身都很方便。您可以在绘制调用之间切换并中断着色器开关。它还显示了由OpenGL传达给应用程序本身的错误消息。

评论


$ \ begingroup $
请注意,自2018年8月7日起,它不支持高于GLSL 1.2的任何内容,并且未积极维护。
$ \ endgroup $
–俄罗斯
18年8月7日在7:00



$ \ begingroup $
这句话理所当然使我难过:(
$ \ endgroup $
–rdelfin
18-09-30在22:07

$ \ begingroup $
该项目是开源的,并且非常愿意帮助实现现代化。没有其他工具可以完成它的工作。
$ \ endgroup $
–北极氙气
19年2月27日在13:50

#3 楼

GPU供应商提供了多种产品,例如AMD的CodeXL或NVIDIA的nSight / Linux GFX调试器,它们可以逐步通过着色器,但与各自的供应商的硬件绑定。 ,在该处使用它们一直很少取得成功。我无法评论Windows下的情况。

我最近使用的选项是通过#includes将我的着色器代码模块化,并将包含的代码限制为GLSL和C的通用子集++&glm。

当我遇到问题时,我尝试在另一台设备上重现该问题,以查看问题是否相同,暗示逻辑错误(而不是驱动程序问题/未定义的行为)。还有机会将错误的数据传递到GPU(例如,通过错误地绑定缓冲区等),通常我会通过cifz答案中的输出调试或通过apitrace检查数据来排除错误。

当出现逻辑错误时,我尝试通过使用相同的数据调用CPU上包含的代码来从CPU上的GPU重建情况。
然后我可以在CPU上逐步解决它。基于代码的模块化,您还可以尝试为其编写单元测试,并比较GPU运行与CPU运行之间的结果。但是,您必须意识到,在某些极端情况下,C ++的行为可能与GLSL不同,因此在这些比较中会给您带来误报。 ,您只能开始挖掘差异的来源。单元测试可能会帮助您缩小发生位置的范围,但最终您可能需要从着色器中写出其他调试信息,如cifz答案中所示。我的调试过程:


为了解决这个问题,这里列出了一些随机的利弊: br />使用常规调试器进行调试
其他(通常更好)的编译器诊断

con


一些数学原语的细微差别(例如,极端情况下的不同返回值)
其他代码在CPU上重现调用环境


评论


$ \ begingroup $
这是一个好主意,也许是最接近单步着色器代码的地方。我想知道通过软件渲染器(Mesa?)运行是否会有类似的好处?
$ \ endgroup $
–user3412
16年6月29日在6:03

$ \ begingroup $
@racarate:我也考虑过,但还没有时间尝试。我不是台面专家,但我认为调试着色器可能很困难,因为着色器调试信息必须以某种方式到达调试器。再说一次,也许台面的人们已经有了一个接口来调试台面本身:)
$ \ endgroup $
–没人远离SE
16年6月29日在10:21

#4 楼

虽然似乎不可能真正地逐步通过OpenGL着色器,但有可能获得编译结果。
以下内容摘自Android Cardboard示例。 br />
如果您的代码可以正确编译,那么您别无选择,只能尝试以另一种方式向您传达程序状态。您可以通过更改顶点颜色或使用其他纹理来表示已到达部分代码。这很尴尬,但似乎是目前唯一的方法。它。

评论


$ \ begingroup $
嗯,我知道我会遇到编译器错误。我希望可以进行更好的运行时调试。我过去也曾使用过WebGL检查器,但我相信它仅显示状态更改,但无法查看着色器调用。我想这个问题可能更清楚了。
$ \ endgroup $
–马丁·恩德(Martin Ender)
15年8月7日在9:42

#5 楼

对我有用的解决方案是将着色器代码编译为C ++-没人提到。即使需要一些设置,它在处理复杂代码时也非常有效。

我主要与HLSL Compute Shaders合作,为此我开发了概念验证库。 :

https://github.com/cezbloch/shaderator

它在DirectX SDK示例的Compute Shader上进行了演示,展示了如何启用HLSL调试等C ++以及如何设置单元测试。

将GLSL计算着色器编译为C ++看起来比HLSL容易。主要是由于HLSL中的语法构造。我在GLSL光线跟踪器Compute Shader上添加了一个简单的可执行单元测试示例,您也可以在Shaderator项目的源代码中的上方链接下找到它。

#6 楼

这是我在StackOverflow上对相同问题的答案的复制粘贴。


此答案的底部是GLSL代码示例,该代码允许将完整的float值输出为颜色,编码为IEEE 754 binary32。我按如下方式使用它(此代码段给出了模型视图矩阵的yy组件): >

将其显示在屏幕上之后,您可以使用任何颜色选择器,将颜色设置为HTML格式(如果不需要更高的精度,则将vec4 xAsColor=toColor(gl_ModelViewMatrix[1][1]); if(bool(1)) // put 0 here to get lowest byte instead of three highest gl_FrontColor=vec4(xAsColor.rgb,1); else gl_FrontColor=vec4(xAsColor.a,0,0,1); 附加到00值,然后进行第二遍处理以获取低字节),然后以IEEE 754 rgb的形式获取float的十六进制表示形式。 =“ lang-c prettyprint-override”> binary32