Unreal Engine* 4.19 发布之后,许多特性针对多核处理器而优化。过去,游戏引擎在图形特性和性能方面采用控制台设计点。一般而言,多数游戏未针对处理器进行优化,这使得大量 PC 性能得不到充分发挥。英特尔与 Unreal Engine 4 的合作重点是尽快帮助使用引擎的开发人员释放游戏的潜能,以充分利用 PC 平台的所有处理器计算能力。
英特尔对 Unreal Engine* 4.19 的支持工作取得了以下成效:
- 增加了匹配用户处理器的工作线程的数量
- 提高了布料物理系统的吞吐量
- 集成了对英特尔® VTune™ 放大器的支持
为了充分利用高端 CPU 的额外计算能力,英特尔开发了一款能提供详细 CPU 指标与 SynthBenchmark 性能指标的插件。CPU 功能可以使用该插件的指标来划分特性与内容。通过这种方式划分特性与内容将支持您的游戏运行于各种系统,并且不会对整体性能造成影响。
如欲下载插件,请访问 GitHub Unreal 功能检测页面。
Unreal Engine* 4.19 功能检测插件
借助功能检测插件,您可以访问兼容 C++ 和蓝图的帮助函数(面向 CPU)、渲染硬件接口 (RHI) 函数和面向 CPU/GPU 的 SynthBenchmark 性能索引。
表 1.CPU 检测函数
第三方函数 | 蓝图函数 | 描述 |
---|---|---|
Intel_IsIntelCPU() | IsIntelCPU() | 如果是英特尔 CPU,返回 TRUE |
Intel_GetNumLogicalCores() | GetNumLogicalCores() | 返回逻辑内核数量 |
Intel_GetNumPhysicalCores() | GetNumPhysicalCores() | 返回物理内核数量 |
Intel_GetCoreFrequency() | GetCoreFrequency() | 返回当前的内核频率 |
Intel_GetMaxBaseFrequency() | GetMaxBaseFrequency() | 返回最大内核频率 |
Intel_GetCorePercMaxFrequency() | GetCorePercMaxFrequency() | 返回正在使用的最大内核频率 % |
Intel_GetFullProcessorName() | GetFullProcessorName() | 返回长处理器名称 |
Intel_GetProcessorName() | GetProcessorName() | 返回短处理器名称 |
Intel_GetSKU() | 不适用 | 未使用 |
表 2.高速缓存与内存检测函数
第三方函数 | 蓝图函数 | 描述 |
---|---|---|
Intel_GetUsablePhysMemoryGB() | GetUsablePhysMemoryGB() | 返回可用的物理内存(GB) |
Intel_GetComittedMemoryMB() | GetComittedMemoryMB() | 返回占用的内存(MB) |
Intel_GetAvailableMemoryMB() | GetAvailableMemoryMB() | 返回可用的内存(MB) |
表 3.渲染硬件接口 (RHI) 包装程序函数
第三方函数 | 蓝图函数 | 描述 |
---|---|---|
不适用 | IsRHIIntel() | 如果是英特尔 GPU,返回 TRUE |
不适用 | IsRHINVIDIA() | 如果是 NVIDIA GPU,返回 TRUE |
不适用 | IsRHIAMD() | 如果是 AMD GPU,返回 TRUE |
不适用 | RHIVendorName() | 返回 GPU 的厂商名称 |
表 4.SynthBenchmark 包装程序函数
第三方函数 | 蓝图函数 | 描述 |
---|---|---|
不适用 | ComputeCPUPerfIndex() | 100:一般、良好的 CPU, <100:较慢, >100:较快 |
不适用 | ComputeGPUPerfIndex() | 100:一般、良好的 GPU, <100:较慢, >100:较快 |
SynthBenchmark
使用 SythBenchmark 包装程序时需要注意,首次调用每个 ComputeCPUPerfIndex()和 ComputeGPUPerfIndex()都将产生少量的性能成本,同时计算性能索引。ComputeCPUPerfIndex()或 ComputeGPUPerfIndex()的首次和后续调用如果在运行基准性能测试时没有产生额外的开销,性能索引值将被缓存。对于游戏中依赖性能的部分,建议您在启动或加载界面的过程中调用这两个函数。
安装功能检测插件
1.从 GitHub*下载功能检测插件并打开项目文件夹。
2.如果插件文件夹不在根目录中,请立即添加。
3.将功能检测插件提取至插件文件夹。
4.使用 .uproject 文件夹启动项目。
5.访问主菜单中的 Edit > Plugins。加载插件窗口时,功能检测插件应安装在项目中。
现在,插件已安装完成,可以用它划分游戏内容与特性。下一节,我们将介绍 CPU 功能如何使用该插件划分特性。
Unreal Engine 4.19 特性划分
检测功能
为了借助平台配置划分特性,创建一个全新的 UDataAsset,并将其命名为 UPlatformConfig。UPlatformConfig 将存储目标平台的特征,如物理内核数量、逻辑内核数量、可用的物理内存、处理器名称和/或 SynthBenchmark 性能索引。
#include "CoreMinimal.h" #include "Engine/DataAsset.h" #include "PlatformConfig.generated.h" /** * Platform Configuration Data Asset */ UCLASS(BlueprintType) class CAPABILITYDETECTDEMO_API UPlatformConfig : public UDataAsset { GENERATED_BODY() public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Platform Configuration") float CPUPerfIndex; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Platform Configuration") FString Name; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Platform Configuration") bool IsIntelCPU; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Platform Configuration") int NumPhysicalCores; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Platform Configuration") int NumLogicalCores; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Platform Configuration") float UsablePhysMemoryGB; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Platform Configuration") float ComittedMemoryMB; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Platform Configuration") float AvailableMemoryMB; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Platform Configuration") float CacheSizeMB; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Platform Configuration") float MaxBaseFrequency; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Platform Configuration") float CoreFrequency; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Platform Configuration") float CorePercMaxFrequency; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Platform Configuration") FString FullProcessorName; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Platform Configuration") FString ProcessorName; };
接下来,我们可以使用静态功能设置名为 UPlatformTest的类,以比较 UPlatformConfig的属性与插件检测到的功能。
#include "CoreMinimal.h" #include "PlatformTest.generated.h" class UPlatformConfig; /** * Static functions for testing capabilities. */ UCLASS(BlueprintType) class CAPABILITYDETECTDEMO_API UCapabilityTest : public UObject { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = "Capabilities") static bool CapabilityTest(UPlatformConfig* config); UFUNCTION(BlueprintCallable, Category = "Capabilities") static UPlatformConfig* GetCapabilityLevel(); };
CapabilityTest()函数将比较 UPlatformConfig与功能检测插件检测到的特性。在本示例中,我们将检查物理内核、逻辑内核和 SynthBenchmark CPU 性能索引是否超越传输至函数的 UPlatformConfig属性。
bool UCapabilityTest::CapabilityTest(UPlatformConfig* config) { // True if system capabilities exceed platform definitions return UCapabilityDetectBPLib::GetNumPhysicalCores() >= config->NumPhysicalCores && UCapabilityDetectBPLib::GetNumLogicalCores() >= config->NumLogicalCores && UCapabilityDetectBPLib::ComputeCPUPerfIndex() >= config->CPUPerfIndex;
现在,我们已经找到了一个比较功能的办法,我们可以创建另一个函数来设置与测试平台配置。我们将创建一个名为 GetCapabilityLevel()的函数,并划分 4 个等级,分别是低、中、高和超高。我们将提供一个与特性等级对应的名称,为每个被测的配置指定物理/逻辑内核和 SynthBenchmark 性能索引。最后,由于我们使用大于等于号来比较 CapabilityTest(),我们将按照从高到低的顺序进行测试,并返回结果。
UPlatformConfig* UCapabilityTest::GetCapabilityLevel() { // Create Platform Definitions UPlatformConfig *ULTRA, *HIGH, *MEDIUM, *LOW; ULTRA = NewObject<UPlatformConfig>(); HIGH = NewObject<UPlatformConfig>(); MEDIUM = NewObject<UPlatformConfig>(); LOW = NewObject<UPlatformConfig>(); // Assign Properties to platform definitions. // LOW - 2 Physical Cores 4 Hyper-threads LOW->Name = TEXT("LOW"); LOW->NumPhysicalCores = 2; LOW->NumLogicalCores = 4; LOW->CPUPerfIndex = 0.0; // MEDIUM - 4 Physical Cores 8 Hyper-threads MEDIUM->Name = TEXT("MEDIUM"); MEDIUM->NumPhysicalCores = 4; MEDIUM->NumLogicalCores = 8; MEDIUM->CPUPerfIndex = 50.0; // HIGH - 6 Physical Cores 12 Hyper-threads HIGH->Name = TEXT("HIGH"); HIGH->NumPhysicalCores = 6; HIGH->NumLogicalCores = 12; HIGH->CPUPerfIndex = 100.0; // ULTRA - 8 Physical Cores 16 Hyper-threads ULTRA->Name = TEXT("ULTRA"); ULTRA->NumLogicalCores = 8; ULTRA->NumPhysicalCores = 16; ULTRA->CPUPerfIndex = 125.0; // Test platforms against detected capabilities. if (CapabilityTest(ULTRA)) { return ULTRA; } if (CapabilityTest(HIGH)) { return HIGH; } if (CapabilityTest(MEDIUM)) { return MEDIUM; } return LOW; }
C++ 中的检测功能
借助 UCapabilityTest类,现在我们可以确定 CPU 特性等级。我们可以使用来自 GetCapabilityLevel()的结果来划分 C++ 或蓝图中的内容。例如,如果我们创建了一个角色,便可以划分 Tick 函数中的特性。
// Called every frame void AMyActor::Tick(float DeltaTime) { Super::Tick(DeltaTime); UPlatformConfig* CapabilityLevel = UCapabilityTest::GetCapabilityLevel(); if (CapabilityLevel->Name == TEXT("LOW")) { // Use Simple Approximation for LOW end CPU... // e.g. Spawn 100 CPU Particles... } else if (CapabilityLevel->Name == TEXT("MEDIUM")) { // Use Advanced Approximation for MID range CPU... // e.g. Spawn 200 CPU Particles } else if (CapabilityLevel->Name == TEXT("HIGH")) { // Use Simple Simulation for HIGH end CPU... // e.g. Spawn 300 CPU Particles } else if (CapabilityLevel->Name == TEXT("ULTRA")) { // Use Advanced Approximation for ULTRA CPU... // e.g. Spawn 400 CPU Particles } }
蓝图中的检测功能
此外,我们可以将在角色的 Tick 函数中使用的 GetCapabilityLevel()函数应用于蓝图中,因为我们使用 UFUNCTION(BlueprintCallable) 属性对它进行了修饰。在本示例中,我们使用关卡蓝图并在 BeginPlay后调用 Get Capability Level节点。Get Capability Level节点返回的 UPlatformConfig值包含一个 Name属性。在 Switch on String 节点中,它可以用来划分您的等级特性。最后,我们只需将 CPU 特性等级的名称打印到屏幕上(图 1)。
图 1.蓝图功能检测
最后,我们介绍与功能检测插件一起封装的蓝图函数。借助该函数,您可以在蓝图中更细致地发掘平台细节。只需将检测功能节点添加至您的蓝图,然后利用游戏所需的值(图 2)。
图 2.检测功能蓝图节点
结论
随着现代 CPU 内核数量的增加,我们可以拥有更多的游戏功能。但是,相比配备高端系统的玩家,内核数量较少的玩家可能会处于劣势。为了缩小这种差距,可以使用 C++ 和蓝图划分特性。如前所示,划分特性将实现最大的 CPU 利用率,同时通过一系列平台配置帮助玩家维持固定的帧速率。