최근 5.5.4 업데이트 후 가장 크게 문제되는 부분을 꼽자면
PSOprecache 부분이 되겠습니다. PSOprecache 자체가 워낙 반복개발로 분류 된 피처라서 계속 수정되고 있습니다.
문제는 5.5.4 네요. PSOprecache 에 대한 스레드 관리부분에서 많은 문제점이 있습니다. PC 에서는 문제가 거의 발생하지 않지만 성능이 좋지 않은 PC 또는 모바일 하드웨어에서는 매우 큰 문제를 유발하고 있어요.
ue5_main 브렌치의 3월 19일짜 브렌치쪽의 Engine/Source/Runtime/RHI/Private/PipelineStateCache.cpp 를 좀 살펴 볼까요?
#if PLATFORM_SUPPORTS_WORKGRAPH_SHADERS
Hash = HashCombineFast(Hash, GetTypeHash(Input.GetWorkGraphShader()));
#endif
WorkGraph Shader는 특정 GPU 연산 및 워크로드 최적화를 가능하게 하는 셰이더입니다. 이런 셰이더는 고급 플랫폼이나 API(예: Vulkan, DirectX 12)에서 지원됩니다. 지원되지 않는 플랫폼(또는 셰이더 모델)에서는 이 코드를 빌드하지 않도록 하기 위해 사용됩니다. WorkGraph Shader에 해당하는 데이터를 사용하여 해시 값을 추가적으로 계산한 뒤 기존의 해시 값에 결합합니다.
FRWScopeLock InterruptGuard(InterruptLock, SLT_ReadOnly);
FRWScopeLock은 Unreal Engine에서 읽기/쓰기 잠금을 쉽게 관리하기 위해 제공되는 동기화 클래스입니다.Read-Only Lock (SLT_ReadOnly)는 여러 스레드에서 안전하게 읽기 작업만 수행할 수 있도록 설정합니다. 동기화 스레드 안정성 부분 작업이 진행 중임을 알 수 있습니다.
void GetResources(TArray<TRefCountPtr<FRHIResource>>& OutResources, bool bConsolidateWithInterrupt, UE::FTimeout ConsolidationTimeout)
{
FRWScopeLock InterruptGuard(InterruptLock, SLT_Write);
// Wait for any in-flight consolidation.
// Consolidation is predicated on command context completion, allow for a timeout in case it's blocked
if (bConsolidateWithInterrupt && WaitAndFinishAsyncCacheConsolidation(ConsolidationTimeout))
{
bIsInterrupt = true;
// Kick off a new one
FlushResources(false);
WaitAndFinishAsyncCacheConsolidation(ConsolidationTimeout);
bIsInterrupt = false;
}
for (auto&& [Desc, State] : *CurrentMap)
{
OutResources.Add(TRefCountPtr<FRHIResource>(State->RHIPipeline));
}
}
쓰기 잠금설정, 비동기 병합처리, 리소스 수집등을 수행하는 함수가 추가 되었습니다. 비동기 병합 작업이 완료될 때까지 대기하거나 타임아웃 조건을 처리 합니다. 플러시를 통해 이전 리소스를 정리하고 병합을 재실행한 후 리소스를 수집하여 호출자에게 반환 합니다. 그래픽 파이프라인 데이터를 안전하고 효율적으로 수집하는데 의미가 있는 함수입니다. 병합과 비동기 작업 처리하며 병합 도중에도 교착 상태를 방지하도록 동기화 메커니즘을 사용합니다. 잠금관리와 복잡성을 줄이고 안정성을 향상하는데 의미가 있습니다. RAII 패턴 활용.
FlushResources() 쪽도 수정 되고 있습니다.
void FlushResources(bool bInDiscardAndSwap)
{
SCOPED_NAMED_EVENT(ConsolidateThreadedCaches, FColor::Turquoise);
if (!bIsInterrupt)
{
InterruptLock.ReadLock();
}
ON_SCOPE_EXIT
{
if (!bIsInterrupt)
{
InterruptLock.ReadUnlock();
}
};
스코프 범위 내에서 잠금 관리를 안전하게 수행하도록 수정이 진행 중입니다. 스코프를 벗어날 때 자동으로 잠금을 해제 합니다. ConsolidateThreadedCaches 라는 이름으로 추적하며 프로파일링 데이터를 기록합니다. 잠금관리를 간소화 하며 읽기 쓰기 동기화 처리가 수정되고 있습니다.
bool WaitAndFinishAsyncCacheConsolidation(UE::FTimeout Timeout)
{
if (!RHICompletionEvent)
{
return true;
}
if (!RHICompletionEvent->FTaskBase::Wait(Timeout))
{
return false;
}
RHICompletionEvent = nullptr;
FinishAsyncCacheConsolidation();
return true;
}
비동기 작업이 완료되기를 기다리고 관련 리소스를 정리합니다. 비동기 이벤트를 확인하고 RHICompletionEvent가 존재하지 않으면 병합작업이 이미 완료된 것으로 간주하고 참을 반환 합니다. 비동기 작업 완료 대기를 하고 시간이 초과되면 거짓을 반환 합니다. 병합 완료 및 정리에 대한 함수로서 비동기 병합 완료관리, 리소스 정리 및 유연한 시간제한 관리를 위한 의미가 있습니다.
FGraphEventArray Prerequisites;
if (!bIsInterrupt)
{
// Add the completion of the RHI cache consolidation as a prerequisite for the next RHI dispatch.
GRHICommandList.AddNextDispatchPrerequisite(RHICompletionEvent);
Prerequisites.Add(GRHICommandList.GetCompletionEvent());
}
비동기 그래픽 작업에서 작업 순서와 작업간 의존성을 명확하게 관리하는데 사용됩니다. 작업 순서 보장 및 리소스 일관성을 유지하도록 합니다. 비동기 RHI 작업(캐시 병합과 같은)이 선행 작업으로 설정되야하고 완료된 후에만 다음 그래픽 명령이 실행 되도록 의존성 그래프를 구축 합니다.
bIsInterrupt == false 인 경우에만 RHI 캐시 병합 작업(RHICompletionEvent)을 다음 명령의 "필수 선행 작업"으로 설정합니다.
FGraphEventArray
작업 그래프의 의존성(Prerequisite)을 관리하는 자료 구조입니다. 이 배열은 특정 작업이 실행되기 전에 완료되어야 할 선행 작업(Prerequisites)을 저장합니다. 나중에 이 배열에 등록된 작업들이 모두 완료된 후에야 다음 작업이 시작됩니다.
GRHICommandList.GetCompletionEvent(),
이 부분은
&Prerequisites,
이렇게 변경됩니다. Prerequisites의 주소를 포인터 형태로 전달합니다. &Prerequisites 를 사용하여 선행작업을 묶어 관련 작업의 완료 이후에만 다음 작업이 실행되도록 보장합니다.
'UNREAL ENGINE' 카테고리의 다른 글
CommonViewUniformBuffer 에 대해서... (0) | 2025.03.23 |
---|---|
언리얼 엔진 5.5.X 인스톨빌드 이슈 회피에 대하여. (0) | 2025.03.23 |
[날로먹기] 셰이더용 사용자 디렉티브를 만들고 싶지 않을 때 (0) | 2025.03.18 |
Plugin 개발만 git 으로 관리 할 때 플러그인 경로 (0) | 2025.03.14 |
FAndroidMisc 클래스 (0) | 2025.03.14 |