25-3D与AR/VR应用Debug与优化再谈

119 阅读9分钟

说明

ARKit系列文章目录

原来写过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输出,又无法打断点调试;就算拿到了数据,又面临看不懂的问题,毕竟肉眼无法直接看出一大堆向量或颜色的浮点数哪里有问题.

有了新的调试工具,以前费尽心机搞的什么假彩色调试都可以不用了.