乐趣区

关于shader:抓取手机端变体组合思路设想

1)抓取手机端变体组合思路构想
​2)如何革除 File.ReadAllBytes 产生的内存泄露
3)atlas.GetSprite(name) 内存泄露
4)Unity 版本更新后 Odin 插件序列化报错


这是第 303 篇 UWA 技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫 10 分钟,认真读完必有播种。

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

Shader

Q:对于变体收集的问题,PC 端编辑器尽管自带收集,然而毕竟运行的时候是 Editor 环境,与实在挪动端环境相差甚远。Warmup 只会预加载列表中的组合,非 Shader 打包的全副组合。这样如果收集的变体非实在环境,只会白白浪费 CPU 及 GPU 显存,等实在渲染的时候发现之前提交的组合非挪动端所须要的,须要从新 Warmup。

再者,如果做品质划分,比方粗劣画面开动静暗影,晦涩机型关。这样会产生两套组合。实践上应该分成两个 SVC,而 PC 是只能保留所有的变体列表。

综上,我构想解决方案就是通过实在跑手机,抓取手机的应用数据,来划分到不同的列表中,这样应该是最实在牢靠的。

为了实现这个构想,须要能找到如何取得提交的变体数据,已知能够在 profiler-CPU-Timeline 模式下的 Shader.CreateGPUProgram 外面的 meta_data 外面能够拿到。

通过 CS 源码剖析到 NativeProfilerTimeline 这个控件是绘制 Timeline 的外围类。NativeProfilerTimeline.GetEntryInstanceInfo 这个函数能够拿到对应的 meta_data。

然而这个类是 C ++ 底层写的,C# 只是 Draw 去提交绘制。GetEntryAtPosition 去依据鼠标地位来取得 Entry,代码无奈反射到 EntryIndex。当初陷入了死胡同。

大家有解决办法或者新的思路吗?最好能获取手机上的变体列表。

A:能够在 Graphics 面板上勾选这个 Log Shader Compilation:

编辑器下 Console 连贯真机,这样就能够在触发 Shader.CreateGPUProgram 时看到相应的 Log:
Autoconnected Player Compiled shader: Unlit/TestShader, pass: <unnamed>, stage: all, keywords FOG_EXP2

感激宗卉轩 @UWA 问答社区提供了答复

Memory

Q:最近我的项目玩的工夫长了,内存始终暴增。在查看过程中,发现游戏中用了一个 File.ReadAllBytes 办法来读取几个 5~10MB 不等的二进制数据,加载完数据曾经复制 null,然而 Mono 还是始终增长,调用 GC 都开释不掉。

实践上来讲这个数组业务层曾经没有援用了。然而,用 Memory Profiler 查看,内存还始终在。求教一下,有没有人晓得革除的办法?

Unity 版本 2019.4.9

A1:缓冲区不必每次都 new 一个。

感激 jim@UWA 问答社区提供了答复

A2:如果是 Mono 版本的 APK,能够试试 IL2CPP。如果 IL2CPP 版本没有这个问题,应该是遇到 Mono 的 Bug 了,一次性调配较多的堆内存,会概率呈现这些调配的堆内存无奈回收的问题。

感激 Xuan@UWA 问答社区提供了答复

A3:Boehm GC 自身的缺点导致的,能够搜搜 BlackList,若有源码,能够有很多种防止或小修的改法;若没源码能够尝试:

  1. 缩小字典中 Struct 当 Key;
  2. 拆小文件,重写 File 的接口,复用内存。

感激 kent@UWA 问答社区提供了答复

Script

Q:Unity 版本 2019.4.23,发现在频繁调用 atlas.GetSprite(name) 时会内存泄露,只增不减,直至解体!有人遇到过这问题吗?请问有什么好的解决办法吗?

A1:如果不思考引擎自身 Bug 的状况下,内存泄露大部分都是援用没有解决好。可能有些中央还在应用这些资源,只是没关联上,导致无奈回收这部分资源。所以能够着重先排查这部分性能。

感激廖武兴 @UWA 问答社区提供了答复

A2:
//
// 摘要:
// Clone the first Sprite in this atlas that matches the name packed in this atlas
// and return it.
//
// 参数:
// name:
// The name of the Sprite.
public Sprite GetSprite(string name);

依据这段的说法是 Clone,也就是说每次调用 GetSprite,都会执行一次克隆操作,并且不会主动开释。

那么就要用治理脚本做一个缓冲池,反复的 Sprite 间接从池子里获取。并且开释的时候也从该脚本进行开释。

Dictionary<string, Sprite> mSpritePool = new Dictionary<string, Sprite>();
public Sprite GetSprite(string key, SpriteAtlas source)
    {
        Sprite result = null;
        if(!mSpritePool.TryGetValue(key, out result))
        {result = source.GetSprite(key);
            if (result != null)
            {mSpritePool.Add(key, result);
            }
        }

        return result;
    }

还能够做 SpriteAtlas 对象的键值对寄存,不便获取和开释。

感激 canyon@UWA 问答社区提供了答复

Script

Q:Unity 版本更新后 Odin 序列化,版本更新后,从 2020.3.21 更新到 2021.3.41 后就呈现这个问题。

A:Odin 仓库有个相似的问题,在 3.0.13.0 版本修复了,试一下降级插件版本:
https://bitbucket.org/sirenix…

感激羽飞 @UWA 问答社区提供了答复

封面图来源于网络


明天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题兴许都只是冰山一角,咱们早已在 UWA 问答网站上筹备了更多的技术话题等你一起来摸索和分享。欢送酷爱提高的你退出,兴许你的办法恰能解他人的当务之急;而他山之“石”,也能攻你之“玉”。

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

退出移动版