SRP Batch合批失败

1)SRP Batch合批失败
​2)Unity增量打包AssetBundle没变化的资源也会被重新打包
3)如何查找il2cpp.so代码段映射的内存突然变大的问题
4)iOS画面不明原因freeze


这是第283篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间10分钟,认真读完必有收获。

UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)

SRP

Q:最近尝试用SRP Batch,但感觉非常难以捉摸。这里所有的物体都是用的同一个Shader,而且关键字也都一样,也就是同一个变体。按说应该可以合并Batch的,但第二个提示Shader的关键字不同,SRP合并失败。

 

 

 

在网上查了一些资料,没有有用的信息。自己试了一下,只要改其中的一些RenderQueue,SRP Batch的结果就有变化(不能合并的数量变少了)。

 

 

 

但是,RenderQueue不能随便改吧?会影响性能。而且对于半透的来讲,渲染结果都会错。更何况改起来非常麻烦。各路大神们,想了解一下大家是怎么解决这个问题的?另外,大家的项目有没有用SRP Batch?还是用的传统的Static Batch?

有人提醒,把光图去掉试试,虽然的确有用,但总不能去掉光图吧?

 

又试了一下,专门把这些结点单独烘一下,也有用。看来跟光图也没直接关系。

 

A1:这个应该是mat序列化文件里残留的关键字导致,Unity的Bug。

比如说:美术先用创建一个材质a,用的lit shader,调整自发光设置,导致材质里多了一个关键字_EMISSION,然后美术把这个材质改成了自定义Shader。这时候就算你的自定义Shader里没有_EMISSION这个关键字,材质的序列化文件里还是会记录下来。

然后再创建一个材质b,和材质a属性完全一样,只是没有残留的关键字_EMISSION,你会惊讶的发现材质a与材质b不能SRP Batcher,原因写:Node use different keywords。并且这时候你用Frame Debuggger去看这两个材质的DrawCall,你是看不到_EMISSION这个关键字的,因为实际上确实没用到。

感谢deviljz@UWA问答社区提供了回答

A2:感谢回复,确实是mat文件里存储的关键字导致的问题,如图:

 

 

 

 

 

修改关键字后,两个SRP Batch变成一个了:

 

 

 

另外,补充一下,之前说的改RenderQueue就能解决部分问题,中间确实是这样。但后来经过测试,我把整个的光图重新烘了一下,问题就解决了。中间做了什么已经不清晰,原因未知。不过,半透的东西我还需要再确认一下是不是改keywords就没问题了。

现在大致摸到门路了,如果Batch和Batch之间上下紧挨着,变体又是一个,就是关键字的bug问题。如果并不是紧挨着,变体虽然是同一个,也不能合并Batch。这时,需要先调整RenderQueue,让它们渲染次序紧挨着,Batch才可能会合并,和NGUI调整图层可以优化性能意思差不多。

 

其实只要把材质使用的Shader里没有的关键字删除就可以了:

    public static void RemoveRedundantMaterialShaderKeywords(Material material)
    {
        List<string> materialKeywordsLst = new List<string>(material.shaderKeywords);
        List<string> shaderKeywordsLst = new List<string>();
        var getKeywordsMethod =
            typeof(ShaderUtil).GetMethod("GetShaderGlobalKeywords", BindingFlags.Static | BindingFlags.NonPublic);
        string[] keywords = (string[]) getKeywordsMethod.Invoke(null, new object[] {material.shader});
        shaderKeywordsLst.AddRange(keywords);

        getKeywordsMethod =
            typeof(ShaderUtil).GetMethod("GetShaderLocalKeywords", BindingFlags.Static | BindingFlags.NonPublic);
        keywords = (string[]) getKeywordsMethod.Invoke(null, new object[] {material.shader});
        shaderKeywordsLst.AddRange(keywords);

        List<string> notExistKeywords = new List<string>();
        foreach (var each in materialKeywordsLst)
        {
            if (!shaderKeywordsLst.Contains(each))
            {
                notExistKeywords.Add(each);
            }
        }

        foreach (var each in notExistKeywords)
        {
            materialKeywordsLst.Remove(each);
        }

        material.shaderKeywords = materialKeywordsLst.ToArray();
    }

  

