작성일: 2025년 9월 12일
📋 개요
언리얼 엔진 5.4에는 DirectX12가 지원되지 않는 하드웨어 환경에서 DirectX11로 자동 전환하는 강력한 호환성 시스템이 구현되어 있습니다. 이 문서는 해당 기능의 내부 구현을 상세히 분석합니다.
🏗️ 아키텍처 구조
핵심 컴포넌트
RHI (Render Hardware Interface)
├── WindowsDynamicRHI.cpp # 메인 RHI 선택 및 fallback 로직
├── D3D12RHI Module # DirectX12 구현체
│ └── WindowsD3D12Device.cpp # DX12 하드웨어 지원 검사
└── D3D11RHI Module # DirectX11 구현체
└── WindowsD3D11Device.cpp # DX11 하드웨어 지원 검사
📁 주요 구현 파일
파일 | 역할 |
---|---|
Engine/Source/Runtime/RHI/Private/Windows/WindowsDynamicRHI.cpp |
RHI 선택, fallback 메커니즘 |
Engine/Source/Runtime/D3D12RHI/Private/Windows/WindowsD3D12Device.cpp |
DirectX12 하드웨어 지원 검사 |
Engine/Source/Runtime/Windows/D3D11RHI/Private/Windows/WindowsD3D11Device.cpp |
DirectX11 하드웨어 지원 검사 |
🔄 Fallback 메커니즘
1. RHI 우선순위 정의
// WindowsDynamicRHI.cpp:76-82
const EWindowsRHI GRHISearchOrder[] =
{
EWindowsRHI::D3D12, // 1순위: DirectX12
EWindowsRHI::D3D11, // 2순위: DirectX11 (fallback 대상)
EWindowsRHI::Vulkan, // 3순위: Vulkan
EWindowsRHI::OpenGL, // 4순위: OpenGL
};
엔진은 기본적으로 DirectX12를 우선 시도하고, 실패 시 DirectX11로 자동 전환합니다.
2. 핵심 Fallback 함수
// WindowsDynamicRHI.cpp:875-926
static bool HandleUnsupportedRHI(EWindowsRHI& WindowsRHI,
ERHIFeatureLevel::Type& FeatureLevel,
TOptional<EWindowsRHI> ForcedRHI,
const FParsedWindowsDynamicRHIConfig& Config)
{
// 강제 지정된 RHI가 있고 DirectX12인 경우 에러 처리
if (ForcedRHI && ForcedRHI == EWindowsRHI::D3D12)
{
// 사용자에게 오류 메시지 표시 후 종료
FMessageDialog::Open(EAppMsgType::Ok,
LOCTEXT("RequiredDX12", "DirectX 12 is not supported on your system. "
"Try running without the -dx12 or -d3d12 command line argument."));
return false;
}
// DirectX12에서 DirectX11로 자동 전환
if (WindowsRHI == EWindowsRHI::D3D12)
{
if (TOptional<ERHIFeatureLevel::Type> D3D11FeatureLevel =
Config.GetHighestSupportedFeatureLevel(EWindowsRHI::D3D11))
{
WindowsRHI = EWindowsRHI::D3D11; // RHI 변경
FeatureLevel = D3D11FeatureLevel.GetValue(); // Feature Level 조정
return true; // Fallback 성공
}
}
return false; // Fallback 실패
}
3. 메인 로드 프로세스
// WindowsDynamicRHI.cpp:973-1011
do
{
// RHI 모듈 로드 시도
IDynamicRHIModule* DynamicRHIModule =
FModuleManager::LoadModulePtr<IDynamicRHIModule>(ModuleName);
// 하드웨어 지원 여부 확인
if (DynamicRHIModule && DynamicRHIModule->IsSupported(DesiredFeatureLevel))
{
UE_LOG(LogRHI, Log, TEXT("RHI %s with Feature Level %s is supported and will be used."),
GetLogName(ChosenRHI), GetLogName(DesiredFeatureLevel));
return DynamicRHIModule; // 성공
}
// 현재 설정 백업
const EWindowsRHI PreviousRHI = ChosenRHI;
const ERHIFeatureLevel::Type PreviousFeatureLevel = DesiredFeatureLevel;
// Fallback 시도
bTryWithNewConfig = HandleUnsupportedRHI(ChosenRHI, DesiredFeatureLevel,
ForcedRHI, Config);
if (bTryWithNewConfig)
{
UE_LOG(LogRHI, Log,
TEXT("RHI %s with Feature Level %s is not supported, "
"attempting to fall back to RHI %s with Feature Level %s"),
GetLogName(PreviousRHI), GetLogName(PreviousFeatureLevel),
GetLogName(ChosenRHI), GetLogName(DesiredFeatureLevel));
}
} while (bTryWithNewConfig); // Fallback 성공 시 재시도
🔍 하드웨어 지원 검사
DirectX12 지원 검사
// WindowsD3D12Device.cpp:673-729
bool FD3D12DynamicRHIModule::IsSupported(ERHIFeatureLevel::Type RequestedFeatureLevel)
{
// 1. Windows 버전 검사 (최소 Windows 10 1703 필요)
if (!FPlatformMisc::VerifyWindowsVersion(10, 0, 15063))
{
UE_LOG(LogD3D12RHI, Warning,
TEXT("Missing full support for Direct3D 12. "
"Update to Windows 1703 or newer for D3D12 support."));
return false;
}
// 2. 어댑터 검색
if (ChosenAdapters.Num() == 0)
{
FindAdapter();
}
// 3. 유효한 어댑터 확인
if (ChosenAdapters.Num() == 0)
{
UE_LOG(LogD3D12RHI, Log, TEXT("No adapters were found."));
return false;
}
const FD3D12Adapter* Adapter = ChosenAdapters[0].Get();
if (!Adapter || !Adapter->GetDesc().IsValid())
{
UE_LOG(LogD3D12RHI, Log, TEXT("Adapter was not found"));
return false;
}
// 4. 어댑터 차단 여부 확인
if (IsAdapterBlocked(Adapter))
{
UE_LOG(LogD3D12RHI, Log, TEXT("Adapter was blocked by RHI.BlockIHVD3D12"));
return false;
}
// 5. Feature Level 지원 여부 확인
if (!IsAdapterSupported(Adapter, RequestedFeatureLevel))
{
UE_LOG(LogD3D12RHI, Log,
TEXT("Adapter only supports up to Feature Level '%s', "
"requested Feature Level was '%s'"),
*SupportedFeatureLevelName, *RequestedFeatureLevelName);
return false;
}
return true; // 모든 검사 통과
}
DirectX11 지원 검사
// WindowsD3D11Device.cpp:631-642
bool FD3D11DynamicRHIModule::IsSupported()
{
// 어댑터 검색 (필요시)
if(!ChosenAdapter.IsValid())
{
FindAdapter();
}
// DirectX 11.0 이상 Feature Level 지원 필수
return ChosenAdapter.IsValid()
&& ChosenAdapter.MaxSupportedFeatureLevel >= D3D_FEATURE_LEVEL_11_0;
}
하드웨어 디바이스 테스트
// WindowsD3D12Device.cpp:479-504
static bool SafeTestD3D12CreateDevice(IDXGIAdapter* Adapter,
D3D_FEATURE_LEVEL MinFeatureLevel,
FD3D12DeviceBasicInfo& OutInfo)
{
__try
{
ID3D12Device* Device = nullptr;
// DirectX12 디바이스 생성 시도
const HRESULT D3D12CreateDeviceResult =
D3D12CreateDevice(Adapter, MinFeatureLevel, IID_PPV_ARGS(&Device));
if (SUCCEEDED(D3D12CreateDeviceResult))
{
// 지원되는 최고 Feature Level 확인
OutInfo.MaxFeatureLevel = FindHighestFeatureLevel(Device, MinFeatureLevel);
OutInfo.MaxShaderModel = FindHighestShaderModel(Device);
GetResourceTiers(Device, OutInfo.ResourceBindingTier, OutInfo.ResourceHeapTier);
// Wave Operations 및 64비트 Atomic 지원 확인
OutInfo.bSupportsWaveOps = GetSupportsWaveOps(Device);
OutInfo.bSupportsAtomic64 = GetSupportsAtomic64(Adapter, Device);
Device->Release();
return true; // 성공
}
else
{
UE_LOG(LogD3D12RHI, Log,
TEXT("D3D12CreateDevice failed with code 0x%08X"),
static_cast<int32>(D3D12CreateDeviceResult));
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
// 예외 발생 시 실패 처리
}
return false; // 실패
}
⚠️ Fallback 발생 조건
시스템 레벨 조건
- Windows 버전 부족
- Windows 10 버전 1703 (빌드 15063) 미만
- DirectX12 API 지원 부족
- 하드웨어 미지원
- GPU가 DirectX12 Feature Level 미지원
- 필요한 하드웨어 기능 부재 (Wave Operations, 64-bit Atomics 등)
- 드라이버 문제
- DirectX12 디바이스 생성 실패
- 구형 그래픽 드라이버
설정 레벨 조건
- 어댑터 차단
RHI.BlockIHVD3D12
콘솔 변수에 의한 차단- 특정 GPU 벤더/모델 차단 목록
- Feature Level 불일치
- 요청된 Feature Level을 하드웨어가 지원하지 않음
- SM6, SM5 등 셰이더 모델 호환성 문제
📊 로그 메시지 분석
정상 동작 시
LogRHI: Using Default RHI: D3D12
LogRHI: Loading RHI module D3D12RHI
LogRHI: Checking if RHI D3D12 with Feature Level SM5 is supported by your system.
LogRHI: RHI D3D12 with Feature Level SM5 is supported and will be used.
Fallback 발생 시
LogRHI: Using Default RHI: D3D12
LogRHI: Loading RHI module D3D12RHI
LogRHI: Checking if RHI D3D12 with Feature Level SM5 is supported by your system.
LogD3D12RHI: Warning: Missing full support for Direct3D 12. Update to Windows 1703 or newer for D3D12 support.
LogRHI: RHI D3D12 with Feature Level SM5 is not supported on your system, attempting to fall back to RHI D3D11 with Feature Level SM5
LogRHI: Loading RHI module D3D11RHI
LogRHI: RHI D3D11 with Feature Level SM5 is supported and will be used.
🎛️ 사용자 제어 옵션
명령줄 인수
-dx12
또는-d3d12
: DirectX12 강제 사용 (fallback 비활성화)-dx11
또는-d3d11
: DirectX11 강제 사용-sm5
,-sm6
: 특정 셰이더 모델 강제 사용
설정 파일
[/Script/WindowsTargetPlatform.WindowsTargetSettings]
DefaultGraphicsRHI=DefaultGraphicsRHI_DX12 ; 기본값
; DefaultGraphicsRHI_DX11, DefaultGraphicsRHI_Vulkan 등 선택 가능
[D3DRHIPreference]
PreferredRHI=dx12 ; 게임 내 RHI 선호도
PreferredFeatureLevel=sm5 ; Feature Level 선호도
🔧 개발자를 위한 참고사항
Feature Level 매핑
DirectX Feature Level | 언리얼 RHI Feature Level | 셰이더 모델 |
---|---|---|
D3D_FEATURE_LEVEL_11_0 | ERHIFeatureLevel::SM5 | SM5.0 |
D3D_FEATURE_LEVEL_12_0 | ERHIFeatureLevel::SM5 | SM5.0 |
D3D_FEATURE_LEVEL_12_1 | ERHIFeatureLevel::SM6 | SM6.0+ |
커스텀 Fallback 로직 구현
// 커스텀 RHI 선택 로직 예제
EWindowsRHI ChooseCustomRHI(const FParsedWindowsDynamicRHIConfig& Config)
{
// 1. 프로젝트 설정 확인
if (TOptional<EWindowsRHI> ConfigDefault = Config.DefaultRHI)
{
return ConfigDefault.GetValue();
}
// 2. 하드웨어 기반 자동 선택
for (EWindowsRHI RHI : GRHISearchOrder)
{
if (TOptional<ERHIFeatureLevel::Type> HighestFL =
ChooseDefaultFeatureLevel(RHI, Config))
{
return RHI;
}
}
// 3. 기본값으로 DirectX11 사용
return EWindowsRHI::D3D11;
}
📈 성능 및 호환성 고려사항
DirectX12 vs DirectX11 성능 차이
기능 | DirectX12 | DirectX11 |
---|---|---|
CPU 오버헤드 | 낮음 | 높음 |
멀티스레딩 | 우수 | 제한적 |
메모리 관리 | 수동 (정밀) | 자동 |
호환성 | Windows 10+ | Windows 7+ |
최적화 권장사항
- 프로젝트 설정
- 타겟 플랫폼에 맞는 셰이더 컴파일
- Feature Level별 에셋 최적화
- 런타임 감지
// 현재 사용 중인 RHI 확인 const TCHAR* CurrentRHI = GetSelectedDynamicRHIModuleName(false); if (FCString::Strcmp(CurrentRHI, TEXT("D3D12RHI")) == 0) { // DirectX12 특화 최적화 }
🚀 결론
언리얼 엔진 5.4의 DirectX12 → DirectX11 자동 fallback 시스템은:
- ✅ 완전 자동화: 사용자 개입 없이 투명한 전환
- ✅ 다단계 검증: Windows 버전, 하드웨어, 드라이버 모든 레벨 검사
- ✅ 상세한 로깅: 디버깅과 문제 해결을 위한 풍부한 로그
- ✅ 유연한 설정: 개발자와 사용자 모두를 위한 제어 옵션
- ✅ 안정성 보장: 예외 처리와 안전한 실패 처리
이 시스템 덕분에 언리얼 엔진으로 개발된 게임은 다양한 하드웨어 환경에서 안정적으로 실행될 수 있으며, 개발자는 호환성 문제에 대한 걱정 없이 최신 그래픽 기술을 활용할 수 있습니다.
'UNREAL ENGINE' 카테고리의 다른 글
일부 휴대폰에서 VulkanRHI를 사용할 때 GPUSort 결과가 정확하지 않는 이슈. (0) | 2025.09.12 |
---|---|
Unreal Engine Data Validation 플러그인 API 총정리 및 확장 가이드 (1) | 2025.09.10 |
.Uasset 데이터 Validation 기능 몇 가지. (3) | 2025.07.09 |
어셋 레퍼런스 규칙 위반 검사기 플러그인. (1) | 2025.05.24 |
CommonViewUniformBuffer 에 대해서... (0) | 2025.03.23 |