异步数据流
数据流是一种优化技术,旨在减少加载图形资源和编译着色器引起的峰值。使用此技术,并非所有数据都立即加载到随机存取存储器(RAM)中。取而代之的是,仅加载所需的数据,其余所有数据根据需要逐步加载。
执行资源加载,并在单独的异步线程中将其转移到GPU。之后,资源将同步并添加到CPU一侧的虚拟场景。
在 UNIGINE 中,默认启用异步数据流。 您可以在 UnigineEditor 中或通过控制台禁用异步数据流:
- 在UnigineEditor中,打开Settings窗口并转到Streaming部分。在这里你可以为纹理和/或网格切换流模式。
- 在控制台中,运行相应的命令,切换纹理和/或网格的流模式。
有两种主要的流模式——异步(Async)和强制(Force)。Force模式确保每帧一次加载所需的所有网格和纹理(例如,抓取帧序列,渲染节点预览,预热等)。
对于网格,有一个额外的All模式,它禁用网格流,并在应用程序启动时提供项目中所有可用网格的加载。这种模式适用于网格较少的小项目。
流系统提供以下数据异步加载到RAM:
- 所有纹理运行时文件和启用了Unchanged选项的纹理,包括cubemaps, 体素探针地图和烘烤阴影的阴影地图。
- ObjectMeshStatic, ObjectMeshClutter, ObjectMeshCluster, ObjectGuiMesh对象的网格,以及DecalMesh。
程序生成的对象(如ObjectMeshClutter)生成在一个单独的线程,显著降低性能成本。
可以通过使用render_streaming_meshes_info和render_streaming_textures_info控制台命令获取流资源的一般信息。
还可以通过使用render_streaming_meshes_list和render_streaming_textures_list控制台命令打印已加载资源的列表和有关它们的详细信息。
异步着色器编译#
除了网格和纹理的异步加载之外,流系统还提供异步着色器编译和加载。
还有 2 种模式 - 异步 (Async) 和强制 (Force)。 在Force模式下,当前帧所需的所有着色器都会在当前线程中同时编译并加载到RAM中。 默认情况下,采用异步模式。
Performance Profiler 工具中提供了已编译和加载的着色器数量。
通用流媒体设置#
为了在应用程序启动时立即显示场景,有一个First Frames Force参数,它设置在第一帧之后加载的帧数。
利用多线程,设置的最大线程数用于流媒体资源利用(国家统计局) render_streaming_max_threads 控制台参数。更高的线程数量导致更快的流,但可能导致峰值在GPU资源的过度消费。
内存限制#
您可以通过指定相应的 预算 来限制每帧加载和卸载的图形资源的数量。 使用它们来找到加载/卸载速度和性能之间的平衡点:请记住,增加预算会提高流媒体性能,但是,内存消耗也会增加。
可调整的内存限制和生命周期可以避免资源在不再使用后仍然加载在内存或视频内存中的情况。它们是为加载到RAM / VRAM的网格、纹理和粒子分别定义的,占总RAM / VRAM的百分比。
内存限制与生命周期关联:只有当内存或显存超过这两个值时,资源才会从内存或显存中删除。
内存限制和RAM / VRAM被流资源可在Performance Profiler工具。
限制用斜杠分隔:第一个值显示当前RAM / VRAM使用情况,第二个值是限制。
纹理缓存#
流传输系统使用纹理缓存,该纹理缓存由为具有用户定义的分辨率的所有纹理生成的最小化副本组成,并存储在 data/.cache_textures 文件夹中。这些副本将在加载时代替原始文件使用。
纹理缓存在引擎启动时加载,并始终在加载后保留在内存中。为了提供流畅的资源加载和呈现,流式实体具有以下加载优先级:
- 纹理缓存
- 几何形状
- 未缓存的纹理(由于在运行中为其生成纹理缓存时会产生尖峰;应用了未缓存和未加载纹理的材质会呈现黑色)
- 全尺寸纹理
使用boot配置文件中的 textures_cache_preload标志,您可以选择纹理缓存加载优先级:预加载或在几何数据后加载。
默认情况下,生成纹理缓存文件的分辨率为16x16,如此低的纹理分辨率会导致加载过程中出现视觉伪像。
通过设置Texture Cache Resolution参数来控制纹理缓存的分辨率。要应用更改,请使用render_streaming_textures_cache_destroy 控制台命令擦除现有的缓存文件,之后将使用新的指定分辨率自动生成纹理缓存。
视频内存数量目前占领的纹理缓存可用Performance Profiler工具。
render_streaming_textures_cache_load 和 render_streaming_textures_cache_unload 控制台命令使您能够控制加载纹理缓存。例如,加载后全尺寸的纹理,你可以卸载的纹理缓存视频内存更好的性能。
网流#
网格可以分别加载到RAM和VRAM中,以便更有效地处理几何图形。这允许消除内存泄漏:参与碰撞和交叉点的网格只能加载到RAM中,如果它们当前没有渲染。
有3种模式的网格流到RAM/VRAM:
- 异步模式,提供网格的异步加载。
- 强制模式,用于立即加载当前框架所需的网格。
- 模式加载 所有网格应用程序启动的项目。实际上,这种模式禁用网流。
异步加载到RAM和VRAM是不同的。即使网格没有及时加载到显存,它也不会影响应用程序的行为(您可能只会注意到一些延迟)。但是,如果网格没有及时加载到内存中,可能会导致场景中对象的物理行为不正确。
首先,我们强烈推荐您使用 形状碰撞和碰撞测试,因为它更快。如果出于某种原因,它不适合你,使用以下方法:
- 加载网格并在它们存在时将它们保存在内存中。一些基于网格的对象的API提供了开箱即用的功能。它可以部分解决不正确行为的问题,然而,只有少数网格可以保持加载。
-
使用预取系统,允许预装的网格参与碰撞和十字路口异步内存之前使用:
- 设置Radius预取模式。
- 指定物理半径(用于碰撞)和/或计算交叉点的半径。
- 指定应该超过碰撞和相交半径值的预取半径。
您还可以预加载所有网格计算碰撞和十字路口(Full预抓取模式),但是它将大大增加内存的使用。
- 一些基于网格(mesh)对象的API,以及MeshStatic类API也提供了允许实现预加载网格的自定义预取逻辑的方法。
异步流网格不应该被修改。改变这种网格的唯一方法是使其程序化。一个过程网格是一个通过代码创建的网格,这样的网格有一个特定的流模式——它们总是在创建后保存在内存中,永远不会卸载,直到对象被代码破坏或网格返回到它的正常模式(从源文件流)。基于网格的对象API允许将网格切换到过程模式并应用更改。
OpenGL设置#
OpenGL API的设置和工作流程与DirectX API略有不同。
在OpenGL,数据流系统使用两个中间缓冲区来提供CPU与新资源之间的数据传输:
- Async Buffer用于网格和纹理流处理
- Async Buffer Indices用于流化网格的顶点索引
Async Buffer缓冲区的 大小 必须与最大资源的大小(网格/纹理)相对应,否则,在资源较大的情况下,将调整缓冲区的大小,从而导致峰值。
如果将Async Buffer Synchronization参数设置为 1 ,则启用缓冲区同步机制。因此,异步缓冲区仅创建一次,然后进行同步,从而减少了分配和释放内存的时间。禁用同步后,将为每个新资源重新创建Async Buffer和Async Buffer Indices。这减少了缓冲区同步的次数,但增加了内存分配的数量。
有时(取决于所使用的硬件/驱动程序,例如,当主线程受到其他线程中的同步原语影响时),内存分配可能比同步要快;在这种情况下,当流变得异常缓慢时,建议禁用缓冲区同步。
一些硬件/驱动程序软件存在一些已知的问题和解决方法:
- Mesa 3D GL:必须禁用缓冲区同步(gl_async_buffer_synchronization 0),以获得更好的性能。需要更新的 Open Graphics Drivers 。
- Intel:有必要考虑到VRAM受操作系统限制为RAM的一半。