用工具改完之后,在编辑器上看,效果还是可以的。一个相机看整个场景,CPU渲染性能提升接近20%。

 

感谢题主仇磊@UWA问答社区提供了回答


AssetBundle

Q:项目中使用Git进行版本管理,在每次生成AssetBundle时都是使用 BuildAssetBundleOptions.Determinestic对所有的资源生成AssetBundle,并且生成的缓存目录都是统一的。但是发现在切换Branch后,本身没变化的资源生成的AssetBundle发生了变化。

通过Editor/Data/Tools中的webextract和binary2text工具对比发现其中的preloadIndex发生了变化,但实际上资源没有变。

 

请问大家的项目中对于AssetBundle增量打包有好的方案吗?还是需要手动管理每一个变化的资源再进行AssetBundle的生成?

A:通过版本管理维护好每一次增量打包的AssetBundle和Library应该能解决不同分支/不同机器增量打包的问题。

比如:

第一次打完上线包:上传Assetbundle + manifest + Library;

第二次打包前,重置并拉取最新的Assetbundle + manifest + Library,资源发生变化的AssetBundle包才会被重新打包;上线后再上传Assetbundle + manifest + Library;

感谢Richard Yu@UWA问答社区提供了回答


IL2CPP

Q:各位大佬问一个问题,就是最近的两个版本发现我们的il2cpp.so这个库mmap内存变大了,这块有什么好的办法查吗?
1. 不是Mono内存变大
2. 静态文件il2cpp.so本身没变大
3. 也不是数据段变大

不知道是谁用到了特殊的代码。请问有什么好的排查方法吗?试过二分法,如下图:79456k这个值是异常的,正常下只有35808k。

 

iOS下并无明显异常,只是安卓有问题。

用的很多方法都没查到,后面在测试时,让测试同学切后台,再开很多新的应用(这时mmap的内存应当会降下去),再把应用杀掉,如果这个mmap的内存降了不再涨,让测试同学就把问题的优先级降了。

原本的思路是想:
1. 通过物理内存—>找到对应的虚拟内存地址,再算出偏移---->对应.so的地址,再找到目标代码---->再找到源代码的,失败了。
2. 使用二分法的话,有操作系统在干扰,不能必现。

如果后面有同学有想法或方法能查到增大部分的内存对应的代码的,可以一起讨论一下。

A:有个思路:

先看下进程的maps,一般一个so有3个映射,看看是不是可执行段(权限带x的)变大了,顺便记一下基地址,如果是:

  1. 可借助bugly符号表工具导一份il2cpp.so的符号表出来,符号表是文本格式的,可以知道任意地址范围对应的符号是什么。
  2. 拉一个游戏进程的smaps,过滤出il2cpp.so的地址范围,减上面的基地址。
  3. 写个小工具标出2里的范围对应1里的符号范围,能得知大概哪些代码进page了。

感谢littlesome@UWA问答社区提供了回答


iOS

Q:我们最近升级Unity到2019.4.29f1,在iOS上(目前发现的是iPhone 12 Pro + iOS 14.7.1)某些时候画面freeze,无法恢复只能退出。但是,只是画面被freeze(画面完全不动),逻辑仍然在跑(后端收到了网络包等,而发送网络包是在客户端主线程),所以排出了主线程死循环的问题。

请问这可能是什么原因呢?是某种Shader问题引发的GPU挂起么?

A:我们之前遇上过,原因是由于Shader报错导致系统crash,现象是画面卡死,Log会刷IOAF code 4。我们之前的解决方法可以参考:https://zhuanlan.zhihu.com/p/335293011

感谢梅辰@UWA问答社区提供了回答

 

封面图来源于网络


今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。

官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
UWA学堂:edu.uwa4d.com
官方技术QQ群:793972859(原群已满员)

 

posted @ 2022-01-24 10:34  UWATech  阅读(221)  评论(0编辑  收藏  举报