那么我该如何实际调试着色器?有没有一种方法可以遍历着色器?我可以看看着色器在特定顶点/基元/片段上的执行情况吗?调试状态更改之类的东西。)
#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
评论
您是否研究过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