说明
原来写过3D与AR/VR应用Debug与优化浅谈,现在苹果在 WWDC 中又一次谈到了 3D/AR 中的 Debug 功能: WWDC2018的 Session 608 - Metal Shader Debugging and Profiling 中文解说原文已发表在WWDC 2018 内参,此处为精简版。 主要内容:
- Geometry viewer(几何体查看器):用来3D可视化方式调试几何体
- Shader debugger(着色器调试器):3D+2D可视化方式调试着色器
- Enhanced shader profiler(增强型着色器分析器):配合A11耗时统计,精准到具体代码
Metal及调试工具简介
Metal包含了以下所有相关内容:
而我们今天所关注的,其实都是属于上图中开发工具中最后一个工具Metal Frame Debugger里面的新功能.下图左侧为原有功能,右侧为新增加的四个功能,本session中,我们只关注右侧中的后三个:
Geometry viewer(几何体查看器)简介
Geometry viewer可以
- 以3D可视化的方式查看顶点变换后的数据.
- 访问所有的顶点数据.
- 查看每个draw call的视图.
比如查看错误的三角形.点击后可查看该三角形三个顶点的索引,位置坐标,纹理坐标,法线,切线等数据.
比如查看摄像机视锥体外的物体.可旋转查看3D空间的布局.
比如可提示缺失的三角形,当顶点数据有错误时,为无穷大或NaN时,右下角会有提示.
经过分析后,如果输入数据有问题,那么就去查看3D模型是否正确;如果输入没有问题,输出有错误,那么就需要进行下一步着色器调试了.
Shader debugger(着色器调试器)简介
长期以来,Shader的调试都很困难.主要原因就是:
- 大量复杂的数学代码.
- 高度并行.每帧调用上千万次
在Unity的"Book of the Dead"中,场景中的一帧,就有上千万的顶点被调用,生成六千万的三角形.
Shader debugger就长这个样子
它的优点非常明显:
- 变量数据高度可视化
- 数据是来自GPU的真实数据.
- 灵活的单步调试,无需使用断点.
- 与Metal Frame Debugger集成.
Shader演练Demo 1
bug展示
首先,是一个mac版的波浪模拟程序,可以看到波浪的显示有问题,出现了明显的断崖,所以点击捕捉,进入Metal Frame Debugger:
开始调试
进入Metal Frame Debugger之后,我们首先要做的是,查看输入几何体有没有问题,点击Geometry进入Geometry viewer:
选中有问题的三角形,查看三个顶点的数据,发现输入值的Y坐标没有问题,那么很可能是Shader的问题,点击右下角Debug按钮,进入Shader debugger:
进入之后,我们先来简单认识一下这个界面及其作用:
发现问题
接着调试我们的程序,找到displacement
向量,就是该偏移向量让水平出现高低不平的波动的.点击展开它的值,发现其中的问题:
追踪并分析问题
从左侧导航栏,进入该函数,查看计算过程,其中出现了NaN
:
根据右侧提示的
newY
的值小于0,导致pow()
函数计算出错,pow(x,y)
功能:计算x的y次幂。 说明:x应大于零,返回幂指数的结果:
修复问题
修复方法:将幂计算提前:
// 原代码
// Final tweaks to the wave 对波浪进行最后的调整
float newY = displ.y;
// Displace the water down a bit 将水体向下偏移一点
newY -= 0.1;
// Exaggerate the waves 放大波浪
newY = pow(newY, 0.95);
// 更新后代码
// Final tweaks to the wave 对波浪进行最后的调整
float newY = displ.y;
// Exaggerate the waves 放大波浪
newY = pow(newY, 0.95);
// Displace the water down a bit 将水体向下偏移一点
newY -= 0.1;
修复后效果
点击右下角刷新按钮,查看无异常后,再点击左下角的继续按钮,程序运行正常了:
Shader debugger(着色器调试器)调试详解
启动Shader debugger(着色器调试器)
Shader debugger是与Metal Frame Debugger集成的,在捕捉过视频帧之后,点击下面的调试按钮就会根据Shader的类型弹出窗口提示:
不同类型的Shader会有不同提示,比如Fragment Shader(片元着色器),会先进入PixelBuffer Inspector(像素缓冲检查器):
而Vertex Shader(顶点着色器),会先进入Geometry viewer(几何体查看器):
而Compute Shader(计算着色器),会先进入选择面板:
三种Shader的弹窗右下角,都有一个Debug按钮,点击就可以进入**Shader debugger(着色器调试器)**中.
检查变量
在代码的右侧:
- 侧边栏可显示修改后的变量
- 点击右侧按钮可展开详情视图
- 鼠标悬停可直接访问数据
- 最下方检查区可显示所有变量
查看执行的顺序
- 可以灵活的查看每一步的执行情况.甚至当发现出现问题时,可以再返回上一步进行查找问题.
- 可使用过滤搜索
访问其他线程(thread)
注:GPU中的线程与CPU中稍有不同,可简单理解为不同的三角形就是不同线程,不同的像素点也是不同的线程.
根据初始时选择的不同内容,可以查看相关线程的集合:
- Vertex -- 选中顶点所在的几何体.
- Fragment -- 选中像素周围的矩形区域
- Compute -- 选中线程所在的线程组. 这样做的好处就是,当你的代码在GPU的百万个线程上执行时,你只查看一个像素或一个顶点的数据是无意义的,必须要有其他数据参考.
查看变量及其相关的上下文数据
- 与周围数据比较,确定好坏
- 鼠标悬停直接访问
- 快速比较不同线程的数据
- 切换选中线程时变量和执行历史也会更新
理解分支(如if分支)
如下图,Mask
视图能帮助你理解同一行代码,在当前线程与其他线程中执行的效果差异,来帮助你理解并控制流程:
Shader演练Demo 2
bug展示
还是前面的波浪效果程序,我们给它添加一些高光效果,但是发现,在边缘处效果出现了问题:
开始调试
我们先长按,出现了像素检查器(就是那个放大镜一样的圆圈),选择好要调试的像素点,然后点击Debug按钮,进入着色器调试中:
发现问题
根据shader中的注释,高光是由三步生成的,查看第一步,没有问题;第二步出现问题了:
追踪并分析问题
从左侧导航栏进入该函数,查看其中的循环,发现问题在weight
计算上:
修复问题
分析后,开始修复,将i
改为center
,刷新,运行:
修复后效果
效果出来了,已修复完成了:
Enhanced shader profiler(增强型着色器分析器)简介
目前,已经有多个优化工具,集成在Metal Frame Debugger中,可以帮助我们优化shaer的性能问题.本session中,我们将带大家领略增强版的Shader profiler的强大功能.
Shader profiler优势
- 可以提供每个管线的时间信息
- 可以显示每行代码执行所需时间(适用于iOS和tvOS)
- 直接编辑并刷新Shader
- 可直接进入shader debugger
Shader profiler对A11芯片的特别增强功能
在A11芯片上,由于得到了内置硬件的支持,可显示的信息更多:
- 可显示每行代码不同类别任务的时间消耗
- ALU -- Float,half,及其他复杂数据处理.
- Memory -- Sample,load和store操作.
- Synchronization -- 等待内存,栅栏,或原子操作.
- 内联函数消耗时间的可视化.
Shader演练Demo 3
还是海面波浪的demo,这次是运行在iOS设备上,我们来分析着色器代码的瓶颈到底在哪里.
开始调试
首先在左侧导航样中,切换显示模式为View Frame By Performance,然后找到花费时间最长的渲染管线,逐级展开,直到找到具体的函数方法.
发现问题
我们发现时间主要都消耗在NoiseFilter
这个方法上了,点击该方法右侧统计图,查看原因分析,可以看到Synchronization时间过长了:
追踪并分析问题
接下来可以根据代码右侧的时间占比,来分析到底是哪一行代码导致的.需要注意的是,编译器会对代码进行优化,所以可能有些代码没有时间显示:
修复问题
导致等待时间过长的这行代码,主要作用是加载一张噪声纹理图片,并读取获得里面的噪声值.而加载纹理并对其采样会花费大量时间,那么我们可以进行优化,改为采用函数自动生成噪声值,然后点击刷新按钮:
修复后效果
刷新完成后,可以看到左侧导航栏中,原有渲染管线的时间占比下降明显,再查看NoiseFilter
这个方法,Synchronization时间明显缩短,主要时间都用来做ALU运算了,这才是正常的工作情况:
Shader编译选项
Xcode默认是离线预编译Shader代码的,app中不包含源代码,但如果你想拿到源代码,可以在Xcode 10中调整选项
总结
本期的调试和优化工具,可谓是诚意满满.苹果竟然真的把shader调试器3D可视化了!!!神一般的操作!简直就是鹅妹子嘤~
相信有很多人,尤其是初学者,在学shader时,遇到问题无从下手,既不能添加print输出,又无法打断点调试;就算拿到了数据,又面临看不懂的问题,毕竟肉眼无法直接看出一大堆向量或颜色的浮点数哪里有问题.
有了新的调试工具,以前费尽心机搞的什么假彩色调试都可以不用了.