从八开始——图形渲染/Metal专题

Metal与图形渲染四:工具与调试

2021-01-28  本文已影响0人  肠粉白粥_Hoben

零. 前言

俗话说,工欲善其事必先利其器,在苹果开发中,XCode给我们提供了众多的debug工具,既然开发工程代码有方便的断点调试机制,那么想必Metal开发也有非常好用的调试手段,今天就来介绍一下如何利用XCode自带的工具调试Metal开发。

这次我们选取的是Metal Sample Code里面的代码,是一个非常非常酷炫的3D带阴影带荧光带光照的特效:

一. 捕获某一帧

首先将代码跑到手机,点击这个小相机按钮,即可捕获到这一帧的信息

下图是这一帧动画的捕获结果,可以看到里面有很多部分,比如G缓冲、光照、阴影等等渲染效果。

我们可以通过setLabel:方法对某些需要重视的缓冲、编码器等进行设置标签,并在Debug导航栏展示。

commandBuffer.label = @"GBuffer & Lighting Commands";

可以对编码器通过pushDebugGroup:popDebugGroup进行文件夹分级:

/// Draw to the three textures which compose the GBuffer
- (void)drawGBuffer:(nonnull id <MTLRenderCommandEncoder>)renderEncoder
{
    [renderEncoder pushDebugGroup:@"Draw G-Buffer"];
    [renderEncoder setCullMode:MTLCullModeBack];
    [renderEncoder setRenderPipelineState:_GBufferPipelineState];
    [renderEncoder setDepthStencilState:_GBufferDepthStencilState];
    [renderEncoder setStencilReferenceValue:128];
    [renderEncoder setVertexBuffer:_frameDataBuffers[_frameDataBufferIndex] offset:0 atIndex:AAPLBufferIndexFrameData];
    [renderEncoder setFragmentBuffer:_frameDataBuffers[_frameDataBufferIndex] offset:0 atIndex:AAPLBufferIndexFrameData];
    [renderEncoder setFragmentTexture:_shadowMap atIndex:AAPLTextureIndexShadow];

    [self drawMeshes:renderEncoder];
    [renderEncoder popDebugGroup];
}

二. 顶点着色器的Debug

我们点击小虫子按钮就可以出现debug界面啦

选中Vertex可以查看顶点情况,可以看到这个图像由若干个三角形组成,现在我们选中其中一个三角形,点击Debug按钮

这时候就会定位到.metal文件的顶点着色器代码,我们可以看到这个三角形对应的坐标情况,每一步都能看到对应的矩阵信息输出,非常非常方便。

如果渲染时发现图像消失掉了,不妨可以用顶点着色器的Debug,看看对应的三角形到底跑哪去了。

三. 片段着色器的Debug

现在我们用像素查看器定位到闪现荧光的地方,看看荧光对应的片段着色器,我们选中Fragment选项,点击Debug按钮

这时候就可以看到对应的片段着色器的代码了,这个着色器起名为Fairy,营造了一种小精灵的气氛哈哈。我们点击右侧的矩阵还可以看到对应的图片效果,把鼠标放上去还可以看到实时的RGBA,真的非常人性化了。

当然,如果你这时候定位到bug了,对Metal文件一番修改后,想实时查看效果,那么可以点击,我改了一下代码,就实时地把小精灵的气氛毁坏掉了=v=

四. 性能表现的Debug

1. Summary

点击Summary栏,可以看到这个程序有6个命令缓冲区、6个渲染命令编码器、33个描绘指令,渲染一帧大概需要7.03ms,接近60w个顶点,纹理内存102.8MB,缓冲内存3.1MB

而下半部分则是Metal对性能上的一些优化建议,如当我点开BandWidth栏的时候,系统告知这是未被使用的资源。

点击后,系统建议编码完成后如果不需要用这一帧,换成MTLStoreActionDontCare,这样可以省掉8.03MB的大小。

2. Counters

计数器选项可以看到每个分组的一些渲染情况,还可以看到哪些阶段比较耗性能,从而进行排查。

3. Memory

内存选项可以看到内存的情况,纹理和缓冲用了多少内存在这里都一目了然。

4. Pineline State

点击这个按钮,切换到Pineline State

选中一个看上去耗时最长的fragment看看情况

可以看到,该G缓冲着色器总耗时1.39ms,且每一步的一些性能占比情况都展示了出来。

点击饼状图还能看到详情:

根据苹果文档Optimizing Performance with the Shader Profiler,这些性能指标分别代表:

ALU:Arithmetic Logic Unit,逻辑计算单元,负责逻辑运算

Memory:内存,采样、读取和存储操作

Synchronization:同步,等待内存、被阻塞、原子操作

根据苹果文档Reducing Shader Bottlenecks,我们可以通过以下操作提高性能:

  1. 如果对精度不那么敏感,可以适当降低精度

  2. 使用Metal的快速运算标记flag,只有真正需要用到的时候才使用精确运算flag,这个在Metal Shading Language Guide的1.5章有提到

  3. 能用half就用half,不行才用float,避免half和float的相互转换

  4. 能采样纹理就不要手动写函数计算,比如相对于写一个噪声点的生成函数,更好的选择是生成一个噪声纹理进行采样。

5. Instrument分析

业界对Instrument的Metal System Trace的分析比较少,找了几个WWDC视频才大致了解。

打开Instrument,Option勾选如下

A13是苹果的Metal Device,而下面的则是各个CPU的占用情况,如果有过高占用的话会很容易看到,从而进行排查。

展开A13又看到几个熟悉的老面孔,顶点和片段着色器,还有一些性能指标

筛选一些数值放大到一次渲染过程看看,可以看到顶点和片段着色器的一些函数执行的流水线,如果需要的话可以定点到具体方法排查。下方还有一些时间信息。

五. 总结

这篇文章主要介绍了如何利用XCode对Metal渲染进行调试,还有介绍了一些性能情况的查看,我们可以通过不同阶段的性能表现来定位哪些函数比较消耗性能,从而优化他们~

参考文章

WWDC2018 Metal Shader Debugging and Profiling

Metal框架详细解析(十八) —— 工具、分析和调试之Metal GPU Capture(二)

Reducing Shader Bottlenecks

WWDC2020 Gain insights into your Metal app with Xcode 12

WWDC2020 Optimize Metal apps and games with GPU counters

上一篇下一篇

猜你喜欢

热点阅读