저자
그래픽 렌더링, 게임 엔진、GPU。知乎:http://www.zhihu.com/people/timlly-chang。UE技术群:943549515,위챗 그룹 먼저 추가 81079389(블로거 참고 사항)
10.1 이 문서의 개요
RHI는 UE 렌더링 시스템에서 매우 기본적이고 중요한 모듈인 렌더 하드웨어 인터페이스로, 여러 그래픽 API(DirectX, OpenGL, 벌칸, 메탈) 간의 차이점을 캡슐화하여 게임 및 렌더러 모듈에 쉽고 일관된 개념, 데이터, 리소스 및 인터페이스를 제공합니다.렌더러 모듈은 하나의 렌더링 코드를 여러 플랫폼에서 실행한다는 목표를 달성하기 위해 간단하고 일관된 개념, 데이터, 리소스 및 인터페이스를 제공합니다.
게임, 렌더러, RHI의 계층형 다이어그램, 여기서 RHI는 플랫폼과 관련이 있습니다.
원래 RHI는 D3D11 API를 기반으로 설계되었으며 리소스 관리 및 명령 인터페이스를 포함합니다:
RHI 스레드가 켜져 있으면 RHI와 함께 렌더링 스레드가 푸시한 RHI 중간 명령을 해당 그래픽 플랫폼에 맞는 GPU 명령어로 변환하는 역할을 하는 RHI 스레드가 함께 제공됩니다.일부 그래픽 API(DX12, 벌칸, 호스트)가 병렬 처리를 지원하는 경우, 렌더 스레드가 RHI 중간 명령을 병렬로 생성하는 경우 RHI 스레드도 병렬로 번역합니다.
병렬로 중간 명령을 생성하는 UE4의 렌더링 스레드와 병렬 변환 후 렌더링 명령을 제출하는 RHI 스레드의 모식도입니다.
이 글에서는 RHI의 기본 개념, 유형, 인터페이스, 이들 간의 연결, 관련 원리 및 메커니즘, 그리고 특정 그래픽 API의 구현 세부사항에 대해 간략하게 설명합니다.
10.2 RHI 기본 사항
이 장에서는 RHI와 관련된 기본 개념과 유형을 분석하여 이들의 관계와 원리를 설명합니다.
10.2.1 FRenderResource
FRenderResource는 렌더링 스레드를 대표하는 렌더링 리소스로, 게임 스레드와 RHI 스레드 사이의 중간 데이터인 렌더링 스레드에서 관리하고 전달합니다.이전 장에서 그 개념을 다루었으나 자세히 설명하지 않았기 때문에 이번 장에 넣었으며, FRenderResource의 정의는 다음과 같습니다:
// Engine\Source\Runtime\RenderCore\Public\RenderResource.h
class RENDERCORE_API FRenderResource
{
public:
// 모든 리소스를 반복하여 콜백 인터페이스를 실행합니다.
template<typename FunctionType>
static void ForAllResources(const FunctionType& Function);
static void InitRHIForAllResources();
static void ReleaseRHIForAllResources();
static void ChangeFeatureLevel(ERHIFeatureLevel::Type NewFeatureLevel);
FRenderResource();
FRenderResource(ERHIFeatureLevel::Type InFeatureLevel);
virtual ~FRenderResource();
// 다음 인터페이스는 렌더링 스레드에서만 호출할 수 있습니다.
// 이 리소스에 대한 동적 RHI 리소스 및/또는 RHI 렌더링 타깃 텍스처를 초기화합니다.
virtual void InitDynamicRHI() {}
// 이 리소스에 대한 동적 RHI 리소스 및/또는 RHI 렌더링 타깃 텍스처를 해제합니다.
virtual void ReleaseDynamicRHI() {}
// 이 리소스에 사용되는 RHI 리소스를 초기화합니다.
virtual void InitRHI() {}
// 이 리소스에 사용된 RHI 리소스를 공개합니다.
virtual void ReleaseRHI() {}
// 리소스 초기화 중 .
virtual void InitResource();
// 리소스 릴리스.
virtual void ReleaseResource();
// RHI 리소스가 초기화된 경우 해제되었다가 다시 초기화됩니다.
void UpdateRHI();
virtual FString GetFriendlyName() const { return TEXT("undefined"); }
FORCEINLINE bool IsInitialized() const { return ListIndex != INDEX_NONE; }
static void InitPreRHIResources();
private:
// 글로벌 리소스 목록(정적).
static TArray<FRenderResource*>& GetResourceList();
static FThreadSafeCounter ResourceListIterationActive;
int32 ListIndex;
TEnumAsByte<ERHIFeatureLevel::Type> FeatureLevel;
(......)
};
다음은 게임 스레드가 렌더링 스레드에 FRenderResource 작업을 전송하는 인터페이스입니다:
// 리소스를 초기화/업데이트/해제합니다.
extern RENDERCORE_API void BeginInitResource(FRenderResource* Resource);
extern RENDERCORE_API void BeginUpdateResourceRHI(FRenderResource* Resource);
extern RENDERCORE_API void BeginReleaseResource(FRenderResource* Resource);
extern RENDERCORE_API void StartBatchedRelease();
extern RENDERCORE_API void EndBatchedRelease();
extern RENDERCORE_API void ReleaseResourceAndFlush(FRenderResource* Resource);
FRenderResource는 리소스 렌더링을 위한 일련의 동작을 정의하는 기본 부모 클래스일 뿐이며, 실제 데이터와 로직은 서브클래스에 의해 구현됩니다.관련된 서브클래스와 계층 구조는 다양하고 복잡하며, 다음은 몇 가지 중요한 서브클래스의 정의입니다:
// Engine\Source\Runtime\RenderCore\Public\RenderResource.h
// 텍스처 리소스.
class FTexture : public FRenderResource
{
public:
FTextureRHIRef TextureRHI; // 텍스처용 RHI 리소스.
FSamplerStateRHIRef SamplerStateRHI; // 텍스처 샘플러 RHI 리소스.
FSamplerStateRHIRef DeferredPassSamplerStateRHI; // 디퍼드페스 채널 샘플러 RHI 리소스.
mutable double LastRenderTime; // 마지막 렌더링 시간입니다.
FMipBiasFade MipBiasFade; // 페이드 인/아웃을 위한 밉 오프셋 값입니다.
bool bGreyScaleFormat; // 그레이 스케일 이미지.
bool bIgnoreGammaConversions; // 감마 변환을 무시할지 여부입니다.
bool bSRGB; // 색상이 sRGB 공간에 있는지 여부.
virtual uint32 GetSizeX() const;
virtual uint32 GetSizeY() const;
virtual uint32 GetSizeZ() const;
// 리소스 릴리스.
virtual void ReleaseRHI() override
{
TextureRHI.SafeRelease();
SamplerStateRHI.SafeRelease();
DeferredPassSamplerStateRHI.SafeRelease();
}
virtual FString GetFriendlyName() const override { return TEXT("FTexture"); }
(......)
protected:
RENDERCORE_API static FRHISamplerState* GetOrCreateSamplerState(const FSamplerStateInitializerRHI& Initializer);
};
// SRV/UAV용 텍스처 리소스를 포함합니다.
class FTextureWithSRV : public FTexture
{
public:
// 전체 텍스처의 SRV에 액세스합니다.
FShaderResourceViewRHIRef ShaderResourceViewRHI;
// 전체 텍스처의 UAV에 액세스합니다.
FUnorderedAccessViewRHIRef UnorderedAccessViewRHI;
virtual void ReleaseRHI() override;
};
// RHI 텍스처 리소스에 대한 레퍼런스를 보유한 렌더링 리소스입니다.
class RENDERCORE_API FTextureReference : public FRenderResource
{
public:
// 텍스처에 대한 RHI 리소스 레퍼런스입니다.
FTextureReferenceRHIRef TextureReferenceRHI;
// FRenderResource interface.
virtual void InitRHI();
virtual void ReleaseRHI();
(......)
};
class RENDERCORE_API FVertexBuffer : public FRenderResource
{
public:
// 버텍스 버퍼에 대한 RHI 리소스 참조.
FVertexBufferRHIRef VertexBufferRHI;
virtual void ReleaseRHI() override;
(......);
};
class RENDERCORE_API FVertexBufferWithSRV : public FVertexBuffer
{
public:
// 전체 버퍼의 SRV/UAV에 액세스합니다.
FShaderResourceViewRHIRef ShaderResourceViewRHI;
FUnorderedAccessViewRHIRef UnorderedAccessViewRHI;
(......)
};
// 인덱스 버퍼.
class FIndexBuffer : public FRenderResource
{
public:
// 인덱스 버퍼에 해당하는 RHI 리소스입니다.
FIndexBufferRHIRef IndexBufferRHI;
(......)
};
위에서 볼 수 있듯이 FRenderResource의 서브클래스는 렌더링 스레드가 게임 스레드의 데이터와 연산을 RHI 스레드(또는 모듈)로 전달할 수 있도록 리소스를 캡슐화하는 RHI의 해당 서브클래스입니다.다음은 FRenderResource 상속 시스템의 일부를 시각화한 UML 다이어그램입니다:
다시 말하지만, 위의 내용은 FRenderResource의 상속 시스템의 일부일 뿐이며, 완전히 매핑할 수는 없습니다.
FRenderResource는 리소스 측면에서 복잡하고 변화하는 UE 렌더링 시스템의 요구를 충족하고 적응하기 위해 거대한 서브클래스 계층구조를 가지고 있음을 알 수 있습니다.
10.2.2 FRHIResource
FRHIResource는 GPU 측의 리소스를 추상화하며 많은 RHI 리소스 유형의 상위 클래스입니다.정의는 다음과 같습니다:
// Engine\Source\Runtime\RHI\Public\RHIResources.h
class RHI_API FRHIResource
{
public:
FRHIResource(bool InbDoNotDeferDelete = false);
virtual ~FRHIResource();
// 리소스의 참조 수입니다.
uint32 AddRef() const;
uint32 Release() const
{
int32 NewValue = NumRefs.Decrement();
if (NewValue == 0)
{
if (!DeferDelete())
{
delete this;
}
else
{
// 보류 중인 삭제 목록에 추가합니다.
if (FPlatformAtomics::InterlockedCompareExchange(&MarkedForDelete, 1, 0) == 0)
{
PendingDeletes.Push(const_cast<FRHIResource*>(this));
}
}
}
return uint32(NewValue);
}
uint32 GetRefCount() const;
// 정적 인터페이스.
static void FlushPendingDeletes(bool bFlushDeferredDeletes = false);
static bool PlatformNeedsExtraDeletionLatency();
static bool Bypass();
void DoNoDeferDelete();
// 즉각적인 리소스 추적.
void SetCommitted(bool bInCommitted);
bool IsCommitted() const;
bool IsValid() const;
private:
// 런타임 마커 및 데이터.
mutable FThreadSafeCounter NumRefs;
mutable int32 MarkedForDelete;
bool bDoNotDeferDelete;
bool bCommitted;
// 삭제할 리소스입니다.
static TLockFreePointerListUnordered<FRHIResource, PLATFORM_CACHE_LINE_SIZE> PendingDeletes;
// 삭제되는 리소스입니다.
static FRHIResource* CurrentlyDeleting;
bool DeferDelete() const;
// 일부 API는 내부 참조 카운팅을 수행하지 않으므로 리소스를 삭제하기 전에 몇 프레임을 더 기다렸다가
// GPU가 완전히 완료되었는지 확인해야 합니다. 값비싼 펜싱 등을 피할 수 있습니다.
struct ResourcesToDelete
{
TArray<FRHIResource*> Resources; // 待删除的资源.
uint32 FrameDeleted; // 等待的帧数.
(......)
};
// 지연된 삭제를 위한 리소스 큐 .
static TArray<ResourcesToDelete> DeferredDeletionQueue;
static uint32 CurrentFrame;
};
위에서 볼 수 있듯이 FRHIResource는 참조 카운팅, 지연된 삭제 및 추적, 런타임 데이터 및 태깅 등 여러 가지 기능을 제공합니다.주요 하위 클래스는 다음과 같습니다:
// Engine\Source\Runtime\RHI\Public\RHIResources.h
// 상태 차단 리소스
class FRHISamplerState : public FRHIResource
{
public:
virtual bool IsImmutable() const { return false; }
};
class FRHIRasterizerState : public FRHIResource
{
public:
virtual bool GetInitializer(struct FRasterizerStateInitializerRHI& Init) { return false; }
};
class FRHIDepthStencilState : public FRHIResource
{
public:
virtual bool GetInitializer(struct FDepthStencilStateInitializerRHI& Init) { return false; }
};
class FRHIBlendState : public FRHIResource
{
public:
virtual bool GetInitializer(class FBlendStateInitializerRHI& Init) { return false; }
};
// 셰이더 바인딩 리소스.
typedef TArray<struct FVertexElement,TFixedAllocator<MaxVertexElementCount> > FVertexDeclarationElementList;
class FRHIVertexDeclaration : public FRHIResource
{
public:
virtual bool GetInitializer(FVertexDeclarationElementList& Init) { return false; }
};
class FRHIBoundShaderState : public FRHIResource {};
// 셰이더
class FRHIShader : public FRHIResource
{
public:
void SetHash(FSHAHash InHash);
FSHAHash GetHash() const;
explicit FRHIShader(EShaderFrequency InFrequency);
inline EShaderFrequency GetFrequency() const;
private:
FSHAHash Hash;
EShaderFrequency Frequency;
};
class FRHIGraphicsShader : public FRHIShader
{
public:
explicit FRHIGraphicsShader(EShaderFrequency InFrequency) : FRHIShader(InFrequency) {}
};
class FRHIVertexShader : public FRHIGraphicsShader
{
public:
FRHIVertexShader() : FRHIGraphicsShader(SF_Vertex) {}
};
class FRHIHullShader : public FRHIGraphicsShader
{
public:
FRHIHullShader() : FRHIGraphicsShader(SF_Hull) {}
};
class FRHIDomainShader : public FRHIGraphicsShader
{
public:
FRHIDomainShader() : FRHIGraphicsShader(SF_Domain) {}
};
class FRHIPixelShader : public FRHIGraphicsShader
{
public:
FRHIPixelShader() : FRHIGraphicsShader(SF_Pixel) {}
};
class FRHIGeometryShader : public FRHIGraphicsShader
{
public:
FRHIGeometryShader() : FRHIGraphicsShader(SF_Geometry) {}
};
class RHI_API FRHIComputeShader : public FRHIShader
{
public:
FRHIComputeShader() : FRHIShader(SF_Compute), Stats(nullptr) {}
inline void SetStats(struct FPipelineStateStats* Ptr) { Stats = Ptr; }
void UpdateStats();
private:
struct FPipelineStateStats* Stats;
};
// 파이프라인 상태
class FRHIGraphicsPipelineState : public FRHIResource {};
class FRHIComputePipelineState : public FRHIResource {};
class FRHIRayTracingPipelineState : public FRHIResource {};
// 버퍼.
class FRHIUniformBuffer : public FRHIResource
{
public:
FRHIUniformBuffer(const FRHIUniformBufferLayout& InLayout);
FORCEINLINE_DEBUGGABLE uint32 AddRef() const;
FORCEINLINE_DEBUGGABLE uint32 Release() const;
uint32 GetSize() const;
const FRHIUniformBufferLayout& GetLayout() const;
bool HasStaticSlot() const;
private:
const FRHIUniformBufferLayout* Layout;
uint32 LayoutConstantBufferSize;
};
class FRHIIndexBuffer : public FRHIResource
{
public:
FRHIIndexBuffer(uint32 InStride,uint32 InSize,uint32 InUsage);
uint32 GetStride() const;
uint32 GetSize() const;
uint32 GetUsage() const;
protected:
FRHIIndexBuffer();
void Swap(FRHIIndexBuffer& Other);
void ReleaseUnderlyingResource();
private:
uint32 Stride;
uint32 Size;
uint32 Usage;
};
class FRHIVertexBuffer : public FRHIResource
{
public:
FRHIVertexBuffer(uint32 InSize,uint32 InUsage)
uint32 GetSize() const;
uint32 GetUsage() const;
protected:
FRHIVertexBuffer();
void Swap(FRHIVertexBuffer& Other);
void ReleaseUnderlyingResource();
private:
uint32 Size;
// e.g. BUF_UnorderedAccess
uint32 Usage;
};
class FRHIStructuredBuffer : public FRHIResource
{
public:
FRHIStructuredBuffer(uint32 InStride,uint32 InSize,uint32 InUsage)
uint32 GetStride() const;
uint32 GetSize() const;
uint32 GetUsage() const;
private:
uint32 Stride;
uint32 Size;
uint32 Usage;
};
// 도움말
class FRHITexture : public FRHIResource
{
public:
FRHITexture(uint32 InNumMips, uint32 InNumSamples, EPixelFormat InFormat, uint32 InFlags, FLastRenderTimeContainer* InLastRenderTime, const FClearValueBinding& InClearValue);
// 동적 유형 변환 인터페이스.
virtual class FRHITexture2D* GetTexture2D();
virtual class FRHITexture2DArray* GetTexture2DArray();
virtual class FRHITexture3D* GetTexture3D();
virtual class FRHITextureCube* GetTextureCube();
virtual class FRHITextureReference* GetTextureReference();
virtual FIntVector GetSizeXYZ() const = 0;
// 플랫폼 관련 기본 리소스에 대한 포인터를 받으세요.
virtual void* GetNativeResource() const;
virtual void* GetNativeShaderResourceView() const
// 플랫폼 관련 RHI 텍스처 베이스 클래스를 가져옵니다.
virtual void* GetTextureBaseRHI();
// 데이터 인터페이스.
uint32 GetNumMips() const;
EPixelFormat GetFormat();
uint32 GetFlags() const;
uint32 GetNumSamples() const;
bool IsMultisampled() const;
bool HasClearValue() const;
FLinearColor GetClearColor() const;
void GetDepthStencilClearValue(float& OutDepth, uint32& OutStencil) const;
float GetDepthClearValue() const;
uint32 GetStencilClearValue() const;
const FClearValueBinding GetClearBinding() const;
virtual void GetWriteMaskProperties(void*& OutData, uint32& OutSize);
(......)
// RHI 리소스 정보.
FRHIResourceInfo ResourceInfo;
private:
// 텍스처 데이터.
FClearValueBinding ClearValue;
uint32 NumMips;
uint32 NumSamples;
EPixelFormat Format;
uint32 Flags;
FLastRenderTimeContainer& LastRenderTime;
FLastRenderTimeContainer DefaultLastRenderTime;
FName TextureName;
};
// 2D RHI 계산.
class FRHITexture2D : public FRHITexture
{
public:
FRHITexture2D(uint32 InSizeX,uint32 InSizeY,uint32 InNumMips,uint32 InNumSamples,EPixelFormat InFormat,uint32 InFlags, const FClearValueBinding& InClearValue);
virtual FRHITexture2D* GetTexture2D() { return this; }
uint32 GetSizeX() const { return SizeX; }
uint32 GetSizeY() const { return SizeY; }
inline FIntPoint GetSizeXY() const;
virtual FIntVector GetSizeXYZ() const override;
private:
uint32 SizeX;
uint32 SizeY;
};
// 2D RHI 텍스처 어레이.
class FRHITexture2DArray : public FRHITexture2D
{
public:
FRHITexture2DArray(uint32 InSizeX,uint32 InSizeY,uint32 InSizeZ,uint32 InNumMips,uint32 NumSamples, EPixelFormat InFormat,uint32 InFlags, const FClearValueBinding& InClearValue);
virtual FRHITexture2DArray* GetTexture2DArray() { return this; }
virtual FRHITexture2D* GetTexture2D() { return NULL; }
uint32 GetSizeZ() const { return SizeZ; }
virtual FIntVector GetSizeXYZ() const final override;
private:
uint32 SizeZ;
};
// 2D RHI 계산.
class FRHITexture3D : public FRHITexture
{
public:
FRHITexture3D(uint32 InSizeX,uint32 InSizeY,uint32 InSizeZ,uint32 InNumMips,EPixelFormat InFormat,uint32 InFlags, const FClearValueBinding& InClearValue);
virtual FRHITexture3D* GetTexture3D() { return this; }
uint32 GetSizeX() const { return SizeX; }
uint32 GetSizeY() const { return SizeY; }
uint32 GetSizeZ() const { return SizeZ; }
virtual FIntVector GetSizeXYZ() const final override;
private:
uint32 SizeX;
uint32 SizeY;
uint32 SizeZ;
};
// 큐빅 RHI 텍스처
class FRHITextureCube : public FRHITexture
{
public:
FRHITextureCube(uint32 InSize,uint32 InNumMips,EPixelFormat InFormat,uint32 InFlags, const FClearValueBinding& InClearValue);
virtual FRHITextureCube* GetTextureCube();
uint32 GetSize() const;
virtual FIntVector GetSizeXYZ() const final override;
private:
uint32 Size;
};
// 텍스처 레퍼런스.
class FRHITextureReference : public FRHITexture
{
public:
explicit FRHITextureReference(FLastRenderTimeContainer* InLastRenderTime);
virtual FRHITextureReference* GetTextureReference() override { return this; }
inline FRHITexture* GetReferencedTexture() const;
// 레퍼런스 텍스처 설정
void SetReferencedTexture(FRHITexture* InTexture);
virtual FIntVector GetSizeXYZ() const final override;
private:
// 레퍼런스 텍스처 리소스입니다.
TRefCountPtr<FRHITexture> ReferencedTexture;
};
class FRHITextureReferenceNullImpl : public FRHITextureReference
{
public:
FRHITextureReferenceNullImpl();
void SetReferencedTexture(FRHITexture* InTexture)
{
FRHITextureReference::SetReferencedTexture(InTexture);
}
};
// 기타 리소스.
// 타임스탬프 보정 쿼리
class FRHITimestampCalibrationQuery : public FRHIResource
{
public:
uint64 GPUMicroseconds = 0;
uint64 CPUMicroseconds = 0;
};
// GPU 펜스 클래스. 즉, 명령 버퍼의 세분성만 나타낼 수도 있습니다. RHI를 위한 특수 펜스는
// 이로부터 파생되어 진정한 GPU->CPU 펜스를 가능하게 합니다.
// 기본 구현은 펜스의 다음 프레임이 삽입될 때까지 Poll에 대해 항상 거짓을 반환하는데,
// 이는 모든 API에 GPU/CPU 동기화 객체가 있고 이를 가짜로 만들어야 하는 것은 아니기 때문입니다.
class FRHIGPUFence : public FRHIResource
{
public:
FRHIGPUFence(FName InName) : FenceName(InName) {}
virtual ~FRHIGPUFence() {}
virtual void Clear() = 0;
// 펜스를 폴링하여 GPU가 신호를 보냈는지 확인합니다. 그렇다면 참을 반환합니다.
virtual bool Poll() const = 0;
// GPU의 하위 집합을 폴링합니다.
virtual bool Poll(FRHIGPUMask GPUMask) const { return Poll(); }
// 쓰기를 기다리는 명령의 수입니다.
FThreadSafeCounter NumPendingWriteCommands;
protected:
FName FenceName;
};
// 일반 FRHIGPUFence 구현.
class RHI_API FGenericRHIGPUFence : public FRHIGPUFence
{
public:
FGenericRHIGPUFence(FName InName);
virtual void Clear() final override;
virtual bool Poll() const final override;
void WriteInternal();
private:
uint32 InsertedFrameNumber;
};
// 쿼리 렌더링.
class FRHIRenderQuery : public FRHIResource
{
};
// 풀링된 렌더링 쿼리.
class RHI_API FRHIPooledRenderQuery
{
TRefCountPtr<FRHIRenderQuery> Query;
FRHIRenderQueryPool* QueryPool = nullptr;
public:
bool IsValid() const;
FRHIRenderQuery* GetQuery() const;
void ReleaseQuery();
(.....)
};
// 쿼리 풀을 렌더링합니다.
class FRHIRenderQueryPool : public FRHIResource
{
public:
virtual ~FRHIRenderQueryPool() {};
virtual FRHIPooledRenderQuery AllocateQuery() = 0;
private:
friend class FRHIPooledRenderQuery;
virtual void ReleaseQuery(TRefCountPtr<FRHIRenderQuery>&& Query) = 0;
};
// 펜스를 계산합니다.
class FRHIComputeFence : public FRHIResource
{
public:
FRHIComputeFence(FName InName);
FORCEINLINE bool GetWriteEnqueued() const;
virtual void Reset();
virtual void WriteFence();
private:
// 태그가 생성된 이후 작성되었는지 여부를 표시합니다.
// 이 태그는 명령 생성 시 대기열이 CPU에서 GPU 중단을 가로체기 하기 위해 대기 중일 때 확인됩니다.
bool bWriteEnqueued;
};
// 뷰포트
class FRHIViewport : public FRHIResource
{
public:
// 플랫폼 관련 네이티브 교환 링크를 받으세요.
virtual void* GetNativeSwapChain() const { return nullptr; }
// 네이티브 백버퍼 텍스처를 가져옵니다.
virtual void* GetNativeBackBufferTexture() const { return nullptr; }
// 네이티브 백버퍼 렌더링 텍스처를 가져옵니다.
virtual void* GetNativeBackBufferRT() const { return nullptr; }
// 네이티브 창을 가져옵니다.
virtual void* GetNativeWindow(void** AddParam = nullptr) const { return nullptr; }
// 뷰포트에서 FRHICustomPresent 핸들러를 설정합니다.
virtual void SetCustomPresent(class FRHICustomPresent*) {}
virtual class FRHICustomPresent* GetCustomPresent() const { return nullptr; }
// 게임 스레드 프레임에서 뷰포트를 업데이트합니다.
virtual void Tick(float DeltaTime) {}
};
// UAV/SRV
class FRHIUnorderedAccessView : public FRHIResource {};
class FRHIShaderResourceView : public FRHIResource {};
// 다양한 RHI 리소스 참조 유형 정의.
typedef TRefCountPtr<FRHISamplerState> FSamplerStateRHIRef;
typedef TRefCountPtr<FRHIRasterizerState> FRasterizerStateRHIRef;
typedef TRefCountPtr<FRHIDepthStencilState> FDepthStencilStateRHIRef;
typedef TRefCountPtr<FRHIBlendState> FBlendStateRHIRef;
typedef TRefCountPtr<FRHIVertexDeclaration> FVertexDeclarationRHIRef;
typedef TRefCountPtr<FRHIVertexShader> FVertexShaderRHIRef;
typedef TRefCountPtr<FRHIHullShader> FHullShaderRHIRef;
typedef TRefCountPtr<FRHIDomainShader> FDomainShaderRHIRef;
typedef TRefCountPtr<FRHIPixelShader> FPixelShaderRHIRef;
typedef TRefCountPtr<FRHIGeometryShader> FGeometryShaderRHIRef;
typedef TRefCountPtr<FRHIComputeShader> FComputeShaderRHIRef;
typedef TRefCountPtr<FRHIRayTracingShader> FRayTracingShaderRHIRef;
typedef TRefCountPtr<FRHIComputeFence> FComputeFenceRHIRef;
typedef TRefCountPtr<FRHIBoundShaderState> FBoundShaderStateRHIRef;
typedef TRefCountPtr<FRHIUniformBuffer> FUniformBufferRHIRef;
typedef TRefCountPtr<FRHIIndexBuffer> FIndexBufferRHIRef;
typedef TRefCountPtr<FRHIVertexBuffer> FVertexBufferRHIRef;
typedef TRefCountPtr<FRHIStructuredBuffer> FStructuredBufferRHIRef;
typedef TRefCountPtr<FRHITexture> FTextureRHIRef;
typedef TRefCountPtr<FRHITexture2D> FTexture2DRHIRef;
typedef TRefCountPtr<FRHITexture2DArray> FTexture2DArrayRHIRef;
typedef TRefCountPtr<FRHITexture3D> FTexture3DRHIRef;
typedef TRefCountPtr<FRHITextureCube> FTextureCubeRHIRef;
typedef TRefCountPtr<FRHITextureReference> FTextureReferenceRHIRef;
typedef TRefCountPtr<FRHIRenderQuery> FRenderQueryRHIRef;
typedef TRefCountPtr<FRHIRenderQueryPool> FRenderQueryPoolRHIRef;
typedef TRefCountPtr<FRHITimestampCalibrationQuery> FTimestampCalibrationQueryRHIRef;
typedef TRefCountPtr<FRHIGPUFence> FGPUFenceRHIRef;
typedef TRefCountPtr<FRHIViewport> FViewportRHIRef;
typedef TRefCountPtr<FRHIUnorderedAccessView> FUnorderedAccessViewRHIRef;
typedef TRefCountPtr<FRHIShaderResourceView> FShaderResourceViewRHIRef;
typedef TRefCountPtr<FRHIGraphicsPipelineState> FGraphicsPipelineStateRHIRef;
typedef TRefCountPtr<FRHIRayTracingPipelineState> FRayTracingPipelineStateRHIRef;
// FRHIGPUMemoryReadback에서 사용하는 일반 세그먼트 버퍼 클래스입니다.
class FRHIStagingBuffer : public FRHIResource
{
public:
FRHIStagingBuffer();
virtual ~FRHIStagingBuffer();
virtual void *Lock(uint32 Offset, uint32 NumBytes) = 0;
virtual void Unlock() = 0;
protected:
bool bIsLocked;
};
class FGenericRHIStagingBuffer : public FRHIStagingBuffer
{
public:
FGenericRHIStagingBuffer();
~FGenericRHIStagingBuffer();
virtual void* Lock(uint32 Offset, uint32 NumBytes) final override;
virtual void Unlock() final override;
FVertexBufferRHIRef ShadowBuffer;
uint32 Offset;
};
// 맞춤형 프레젠테이션.
class FRHICustomPresent : public FRHIResource
{
public:
FRHICustomPresent() {}
virtual ~FRHICustomPresent() {}
// 뷰포트 크기가 변경될 때 호출됩니다.
virtual void OnBackBufferResize() = 0;
// 렌더 스레드에서 호출하여 네이티브 렌더링이 요청되는지 확인합니다.
virtual bool NeedsNativePresent() = 0;
// RHI 스레드 호출을 통해 커스텀 렌더링을 수행합니다.
virtual bool Present(int32& InOutSyncInterval) = 0;
// 현재 다음에 호출되는 RHI 스레드 호출.
virtual void PostPresent() {};
// 렌더링 스레드가 캡처될 때 호출됩니다.
virtual void OnAcquireThreadOwnership() {}
// 렌더링 스레드가 릴리스될 때 호출됩니다.
virtual void OnReleaseThreadOwnership() {}
};
위에서 볼 수 있듯이 FRHIResource에는 상태 블록, 셰이더 바인딩, 셰이더, 파이프라인 상태, 버퍼, 텍스처, 뷰 및 기타 기타 항목으로 분류할 수 있는 수많은 유형과 서브클래스가 있습니다.위는 플랫폼에 독립적인 기본 유형만 보여주며, 실제로 위의 유형은 다른 그래픽 API에서 상속된다는 점에 유의하세요.FRHIUniformBuffer를 예로 들면, 상속 체계는 다음과 같습니다:
위는 유니폼 버퍼에 대한 플랫폼 관련 리소스 및 연산 인터페이스를 구현하기 위해 D3D11, D3D12, OpenGL, 벌칸, 메탈 및 기타 그래픽 API에서 FRHIUniformBuffer의 서브클래스와 FEmptyUniformBuffer의 특수 널 구현을 보여줍니다.마찬가지로, 해당 플랫폼에서 렌더링을 지원하려면 특정 그래픽 API 또는 운영 체제 서브클래스에서 FRHIResource의 다른 직접 또는 간접 서브클래스를 구현해야 합니다.텍스처 리소스 클래스 상속 시스템의 가장 복잡한 UML 다이어그램은 아래와 같습니다:
위 다이어그램은 다양한 그래픽 API에 의해 서브클래싱되는 FRHITexture2D 외에도 다른 텍스처 유형
(예: FRHITexture2DArray, FRHITexture3D, FRHITextureCube 및 FRHITextureReference)이 다양한 플랫폼과 구현에서 상속될 수 있도록 단순화되었음을 참고하세요.구현에 상속됩니다.
10.2.3 FRHICommand
FRHICommand는 RHI 모듈을 위한 렌더링 명령의 베이스 클래스이며, 이러한 명령은 일반적으로 명령 큐를 통해 렌더링 스레드에 의해 RHI 스레드로 푸시되고 적절한 시점에 RHI 스레드에서 실행됩니다.FRHICommand는 또한 FRHICommandBase를 상속하며 그 정의는 다음과 같습니다:
// Engine\Source\Runtime\RHI\Public\RHICommandList.h
// RHI 명령 베이스 클래스.
struct FRHICommandBase
{
// 다음 명령. (명령 체인의 노드)
FRHICommandBase* Next = nullptr;
// 실행 후 폐기합니다.
virtual void ExecuteAndDestruct(FRHICommandListBase& CmdList, FRHICommandListDebugContext& DebugContext) = 0;
};
emplate<typename TCmd, typename NameType = FUnnamedRhiCommand>
struct FRHICommand : public FRHICommandBase
{
// 실행 후 폐기합니다.
void ExecuteAndDestruct(FRHICommandListBase& CmdList, FRHICommandListDebugContext& Context) override final
{
TCmd *ThisCmd = static_cast<TCmd*>(this);
ThisCmd->Execute(CmdList);
ThisCmd->~TCmd();
}
};
다음 노드를 가리키는 Next 변수가 있다는 점은 FRHICommandBase가 명령 체인 테이블의 노드라는 것을 의미합니다.FRHICommand에는 특수 매크로로 즉시 선언되는 많은 수의 서브 클래스가 있습니다:
// RHI 명령의 하위 클래스를 정의하는 매크로
#define FRHICOMMAND_MACRO(CommandName) \
struct PREPROCESSOR_JOIN(CommandName##String, __LINE__) \
{ \
static const TCHAR* TStr() { return TEXT(#CommandName); } \
}; \
// 명령은 FRHICommand를 상속받습니다.
struct CommandName final : public FRHICommand<CommandName, PREPROCESSOR_JOIN(CommandName##String, __LINE__)>
예를 들어 위의 매크로를 사용하면 FRHICommand의 하위 클래스(예: 특정 RHI 명령)를 빠르게 정의할 수 있습니다:
FRHICOMMAND_MACRO(FRHICommandSetStencilRef)
{
uint32 StencilRef;
FORCEINLINE_DEBUGGABLE FRHICommandSetStencilRef(uint32 InStencilRef)
: StencilRef(InStencilRef)
{
}
RHI_API void Execute(FRHICommandListBase& CmdList);
};
매크로 정의를 확장한 후 코드는 다음과 같습니다:
struct FRHICommandSetStencilRefString853
{
static const TCHAR* TStr() { return TEXT("FRHICommandSetStencilRef"); }
};
// FRHICommandSetStencilRef는 FRHICommand를 상속합니다.
struct FRHICommandSetStencilRef final : public FRHICommand<FRHICommandSetStencilRef, FRHICommandSetStencilRefString853>
{
uint32 StencilRef;
FRHICommandSetStencilRef(uint32 InStencilRef)
: StencilRef(InStencilRef)
{
}
RHI_API void Execute(FRHICommandListBase& CmdList);
};
FRHICOMMAND_MACRO 문을 사용하는 많은 RHI 명령이 있으며, 그 중 일부는 아래에 나열되어 있습니다:
FRHICOMMAND_MACRO(FRHISyncFrameCommand)
FRHICOMMAND_MACRO(FRHICommandStat)
FRHICOMMAND_MACRO(FRHICommandRHIThreadFence)
FRHICOMMAND_MACRO(FRHIAsyncComputeSubmitList)
FRHICOMMAND_MACRO(FRHICommandSubmitSubList)
FRHICOMMAND_MACRO(FRHICommandWaitForAndSubmitSubListParallel)
FRHICOMMAND_MACRO(FRHICommandWaitForAndSubmitSubList)
FRHICOMMAND_MACRO(FRHICommandWaitForAndSubmitRTSubList)
FRHICOMMAND_MACRO(FRHICommandWaitForTemporalEffect)
FRHICOMMAND_MACRO(FRHICommandWaitForTemporalEffect)
FRHICOMMAND_MACRO(FRHICommandBroadcastTemporalEffect)
FRHICOMMAND_MACRO(FRHICommandBeginUpdateMultiFrameResource)
FRHICOMMAND_MACRO(FRHICommandEndUpdateMultiFrameResource)
FRHICOMMAND_MACRO(FRHICommandBeginUpdateMultiFrameUAV)
FRHICOMMAND_MACRO(FRHICommandEndUpdateMultiFrameUAV)
FRHICOMMAND_MACRO(FRHICommandSetGPUMask)
FRHICOMMAND_MACRO(FRHICommandSetStencilRef)
FRHICOMMAND_MACRO(FRHICommandSetBlendFactor)
FRHICOMMAND_MACRO(FRHICommandSetStreamSource)
FRHICOMMAND_MACRO(FRHICommandSetStreamSource)
FRHICOMMAND_MACRO(FRHICommandSetViewport)
FRHICOMMAND_MACRO(FRHICommandSetScissorRect)
FRHICOMMAND_MACRO(FRHICommandBeginRenderPass)
FRHICOMMAND_MACRO(FRHICommandEndRenderPass)
FRHICOMMAND_MACRO(FRHICommandNextSubpass)
FRHICOMMAND_MACRO(FRHICommandBeginParallelRenderPass)
FRHICOMMAND_MACRO(FRHICommandEndParallelRenderPass)
FRHICOMMAND_MACRO(FRHICommandBeginRenderSubPass)
FRHICOMMAND_MACRO(FRHICommandEndRenderSubPass)
FRHICOMMAND_MACRO(FRHICommandDrawPrimitive)
FRHICOMMAND_MACRO(FRHICommandDrawIndexedPrimitive)
FRHICOMMAND_MACRO(FRHICommandDrawPrimitiveIndirect)
FRHICOMMAND_MACRO(FRHICommandDrawIndexedIndirect)
FRHICOMMAND_MACRO(FRHICommandDrawIndexedPrimitiveIndirect)
FRHICOMMAND_MACRO(FRHICommandSetGraphicsPipelineState)
FRHICOMMAND_MACRO(FRHICommandBeginUAVOverlap)
FRHICOMMAND_MACRO(FRHICommandEndUAVOverlap)
FRHICOMMAND_MACRO(FRHICommandSetDepthBounds)
FRHICOMMAND_MACRO(FRHICommandSetShadingRate)
FRHICOMMAND_MACRO(FRHICommandSetShadingRateImage)
FRHICOMMAND_MACRO(FRHICommandClearUAVFloat)
FRHICOMMAND_MACRO(FRHICommandCopyToResolveTarget)
FRHICOMMAND_MACRO(FRHICommandCopyTexture)
FRHICOMMAND_MACRO(FRHICommandBeginTransitions)
FRHICOMMAND_MACRO(FRHICommandEndTransitions)
FRHICOMMAND_MACRO(FRHICommandResourceTransition)
FRHICOMMAND_MACRO(FRHICommandClearColorTexture)
FRHICOMMAND_MACRO(FRHICommandClearDepthStencilTexture)
FRHICOMMAND_MACRO(FRHICommandClearColorTextures)
FRHICOMMAND_MACRO(FRHICommandSetGlobalUniformBuffers)
FRHICOMMAND_MACRO(FRHICommandBuildLocalUniformBuffer)
FRHICOMMAND_MACRO(FRHICommandBeginRenderQuery)
FRHICOMMAND_MACRO(FRHICommandEndRenderQuery)
FRHICOMMAND_MACRO(FRHICommandPollOcclusionQueries)
FRHICOMMAND_MACRO(FRHICommandBeginScene)
FRHICOMMAND_MACRO(FRHICommandEndScene)
FRHICOMMAND_MACRO(FRHICommandBeginFrame)
FRHICOMMAND_MACRO(FRHICommandEndFrame)
FRHICOMMAND_MACRO(FRHICommandBeginDrawingViewport)
FRHICOMMAND_MACRO(FRHICommandEndDrawingViewport)
FRHICOMMAND_MACRO(FRHICommandInvalidateCachedState)
FRHICOMMAND_MACRO(FRHICommandDiscardRenderTargets)
FRHICOMMAND_MACRO(FRHICommandUpdateTextureReference)
FRHICOMMAND_MACRO(FRHICommandUpdateRHIResources)
FRHICOMMAND_MACRO(FRHICommandBackBufferWaitTrackingBeginFrame)
FRHICOMMAND_MACRO(FRHICommandFlushTextureCacheBOP)
FRHICOMMAND_MACRO(FRHICommandCopyBufferRegion)
FRHICOMMAND_MACRO(FRHICommandCopyBufferRegions)
FRHICOMMAND_MACRO(FClearCachedRenderingDataCommand)
FRHICOMMAND_MACRO(FClearCachedElementDataCommand)
FRHICOMMAND_MACRO(FRHICommandRayTraceOcclusion)
FRHICOMMAND_MACRO(FRHICommandRayTraceIntersection)
FRHICOMMAND_MACRO(FRHICommandRayTraceDispatch)
FRHICOMMAND_MACRO(FRHICommandSetRayTracingBindings)
FRHICOMMAND_MACRO(FRHICommandClearRayTracingBindings)
FRHICommand의 서브 클래스에는 위에 FRHICOMMAND_MACRO로 선언된 것 외에도 다음과 같은 직접 파생 클래스가 있습니다:
- FRHICommandSetShaderParameter
- FRHICommandSetShaderUniformBuffer
- FRHICommandSetShaderTexture
- FRHICommandSetShaderResourceViewParameter
- FRHICommandSetUAVParameter
- FRHICommandSetShaderSampler
- FRHICommandSetComputeShader
- FRHICommandSetComputePipelineState
- FRHICommandDispatchComputeShader
- FRHICommandDispatchIndirectComputeShader
- FRHICommandSetAsyncComputeBudget
- FRHICommandCopyToStagingBuffer
- FRHICommandWriteGPUFence
- FRHICommandSetLocalUniformBuffer
- FRHICommandSubmitCommandsHint
- FRHICommandPushEvent
- FRHICommandPopEvent
- FRHICommandBuildAccelerationStructure
- FRHICommandBuildAccelerationStructures
- ......
직접 파생하든 FRHICOMMAND_MACRO를 사용하든 본질적인 차이는 없으며, 모두 FRHICommand의 서브클래스이고 렌더링 스레드에서 조작할 수 있는 RHI 계층의 중간 렌더링 명령어입니다.다만 FRHICOMMAND_MACRO가 더 쉽고 덜 반복적인 코드를 작성할 수 있을 뿐입니다.
따라서 RHI 명령에는 주로 다음 범주를 포함하여 많은 종류가 있음을 알 수 있습니다:
- 데이터와 리소스를 설정, 업데이트, 정리, 변환, 복사, 다시 읽기가 가능합니다.
- 요소 그리기.
- 패스, 서브패스, 씬, 뷰포트 등에 대한 이벤트 시작 및 종료
- 펜스, 대기 및 방송 인터페이스.
- 라이트 트레이싱.
- 슬레이트, 관련 명령 디버깅.
FRHICommand의 핵심 상속 시스템은 아래와 같습니다:
10.2.4 FRHICommandList
FRHICommandList는 FRHICommand 객체 집합을 관리하고 실행하기 위한 RHI의 명령 큐입니다.이 클래스와 그 부모 클래스는 아래에 정의되어 있습니다:
// Engine\Source\Runtime\RHI\Public\RHICommandList.h
// RHI命令列表基类.
class FRHICommandListBase : public FNoncopyable
{
public:
~FRHICommandListBase();
// 附带了循环利用的自定义new/delete操作.
void* operator new(size_t Size);
void operator delete(void *RawMemory);
// 刷新命令队列.
inline void Flush();
// 是否立即模式.
inline bool IsImmediate();
// 是否立即的异步计算.
inline bool IsImmediateAsyncCompute();
// 获取已占用的内存.
const int32 GetUsedMemory() const;
// 入队异步命令队列的提交.
void QueueAsyncCommandListSubmit(FGraphEventRef& AnyThreadCompletionEvent, class FRHICommandList* CmdList);
// 入队并行的异步命令队列的提交.
void QueueParallelAsyncCommandListSubmit(FGraphEventRef* AnyThreadCompletionEvents, bool bIsPrepass, class FRHICommandList** CmdLists, int32* NumDrawsIfKnown, int32 Num, int32 MinDrawsPerTranslate, bool bSpewMerge);
// 入队渲染线程命令队列的提交.
void QueueRenderThreadCommandListSubmit(FGraphEventRef& RenderThreadCompletionEvent, class FRHICommandList* CmdList);
// 入队命令队列的提交.
void QueueCommandListSubmit(class FRHICommandList* CmdList);
// 增加派发前序任务.
void AddDispatchPrerequisite(const FGraphEventRef& Prereq);
// 等待接口.
void WaitForTasks(bool bKnownToBeComplete = false);
void WaitForDispatch();
void WaitForRHIThreadTasks();
void HandleRTThreadTaskCompletion(const FGraphEventRef& MyCompletionGraphEvent);
// 分配接口.
void* Alloc(int32 AllocSize, int32 Alignment);
template <typename T>
void* Alloc();
template <typename T>
const TArrayView<T> AllocArray(const TArrayView<T> InArray);
TCHAR* AllocString(const TCHAR* Name);
// 分配指令.
void* AllocCommand(int32 AllocSize, int32 Alignment);
template <typename TCmd>
void* AllocCommand();
bool HasCommands() const;
bool IsExecuting() const;
bool IsBottomOfPipe() const;
bool IsTopOfPipe() const;
bool IsGraphics() const;
bool IsAsyncCompute() const;
// RHI管线, ERHIPipeline::Graphics或ERHIPipeline::AsyncCompute.
ERHIPipeline GetPipeline() const;
// 是否忽略RHI线程而直接当同步执行.
bool Bypass() const;
// 交换命令队列.
void ExchangeCmdList(FRHICommandListBase& Other);
// 设置Context.
void SetContext(IRHICommandContext* InContext);
IRHICommandContext& GetContext();
void SetComputeContext(IRHIComputeContext* InComputeContext);
IRHIComputeContext& GetComputeContext();
void CopyContext(FRHICommandListBase& ParentCommandList);
void MaybeDispatchToRHIThread();
void MaybeDispatchToRHIThreadInner();
(......)
private:
// 命令链表的头.
FRHICommandBase* Root;
// 指向Root的指针.
FRHICommandBase** CommandLink;
bool bExecuting;
uint32 NumCommands;
uint32 UID;
// 设备上下文.
IRHICommandContext* Context;
// 计算上下文.
IRHIComputeContext* ComputeContext;
FMemStackBase MemManager;
FGraphEventArray RTTasks;
// 重置.
void Reset();
public:
enum class ERenderThreadContext
{
SceneRenderTargets,
Num
};
// 渲染线程上下文.
void *RenderThreadContexts[(int32)ERenderThreadContext::Num];
protected:
//the values of this struct must be copied when the commandlist is split
struct FPSOContext
{
uint32 CachedNumSimultanousRenderTargets = 0;
TStaticArray<FRHIRenderTargetView, MaxSimultaneousRenderTargets> CachedRenderTargets;
FRHIDepthRenderTargetView CachedDepthStencilTarget;
ESubpassHint SubpassHint = ESubpassHint::None;
uint8 SubpassIndex = 0;
uint8 MultiViewCount = 0;
bool HasFragmentDensityAttachment = false;
} PSOContext;
// 绑定的着色器输入.
FBoundShaderStateInput BoundShaderInput;
// 绑定的计算着色器RHI资源.
FRHIComputeShader* BoundComputeShaderRHI;
// 使绑定的着色器生效.
void ValidateBoundShader(FRHIVertexShader* ShaderRHI);
void ValidateBoundShader(FRHIPixelShader* ShaderRHI);
(......)
void CacheActiveRenderTargets(...);
void CacheActiveRenderTargets(const FRHIRenderPassInfo& Info);
void IncrementSubpass();
void ResetSubpass(ESubpassHint SubpassHint);
public:
void CopyRenderThreadContexts(const FRHICommandListBase& ParentCommandList);
void SetRenderThreadContext(void* InContext, ERenderThreadContext Slot);
void* GetRenderThreadContext(ERenderThreadContext Slot);
// 通用数据.
struct FCommonData
{
class FRHICommandListBase* Parent = nullptr;
enum class ECmdListType
{
Immediate = 1,
Regular,
};
ECmdListType Type = ECmdListType::Regular;
bool bInsideRenderPass = false;
bool bInsideComputePass = false;
};
bool DoValidation() const;
inline bool IsOutsideRenderPass() const;
inline bool IsInsideRenderPass() const;
inline bool IsInsideComputePass() const;
FCommonData Data;
};
// 计算命令队列.
class FRHIComputeCommandList : public FRHICommandListBase
{
public:
FRHIComputeCommandList(FRHIGPUMask GPUMask) : FRHICommandListBase(GPUMask) {}
void* operator new(size_t Size);
void operator delete(void *RawMemory);
// 着色器参数设置和获取.
inline FRHIComputeShader* GetBoundComputeShader() const;
void SetGlobalUniformBuffers(const FUniformBufferStaticBindings& UniformBuffers);
void SetShaderUniformBuffer(FRHIComputeShader* Shader, uint32 BaseIndex, FRHIUniformBuffer* UniformBuffer);
void SetShaderUniformBuffer(const FComputeShaderRHIRef& Shader, uint32 BaseIndex, FRHIUniformBuffer* UniformBuffer);
void SetShaderParameter(FRHIComputeShader* Shader, uint32 BufferIndex, uint32 BaseIndex, uint32 NumBytes, const void* NewValue);
void SetShaderParameter(FComputeShaderRHIRef& Shader, uint32 BufferIndex, uint32 BaseIndex, uint32 NumBytes, const void* NewValue);
void SetShaderTexture(FRHIComputeShader* Shader, uint32 TextureIndex, FRHITexture* Texture);
void SetShaderResourceViewParameter(FRHIComputeShader* Shader, uint32 SamplerIndex, FRHIShaderResourceView* SRV);
void SetShaderSampler(FRHIComputeShader* Shader, uint32 SamplerIndex, FRHISamplerState* State);
void SetUAVParameter(FRHIComputeShader* Shader, uint32 UAVIndex, FRHIUnorderedAccessView* UAV);
void SetUAVParameter(FRHIComputeShader* Shader, uint32 UAVIndex, FRHIUnorderedAccessView* UAV, uint32 InitialCount);
void SetComputeShader(FRHIComputeShader* ComputeShader);
void SetComputePipelineState(FComputePipelineState* ComputePipelineState, FRHIComputeShader* ComputeShader);
void SetAsyncComputeBudget(EAsyncComputeBudget Budget);
// 派发计算着色器.
void DispatchComputeShader(uint32 ThreadGroupCountX, uint32 ThreadGroupCountY, uint32 ThreadGroupCountZ);
void DispatchIndirectComputeShader(FRHIVertexBuffer* ArgumentBuffer, uint32 ArgumentOffset);
// 清理.
void ClearUAVFloat(FRHIUnorderedAccessView* UnorderedAccessViewRHI, const FVector4& Values);
void ClearUAVUint(FRHIUnorderedAccessView* UnorderedAccessViewRHI, const FUintVector4& Values);
// 资源转换.
void BeginTransitions(TArrayView<const FRHITransition*> Transitions);
void EndTransitions(TArrayView<const FRHITransition*> Transitions);
inline void Transition(TArrayView<const FRHITransitionInfo> Infos);
void BeginTransition(const FRHITransition* Transition);
void EndTransition(const FRHITransition* Transition);
void Transition(const FRHITransitionInfo& Info)
// ---- 旧有的API ----
void TransitionResource(ERHIAccess TransitionType, const FTextureRHIRef& InTexture);
void TransitionResource(ERHIAccess TransitionType, FRHITexture* InTexture);
inline void TransitionResources(ERHIAccess TransitionType, FRHITexture* const* InTextures, int32 NumTextures);
void TransitionResourceArrayNoCopy(ERHIAccess TransitionType, TArray<FRHITexture*>& InTextures);
inline void TransitionResources(ERHIAccess TransitionType, EResourceTransitionPipeline /* ignored TransitionPipeline */, FRHIUnorderedAccessView* const* InUAVs, int32 NumUAVs, FRHIComputeFence* WriteFence);
void TransitionResource(ERHIAccess TransitionType, EResourceTransitionPipeline TransitionPipeline, FRHIUnorderedAccessView* InUAV, FRHIComputeFence* WriteFence);
void TransitionResource(ERHIAccess TransitionType, EResourceTransitionPipeline TransitionPipeline, FRHIUnorderedAccessView* InUAV);
void TransitionResources(ERHIAccess TransitionType, EResourceTransitionPipeline TransitionPipeline, FRHIUnorderedAccessView* const* InUAVs, int32 NumUAVs);
void WaitComputeFence(FRHIComputeFence* WaitFence);
void BeginUAVOverlap();
void EndUAVOverlap();
void BeginUAVOverlap(FRHIUnorderedAccessView* UAV);
void EndUAVOverlap(FRHIUnorderedAccessView* UAV);
void BeginUAVOverlap(TArrayView<FRHIUnorderedAccessView* const> UAVs);
void EndUAVOverlap(TArrayView<FRHIUnorderedAccessView* const> UAVs);
void PushEvent(const TCHAR* Name, FColor Color);
void PopEvent();
void BreakPoint();
void SubmitCommandsHint();
void CopyToStagingBuffer(FRHIVertexBuffer* SourceBuffer, FRHIStagingBuffer* DestinationStagingBuffer, uint32 Offset, uint32 NumBytes);
void WriteGPUFence(FRHIGPUFence* Fence);
void SetGPUMask(FRHIGPUMask InGPUMask);
(......)
};
// RHI命令队列.
class FRHICommandList : public FRHIComputeCommandList
{
public:
FRHICommandList(FRHIGPUMask GPUMask) : FRHIComputeCommandList(GPUMask) {}
bool AsyncPSOCompileAllowed() const;
void* operator new(size_t Size);
void operator delete(void *RawMemory);
// 获取绑定的着色器.
inline FRHIVertexShader* GetBoundVertexShader() const;
inline FRHIHullShader* GetBoundHullShader() const;
inline FRHIDomainShader* GetBoundDomainShader() const;
inline FRHIPixelShader* GetBoundPixelShader() const;
inline FRHIGeometryShader* GetBoundGeometryShader() const;
// 更新多帧资源.
void BeginUpdateMultiFrameResource(FRHITexture* Texture);
void EndUpdateMultiFrameResource(FRHITexture* Texture);
void BeginUpdateMultiFrameResource(FRHIUnorderedAccessView* UAV);
void EndUpdateMultiFrameResource(FRHIUnorderedAccessView* UAV);
// Uniform Buffer接口.
FLocalUniformBuffer BuildLocalUniformBuffer(const void* Contents, uint32 ContentsSize, const FRHIUniformBufferLayout& Layout);
template <typename TRHIShader>
void SetLocalShaderUniformBuffer(TRHIShader* Shader, uint32 BaseIndex, const FLocalUniformBuffer& UniformBuffer);
template <typename TShaderRHI>
void SetLocalShaderUniformBuffer(const TRefCountPtr<TShaderRHI>& Shader, uint32 BaseIndex, const FLocalUniformBuffer& UniformBuffer);
void SetShaderUniformBuffer(FRHIGraphicsShader* Shader, uint32 BaseIndex, FRHIUniformBuffer* UniformBuffer);
template <typename TShaderRHI>
FORCEINLINE void SetShaderUniformBuffer(const TRefCountPtr<TShaderRHI>& Shader, uint32 BaseIndex, FRHIUniformBuffer* UniformBuffer);
// 着色器参数.
void SetShaderParameter(FRHIGraphicsShader* Shader, uint32 BufferIndex, uint32 BaseIndex, uint32 NumBytes, const void* NewValue);
template <typename TShaderRHI>
void SetShaderParameter(const TRefCountPtr<TShaderRHI>& Shader, uint32 BufferIndex, uint32 BaseIndex, uint32 NumBytes, const void* NewValue);
void SetShaderTexture(FRHIGraphicsShader* Shader, uint32 TextureIndex, FRHITexture* Texture);
template <typename TShaderRHI>
void SetShaderTexture(const TRefCountPtr<TShaderRHI>& Shader, uint32 TextureIndex, FRHITexture* Texture);
void SetShaderResourceViewParameter(FRHIGraphicsShader* Shader, uint32 SamplerIndex, FRHIShaderResourceView* SRV);
template <typename TShaderRHI>
void SetShaderResourceViewParameter(const TRefCountPtr<TShaderRHI>& Shader, uint32 SamplerIndex, FRHIShaderResourceView* SRV);
void SetShaderSampler(FRHIGraphicsShader* Shader, uint32 SamplerIndex, FRHISamplerState* State);
template <typename TShaderRHI>
void SetShaderSampler(const TRefCountPtr<TShaderRHI>& Shader, uint32 SamplerIndex, FRHISamplerState* State);
void SetUAVParameter(FRHIPixelShader* Shader, uint32 UAVIndex, FRHIUnorderedAccessView* UAV);
void SetUAVParameter(const TRefCountPtr<FRHIPixelShader>& Shader, uint32 UAVIndex, FRHIUnorderedAccessView* UAV);
void SetBlendFactor(const FLinearColor& BlendFactor = FLinearColor::White);
// 图元绘制.
void DrawPrimitive(uint32 BaseVertexIndex, uint32 NumPrimitives, uint32 NumInstances);
void DrawIndexedPrimitive(FRHIIndexBuffer* IndexBuffer, int32 BaseVertexIndex, uint32 FirstInstance, uint32 NumVertices, uint32 StartIndex, uint32 NumPrimitives, uint32 NumInstances);
void DrawPrimitiveIndirect(FRHIVertexBuffer* ArgumentBuffer, uint32 ArgumentOffset);
void DrawIndexedIndirect(FRHIIndexBuffer* IndexBufferRHI, FRHIStructuredBuffer* ArgumentsBufferRHI, uint32 DrawArgumentsIndex, uint32 NumInstances);
void DrawIndexedPrimitiveIndirect(FRHIIndexBuffer* IndexBuffer, FRHIVertexBuffer* ArgumentsBuffer, uint32 ArgumentOffset);
// 设置数据.
void SetStreamSource(uint32 StreamIndex, FRHIVertexBuffer* VertexBuffer, uint32 Offset);
void SetStencilRef(uint32 StencilRef);
void SetViewport(float MinX, float MinY, float MinZ, float MaxX, float MaxY, float MaxZ);
void SetStereoViewport(float LeftMinX, float RightMinX, float LeftMinY, float RightMinY, float MinZ, float LeftMaxX, float RightMaxX, float LeftMaxY, float RightMaxY, float MaxZ);
void SetScissorRect(bool bEnable, uint32 MinX, uint32 MinY, uint32 MaxX, uint32 MaxY);
void ApplyCachedRenderTargets(FGraphicsPipelineStateInitializer& GraphicsPSOInit);
void SetGraphicsPipelineState(class FGraphicsPipelineState* GraphicsPipelineState, const FBoundShaderStateInput& ShaderInput, bool bApplyAdditionalState);
void SetDepthBounds(float MinDepth, float MaxDepth);
void SetShadingRate(EVRSShadingRate ShadingRate, EVRSRateCombiner Combiner);
void SetShadingRateImage(FRHITexture* RateImageTexture, EVRSRateCombiner Combiner);
// 拷贝纹理.
void CopyToResolveTarget(FRHITexture* SourceTextureRHI, FRHITexture* DestTextureRHI, const FResolveParams& ResolveParams);
void CopyTexture(FRHITexture* SourceTextureRHI, FRHITexture* DestTextureRHI, const FRHICopyTextureInfo& CopyInfo);
void ResummarizeHTile(FRHITexture2D* DepthTexture);
// 渲染查询.
void BeginRenderQuery(FRHIRenderQuery* RenderQuery)
void EndRenderQuery(FRHIRenderQuery* RenderQuery)
void CalibrateTimers(FRHITimestampCalibrationQuery* CalibrationQuery);
void PollOcclusionQueries()
/* LEGACY API */
void TransitionResource(FExclusiveDepthStencil DepthStencilMode, FRHITexture* DepthTexture);
void BeginRenderPass(const FRHIRenderPassInfo& InInfo, const TCHAR* Name);
void EndRenderPass();
void NextSubpass();
// 下面接口需要在立即模式的命令队列调用.
void BeginScene();
void EndScene();
void BeginDrawingViewport(FRHIViewport* Viewport, FRHITexture* RenderTargetRHI);
void EndDrawingViewport(FRHIViewport* Viewport, bool bPresent, bool bLockToVsync);
void BeginFrame();
void EndFrame();
void RHIInvalidateCachedState();
void DiscardRenderTargets(bool Depth, bool Stencil, uint32 ColorBitMask);
void CopyBufferRegion(FRHIVertexBuffer* DestBuffer, uint64 DstOffset, FRHIVertexBuffer* SourceBuffer, uint64 SrcOffset, uint64 NumBytes);
(......)
};
FRHICommandListBase는 명령 대기열에 필요한 기본 데이터(명령 목록, 장치 컨텍스트) 및 인터페이스(명령의 새로 고침, 대기, 큐, 디스패치 등, 메모리 할당)를 정의하고, FRHIComputeCommandList는 컴퓨팅 셰이더, GPU 리소스 상태 전환 및 셰이더의 일부 매개 변수 설정에 관련된 인터페이스를 정의합니다.FRHICommandList는 VS, PS, GS 바인딩, 요소 그리기, 더 많은 셰이더 파라미터 설정 및 리소스 상태 전환, 리소스 생성, 업데이트 및 대기 등 일반적인 렌더링 파이프라인에 대한 인터페이스를 정의합니다.
또한 다음과 같이 정의된 여러 서브클래스가 있습니다:
// 立即模式的命令队列.
class FRHICommandListImmediate : public FRHICommandList
{
// 命令匿名函数.
template <typename LAMBDA>
struct TRHILambdaCommand final : public FRHICommandBase
{
LAMBDA Lambda;
void ExecuteAndDestruct(FRHICommandListBase& CmdList, FRHICommandListDebugContext&) override final;
};
FRHICommandListImmediate();
~FRHICommandListImmediate();
public:
// 立即刷新命令.
void ImmediateFlush(EImmediateFlushType::Type FlushType);
// 阻塞RHI线程.
bool StallRHIThread();
// 取消阻塞RHI线程.
void UnStallRHIThread();
// 是否阻塞中.
static bool IsStalled();
void SetCurrentStat(TStatId Stat);
static FGraphEventRef RenderThreadTaskFence();
static FGraphEventArray& GetRenderThreadTaskArray();
static void WaitOnRenderThreadTaskFence(FGraphEventRef& Fence);
static bool AnyRenderThreadTasksOutstanding();
FGraphEventRef RHIThreadFence(bool bSetLockFence = false);
// 将给定的异步计算命令列表按当前立即命令列表的顺序排列.
void QueueAsyncCompute(FRHIComputeCommandList& RHIComputeCmdList);
bool IsBottomOfPipe();
bool IsTopOfPipe();
template <typename LAMBDA>
void EnqueueLambda(LAMBDA&& Lambda);
// 资源创建.
FSamplerStateRHIRef CreateSamplerState(const FSamplerStateInitializerRHI& Initializer)
FRasterizerStateRHIRef CreateRasterizerState(const FRasterizerStateInitializerRHI& Initializer)
FDepthStencilStateRHIRef CreateDepthStencilState(const FDepthStencilStateInitializerRHI& Initializer)
FBlendStateRHIRef CreateBlendState(const FBlendStateInitializerRHI& Initializer)
FPixelShaderRHIRef CreatePixelShader(TArrayView<const uint8> Code, const FSHAHash& Hash)
FVertexShaderRHIRef CreateVertexShader(TArrayView<const uint8> Code, const FSHAHash& Hash)
FHullShaderRHIRef CreateHullShader(TArrayView<const uint8> Code, const FSHAHash& Hash)
FDomainShaderRHIRef CreateDomainShader(TArrayView<const uint8> Code, const FSHAHash& Hash)
FGeometryShaderRHIRef CreateGeometryShader(TArrayView<const uint8> Code, const FSHAHash& Hash)
FComputeShaderRHIRef CreateComputeShader(TArrayView<const uint8> Code, const FSHAHash& Hash)
FComputeFenceRHIRef CreateComputeFence(const FName& Name)
FGPUFenceRHIRef CreateGPUFence(const FName& Name)
FStagingBufferRHIRef CreateStagingBuffer()
FBoundShaderStateRHIRef CreateBoundShaderState(...)
FGraphicsPipelineStateRHIRef CreateGraphicsPipelineState(const FGraphicsPipelineStateInitializer& Initializer)
TRefCountPtr<FRHIComputePipelineState> CreateComputePipelineState(FRHIComputeShader* ComputeShader)
FUniformBufferRHIRef CreateUniformBuffer(...)
FIndexBufferRHIRef CreateAndLockIndexBuffer(uint32 Stride, uint32 Size, EBufferUsageFlags InUsage, ERHIAccess InResourceState, FRHIResourceCreateInfo& CreateInfo, void*& OutDataBuffer)
FIndexBufferRHIRef CreateAndLockIndexBuffer(uint32 Stride, uint32 Size, uint32 InUsage, FRHIResourceCreateInfo& CreateInfo, void*& OutDataBuffer)
// 顶点/索引接口.
void* LockIndexBuffer(FRHIIndexBuffer* IndexBuffer, uint32 Offset, uint32 SizeRHI, EResourceLockMode LockMode);
void UnlockIndexBuffer(FRHIIndexBuffer* IndexBuffer);
void* LockStagingBuffer(FRHIStagingBuffer* StagingBuffer, FRHIGPUFence* Fence, uint32 Offset, uint32 SizeRHI);
void UnlockStagingBuffer(FRHIStagingBuffer* StagingBuffer);
FVertexBufferRHIRef CreateAndLockVertexBuffer(uint32 Size, EBufferUsageFlags InUsage, ...);
FVertexBufferRHIRef CreateAndLockVertexBuffer(uint32 Size, uint32 InUsage, FRHIResourceCreateInfo& CreateInfo, void*& OutDataBuffer);
void* LockVertexBuffer(FRHIVertexBuffer* VertexBuffer, uint32 Offset, uint32 SizeRHI, EResourceLockMode LockMode);
void UnlockVertexBuffer(FRHIVertexBuffer* VertexBuffer);
void CopyVertexBuffer(FRHIVertexBuffer* SourceBuffer, FRHIVertexBuffer* DestBuffer);
void* LockStructuredBuffer(FRHIStructuredBuffer* StructuredBuffer, uint32 Offset, uint32 SizeRHI, EResourceLockMode LockMode);
void UnlockStructuredBuffer(FRHIStructuredBuffer* StructuredBuffer);
// UAV/SRV创建.
FUnorderedAccessViewRHIRef CreateUnorderedAccessView(FRHIStructuredBuffer* StructuredBuffer, bool bUseUAVCounter, bool bAppendBuffer)
FUnorderedAccessViewRHIRef CreateUnorderedAccessView(FRHITexture* Texture, uint32 MipLevel)
FUnorderedAccessViewRHIRef CreateUnorderedAccessView(FRHITexture* Texture, uint32 MipLevel, uint8 Format)
FUnorderedAccessViewRHIRef CreateUnorderedAccessView(FRHIVertexBuffer* VertexBuffer, uint8 Format)
FUnorderedAccessViewRHIRef CreateUnorderedAccessView(FRHIIndexBuffer* IndexBuffer, uint8 Format)
FShaderResourceViewRHIRef CreateShaderResourceView(FRHIStructuredBuffer* StructuredBuffer)
FShaderResourceViewRHIRef CreateShaderResourceView(FRHIVertexBuffer* VertexBuffer, uint32 Stride, uint8 Format)
FShaderResourceViewRHIRef CreateShaderResourceView(const FShaderResourceViewInitializer& Initializer)
FShaderResourceViewRHIRef CreateShaderResourceView(FRHIIndexBuffer* Buffer)
uint64 CalcTexture2DPlatformSize(...);
uint64 CalcTexture3DPlatformSize(...);
uint64 CalcTextureCubePlatformSize(...);
// 纹理操作.
void GetTextureMemoryStats(FTextureMemoryStats& OutStats);
bool GetTextureMemoryVisualizeData(...);
void CopySharedMips(FRHITexture2D* DestTexture2D, FRHITexture2D* SrcTexture2D);
void TransferTexture(FRHITexture2D* Texture, FIntRect Rect, uint32 SrcGPUIndex, uint32 DestGPUIndex, bool PullData);
void TransferTextures(const TArrayView<const FTransferTextureParams> Params);
void GetResourceInfo(FRHITexture* Ref, FRHIResourceInfo& OutInfo);
FShaderResourceViewRHIRef CreateShaderResourceView(FRHITexture* Texture, const FRHITextureSRVCreateInfo& CreateInfo);
FShaderResourceViewRHIRef CreateShaderResourceView(FRHITexture* Texture, uint8 MipLevel);
FShaderResourceViewRHIRef CreateShaderResourceView(FRHITexture* Texture, uint8 MipLevel, uint8 NumMipLevels, uint8 Format);
FShaderResourceViewRHIRef CreateShaderResourceViewWriteMask(FRHITexture2D* Texture2DRHI);
FShaderResourceViewRHIRef CreateShaderResourceViewFMask(FRHITexture2D* Texture2DRHI);
uint32 ComputeMemorySize(FRHITexture* TextureRHI);
FTexture2DRHIRef AsyncReallocateTexture2D(...);
ETextureReallocationStatus FinalizeAsyncReallocateTexture2D(FRHITexture2D* Texture2D, bool bBlockUntilCompleted);
ETextureReallocationStatus CancelAsyncReallocateTexture2D(FRHITexture2D* Texture2D, bool bBlockUntilCompleted);
void* LockTexture2D(...);
void UnlockTexture2D(FRHITexture2D* Texture, uint32 MipIndex, bool bLockWithinMiptail, bool bFlushRHIThread = true);
void* LockTexture2DArray(...);
void UnlockTexture2DArray(FRHITexture2DArray* Texture, uint32 TextureIndex, uint32 MipIndex, bool bLockWithinMiptail);
void UpdateTexture2D(...);
void UpdateFromBufferTexture2D(...);
FUpdateTexture3DData BeginUpdateTexture3D(...);
void EndUpdateTexture3D(FUpdateTexture3DData& UpdateData);
void EndMultiUpdateTexture3D(TArray<FUpdateTexture3DData>& UpdateDataArray);
void UpdateTexture3D(...);
void* LockTextureCubeFace(...);
void UnlockTextureCubeFace(FRHITextureCube* Texture, ...);
// 读取纹理表面数据.
void ReadSurfaceData(FRHITexture* Texture, ...);
void ReadSurfaceData(FRHITexture* Texture, ...);
void MapStagingSurface(FRHITexture* Texture, void*& OutData, int32& OutWidth, int32& OutHeight);
void MapStagingSurface(FRHITexture* Texture, ...);
void UnmapStagingSurface(FRHITexture* Texture);
void ReadSurfaceFloatData(FRHITexture* Texture, ...);
void ReadSurfaceFloatData(FRHITexture* Texture, ...);
void Read3DSurfaceFloatData(FRHITexture* Texture,...);
// 渲染线程的资源状态转换.
void AcquireTransientResource_RenderThread(FRHITexture* Texture);
void DiscardTransientResource_RenderThread(FRHITexture* Texture);
void AcquireTransientResource_RenderThread(FRHIVertexBuffer* Buffer);
void DiscardTransientResource_RenderThread(FRHIVertexBuffer* Buffer);
void AcquireTransientResource_RenderThread(FRHIStructuredBuffer* Buffer);
void DiscardTransientResource_RenderThread(FRHIStructuredBuffer* Buffer);
// 获取渲染查询结果.
bool GetRenderQueryResult(FRHIRenderQuery* RenderQuery, ...);
void PollRenderQueryResults();
// 视口
FViewportRHIRef CreateViewport(void* WindowHandle, ...);
uint32 GetViewportNextPresentGPUIndex(FRHIViewport* Viewport);
FTexture2DRHIRef GetViewportBackBuffer(FRHIViewport* Viewport);
void AdvanceFrameForGetViewportBackBuffer(FRHIViewport* Viewport);
void ResizeViewport(FRHIViewport* Viewport, ...);
void AcquireThreadOwnership();
void ReleaseThreadOwnership();
// 提交命令并刷新到GPU.
void SubmitCommandsAndFlushGPU();
// 执行命令队列.
void ExecuteCommandList(FRHICommandList* CmdList);
// 更新资源.
void UpdateTextureReference(FRHITextureReference* TextureRef, FRHITexture* NewTexture);
void UpdateRHIResources(FRHIResourceUpdateInfo* UpdateInfos, int32 Num, bool bNeedReleaseRefs);
// 刷新资源.
void FlushResources();
// 帧更新.
void Tick(float DeltaTime);
// 阻塞直到GPU空闲.
void BlockUntilGPUIdle();
// 暂停/开启渲染.
void SuspendRendering();
void ResumeRendering();
bool IsRenderingSuspended();
// 压缩/解压数据.
bool EnqueueDecompress(uint8_t* SrcBuffer, uint8_t* DestBuffer, int CompressedSize, void* ErrorCodeBuffer);
bool EnqueueCompress(uint8_t* SrcBuffer, uint8_t* DestBuffer, int UnCompressedSize, void* ErrorCodeBuffer);
// 其它接口.
bool GetAvailableResolutions(FScreenResolutionArray& Resolutions, bool bIgnoreRefreshRate);
void GetSupportedResolution(uint32& Width, uint32& Height);
void VirtualTextureSetFirstMipInMemory(FRHITexture2D* Texture, uint32 FirstMip);
void VirtualTextureSetFirstMipVisible(FRHITexture2D* Texture, uint32 FirstMip);
// 获取原生的数据.
void* GetNativeDevice();
void* GetNativeInstance();
// 获取立即模式的命令上下文.
IRHICommandContext* GetDefaultContext();
// 获取命令上下文容器.
IRHICommandContextContainer* GetCommandContextContainer(int32 Index, int32 Num);
uint32 GetGPUFrameCycles();
};
// 在RHI实现中标记命令列表的递归使用的类型定义.
class FRHICommandList_RecursiveHazardous : public FRHICommandList
{
public:
FRHICommandList_RecursiveHazardous(IRHICommandContext *Context, FRHIGPUMask InGPUMask = FRHIGPUMask::All());
};
// RHI内部使用的工具类,以更安全地使用FRHICommandList_RecursiveHazardous
template <typename ContextType>
class TRHICommandList_RecursiveHazardous : public FRHICommandList_RecursiveHazardous
{
template <typename LAMBDA>
struct TRHILambdaCommand final : public FRHICommandBase
{
LAMBDA Lambda;
TRHILambdaCommand(LAMBDA&& InLambda);
void ExecuteAndDestruct(FRHICommandListBase& CmdList, FRHICommandListDebugContext&) override final;
};
public:
TRHICommandList_RecursiveHazardous(ContextType *Context, FRHIGPUMask GPUMask = FRHIGPUMask::All());
template <typename LAMBDA>
void RunOnContext(LAMBDA&& Lambda);
};
FRHICommandListImmediate는 UE 렌더링 아키텍처에서 널리 사용되는 인스턴트 모드 그래픽 API 인터페이스를 캡슐화합니다.또한 리소스 조작, 생성, 업데이트, 읽기 및 상태 전환 인터페이스를 정의하고 스레드 동기화 및 GPU 동기화를 위한 인터페이스도 추가합니다.
아래는 FRHICommandList 코어 상속 시스템을 요약한 UML 다이어그램입니다:
10.3 RHIContext, DynamicRHI
이 장에서는 RHI 컨텍스트, DynamicRHI의 개념, 유형 및 연관성에 대해 설명합니다.
10.3.1 IRHICommandContext
IRHICommandContext는 그래픽 API와 관련된 일련의 작업을 정의하는 RHI의 명령 컨텍스트 인터페이스 클래스입니다.이는 명령 목록을 병렬로 처리할 수 있는 플랫폼에서 별도의 객체입니다.이 객체와 관련 상속된 유형은 아래에 정의되어 있습니다:
// Engine\Source\Runtime\RHI\Public\RHIContext.h
// 能够执行计算工作的上下文。可以在gfx管道上执行异步或计算.
class IRHIComputeContext
{
public:
virtual ~IRHIComputeContext();
// 设置/派发计算着色器.
virtual void RHISetComputeShader(FRHIComputeShader* ComputeShader) = 0;
virtual void RHISetComputePipelineState(FRHIComputePipelineState* ComputePipelineState);
virtual void RHIDispatchComputeShader(uint32 ThreadGroupCountX, uint32 ThreadGroupCountY, uint32 ThreadGroupCountZ) = 0;
virtual void RHIDispatchIndirectComputeShader(FRHIVertexBuffer* ArgumentBuffer, uint32 ArgumentOffset) = 0;
virtual void RHISetAsyncComputeBudget(EAsyncComputeBudget Budget) {}
// 转换资源.
virtual void RHIBeginTransitions(TArrayView<const FRHITransition*> Transitions) = 0;
virtual void RHIEndTransitions(TArrayView<const FRHITransition*> Transitions) = 0;
// UAV
virtual void RHIClearUAVFloat(FRHIUnorderedAccessView* UnorderedAccessViewRHI, const FVector4& Values) = 0;
virtual void RHIClearUAVUint(FRHIUnorderedAccessView* UnorderedAccessViewRHI, const FUintVector4& Values) = 0;
virtual void RHIBeginUAVOverlap() {}
virtual void RHIEndUAVOverlap() {}
virtual void RHIBeginUAVOverlap(TArrayView<FRHIUnorderedAccessView* const> UAVs) {}
virtual void RHIEndUAVOverlap(TArrayView<FRHIUnorderedAccessView* const> UAVs) {}
// 着色器参数.
virtual void RHISetShaderTexture(FRHIComputeShader* PixelShader, uint32 TextureIndex, FRHITexture* NewTexture) = 0;
virtual void RHISetShaderSampler(FRHIComputeShader* ComputeShader, uint32 SamplerIndex, FRHISamplerState* NewState) = 0;
virtual void RHISetUAVParameter(FRHIComputeShader* ComputeShader, uint32 UAVIndex, FRHIUnorderedAccessView* UAV) = 0;
virtual void RHISetUAVParameter(FRHIComputeShader* ComputeShader, uint32 UAVIndex, FRHIUnorderedAccessView* UAV, uint32 InitialCount) = 0;
virtual void RHISetShaderResourceViewParameter(FRHIComputeShader* ComputeShader, uint32 SamplerIndex, FRHIShaderResourceView* SRV) = 0;
virtual void RHISetShaderUniformBuffer(FRHIComputeShader* ComputeShader, uint32 BufferIndex, FRHIUniformBuffer* Buffer) = 0;
virtual void RHISetShaderParameter(FRHIComputeShader* ComputeShader, uint32 BufferIndex, uint32 BaseIndex, uint32 NumBytes, const void* NewValue) = 0;
virtual void RHISetGlobalUniformBuffers(const FUniformBufferStaticBindings& InUniformBuffers);
// 压入/弹出事件.
virtual void RHIPushEvent(const TCHAR* Name, FColor Color) = 0;
virtual void RHIPopEvent() = 0;
// 其它接口.
virtual void RHISubmitCommandsHint() = 0;
virtual void RHIInvalidateCachedState() {}
virtual void RHICopyToStagingBuffer(FRHIVertexBuffer* SourceBufferRHI, FRHIStagingBuffer* DestinationStagingBufferRHI, uint32 InOffset, uint32 InNumBytes);
virtual void RHIWriteGPUFence(FRHIGPUFence* FenceRHI);
virtual void RHISetGPUMask(FRHIGPUMask GPUMask);
// 加速结构.
virtual void RHIBuildAccelerationStructure(FRHIRayTracingGeometry* Geometry);
virtual void RHIBuildAccelerationStructures(const TArrayView<const FAccelerationStructureBuildParams> Params);
virtual void RHIBuildAccelerationStructure(FRHIRayTracingScene* Scene);
// 获取计算上下文.
inline IRHIComputeContext& GetLowestLevelContext() { return *this; }
inline IRHIComputeContext& GetHighestLevelContext() { return *this; }
};
// 命令上下文.
class IRHICommandContext : public IRHIComputeContext
{
public:
virtual ~IRHICommandContext();
// 派发计算.
virtual void RHIDispatchComputeShader(uint32 ThreadGroupCountX, uint32 ThreadGroupCountY, uint32 ThreadGroupCountZ) = 0;
virtual void RHIDispatchIndirectComputeShader(FRHIVertexBuffer* ArgumentBuffer, uint32 ArgumentOffset) = 0;
// 渲染查询.
virtual void RHIBeginRenderQuery(FRHIRenderQuery* RenderQuery) = 0;
virtual void RHIEndRenderQuery(FRHIRenderQuery* RenderQuery) = 0;
virtual void RHIPollOcclusionQueries();
// 开启/结束接口.
virtual void RHIBeginDrawingViewport(FRHIViewport* Viewport, FRHITexture* RenderTargetRHI) = 0;
virtual void RHIEndDrawingViewport(FRHIViewport* Viewport, bool bPresent, bool bLockToVsync) = 0;
virtual void RHIBeginFrame() = 0;
virtual void RHIEndFrame() = 0;
virtual void RHIBeginScene() = 0;
virtual void RHIEndScene() = 0;
virtual void RHIBeginUpdateMultiFrameResource(FRHITexture* Texture);
virtual void RHIEndUpdateMultiFrameResource(FRHITexture* Texture);
virtual void RHIBeginUpdateMultiFrameResource(FRHIUnorderedAccessView* UAV);
virtual void RHIEndUpdateMultiFrameResource(FRHIUnorderedAccessView* UAV);
// 设置数据.
virtual void RHISetStreamSource(uint32 StreamIndex, FRHIVertexBuffer* VertexBuffer, uint32 Offset) = 0;
virtual void RHISetViewport(float MinX, float MinY, float MinZ, float MaxX, float MaxY, float MaxZ) = 0;
virtual void RHISetStereoViewport(...);
virtual void RHISetScissorRect(bool bEnable, uint32 MinX, uint32 MinY, uint32 MaxX, uint32 MaxY) = 0;
virtual void RHISetGraphicsPipelineState(FRHIGraphicsPipelineState* GraphicsState, bool bApplyAdditionalState) = 0;
// 设置着色器参数.
virtual void RHISetShaderTexture(FRHIGraphicsShader* Shader, uint32 TextureIndex, FRHITexture* NewTexture) = 0;
virtual void RHISetShaderTexture(FRHIComputeShader* PixelShader, uint32 TextureIndex, FRHITexture* NewTexture) = 0;
virtual void RHISetShaderSampler(FRHIComputeShader* ComputeShader, uint32 SamplerIndex, FRHISamplerState* NewState) = 0;
virtual void RHISetShaderSampler(FRHIGraphicsShader* Shader, uint32 SamplerIndex, FRHISamplerState* NewState) = 0;
virtual void RHISetUAVParameter(FRHIPixelShader* PixelShader, uint32 UAVIndex, FRHIUnorderedAccessView* UAV) = 0;
virtual void RHISetUAVParameter(FRHIComputeShader* ComputeShader, uint32 UAVIndex, FRHIUnorderedAccessView* UAV) = 0;
virtual void RHISetUAVParameter(FRHIComputeShader* ComputeShader, uint32 UAVIndex, FRHIUnorderedAccessView* UAV, uint32 InitialCount) = 0;
virtual void RHISetShaderResourceViewParameter(FRHIComputeShader* ComputeShader, uint32 SamplerIndex, FRHIShaderResourceView* SRV) = 0;
virtual void RHISetShaderResourceViewParameter(FRHIGraphicsShader* Shader, uint32 SamplerIndex, FRHIShaderResourceView* SRV) = 0;
virtual void RHISetShaderUniformBuffer(FRHIGraphicsShader* Shader, uint32 BufferIndex, FRHIUniformBuffer* Buffer) = 0;
virtual void RHISetShaderUniformBuffer(FRHIComputeShader* ComputeShader, uint32 BufferIndex, FRHIUniformBuffer* Buffer) = 0;
virtual void RHISetShaderParameter(FRHIGraphicsShader* Shader, uint32 BufferIndex, uint32 BaseIndex, uint32 NumBytes, const void* NewValue) = 0;
virtual void RHISetShaderParameter(FRHIComputeShader* ComputeShader, uint32 BufferIndex, uint32 BaseIndex, uint32 NumBytes, const void* NewValue) = 0;
virtual void RHISetStencilRef(uint32 StencilRef) {}
virtual void RHISetBlendFactor(const FLinearColor& BlendFactor) {}
// 绘制图元.
virtual void RHIDrawPrimitive(uint32 BaseVertexIndex, uint32 NumPrimitives, uint32 NumInstances) = 0;
virtual void RHIDrawPrimitiveIndirect(FRHIVertexBuffer* ArgumentBuffer, uint32 ArgumentOffset) = 0;
virtual void RHIDrawIndexedIndirect(FRHIIndexBuffer* IndexBufferRHI, FRHIStructuredBuffer* ArgumentsBufferRHI, int32 DrawArgumentsIndex, uint32 NumInstances) = 0;
virtual void RHIDrawIndexedPrimitive(FRHIIndexBuffer* IndexBuffer, int32 BaseVertexIndex, uint32 FirstInstance, uint32 NumVertices, uint32 StartIndex, uint32 NumPrimitives, uint32 NumInstances) = 0;
virtual void RHIDrawIndexedPrimitiveIndirect(FRHIIndexBuffer* IndexBuffer, FRHIVertexBuffer* ArgumentBuffer, uint32 ArgumentOffset) = 0;
// 其它接口
virtual void RHISetDepthBounds(float MinDepth, float MaxDepth) = 0;
virtual void RHISetShadingRate(EVRSShadingRate ShadingRate, EVRSRateCombiner Combiner);
virtual void RHISetShadingRateImage(FRHITexture* RateImageTexture, EVRSRateCombiner Combiner);
virtual void RHISetMultipleViewports(uint32 Count, const FViewportBounds* Data) = 0;
virtual void RHICopyToResolveTarget(FRHITexture* SourceTexture, FRHITexture* DestTexture, const FResolveParams& ResolveParams) = 0;
virtual void RHIResummarizeHTile(FRHITexture2D* DepthTexture);
virtual void RHICalibrateTimers();
virtual void RHICalibrateTimers(FRHITimestampCalibrationQuery* CalibrationQuery);
virtual void RHIDiscardRenderTargets(bool Depth, bool Stencil, uint32 ColorBitMask) {}
// 纹理
virtual void RHIUpdateTextureReference(FRHITextureReference* TextureRef, FRHITexture* NewTexture) = 0;
virtual void RHICopyTexture(FRHITexture* SourceTexture, FRHITexture* DestTexture, const FRHICopyTextureInfo& CopyInfo);
virtual void RHICopyBufferRegion(FRHIVertexBuffer* DestBuffer, ...);
// Pass相关.
virtual void RHIBeginRenderPass(const FRHIRenderPassInfo& InInfo, const TCHAR* InName) = 0;
virtual void RHIEndRenderPass() = 0;
virtual void RHINextSubpass();
// 光线追踪.
virtual void RHIClearRayTracingBindings(FRHIRayTracingScene* Scene);
virtual void RHIBuildAccelerationStructures(const TArrayView<const FAccelerationStructureBuildParams> Params);
virtual void RHIBuildAccelerationStructure(FRHIRayTracingGeometry* Geometry) final override;
virtual void RHIBuildAccelerationStructure(FRHIRayTracingScene* Scene);
virtual void RHIRayTraceOcclusion(FRHIRayTracingScene* Scene, ...);
virtual void RHIRayTraceIntersection(FRHIRayTracingScene* Scene, ...);
virtual void RHIRayTraceDispatch(FRHIRayTracingPipelineState* RayTracingPipelineState, ...);
virtual void RHISetRayTracingHitGroups(FRHIRayTracingScene* Scene, ...);
virtual void RHISetRayTracingHitGroup(FRHIRayTracingScene* Scene, ...);
virtual void RHISetRayTracingCallableShader(FRHIRayTracingScene* Scene, ...);
virtual void RHISetRayTracingMissShader(FRHIRayTracingScene* Scene, ...);
(......)
protected:
// 渲染Pass信息.
FRHIRenderPassInfo RenderPassInfo;
};
위에서 볼 수 있듯이 IRHICommandContext와 FRHICommandList의 인터페이스는 매우 유사하고 겹치는 부분이 많습니다.IRHICommandContext에는 많은 서브클래스가 있습니다:
- IRHICommandContextPSOFallback: 실제 그래픽 파이프라인에 대한 RHI 명령 컨텍스트를 지원하지 않습니다.
- FNullDynamicRHI: Null로 구현된 동적 바인딩 RHI입니다.
- FOpenGLDynamicRHI: OpenGL용 동적 RHI.
- FD3D11DynamicRHI: D3D11용 동적 RHI.
- FMetalRHICommandContext: 메탈 플랫폼의 명령 컨텍스트입니다.
- FD3D12CommandContextBase: D3D12의 명령 컨텍스트입니다.
- FVulkanCommandListContext: 벌칸 플랫폼의 명령 대기열 컨텍스트입니다.
- FEmptyDynamicRHI: 동적으로 바인딩된 RHI로 구현된 인터페이스입니다.
- FValidationContext: 유효성 검사 컨텍스트입니다.
위의 서브 클래스 중 일부 플랫폼 관련 서브 클래스도 FDynamicRHI를 상속합니다. IRHICommandContextPSOFallback은 더 특별하며, 그 서브 클래스는 모두 병렬 그리기 (OpenGL, D3D11)를 지원하지 않는 그래픽 API입니다. IRHICommandContextPSOFallback은 다음과 같습니다. 정의는 다음과 같습니다:
class IRHICommandContextPSOFallback : public IRHICommandContext
{
public:
// 设置渲染状态.
virtual void RHISetBoundShaderState(FRHIBoundShaderState* BoundShaderState) = 0;
virtual void RHISetDepthStencilState(FRHIDepthStencilState* NewState, uint32 StencilRef) = 0;
virtual void RHISetRasterizerState(FRHIRasterizerState* NewState) = 0;
virtual void RHISetBlendState(FRHIBlendState* NewState, const FLinearColor& BlendFactor) = 0;
virtual void RHIEnableDepthBoundsTest(bool bEnable) = 0;
// 管线状态.
virtual void RHISetGraphicsPipelineState(FRHIGraphicsPipelineState* GraphicsState, bool bApplyAdditionalState) override;
};
IRHICommandContext의 핵심 상속 UML 다이어그램은 아래와 같습니다:
10.3.2 IRHICommandContextContainer
IRHICommandContextContainer는 다음과 같이 핵심 상속 하위 클래스로 정의되는 IRHICommandContext 객체를 포함하는 유형입니다:
// Engine\Source\Runtime\RHI\Public\RHICommandList.h
class IRHICommandContextContainer
{
public:
virtual ~IRHICommandContextContainer();
// 获取IRHICommandContext实例.
virtual IRHICommandContext* GetContext();
virtual void SubmitAndFreeContextContainer(int32 Index, int32 Num);
virtual void FinishContext();
};
// Engine\Source\Runtime\Apple\MetalRHI\Private\MetalContext.cpp
class FMetalCommandContextContainer : public IRHICommandContextContainer
{
// FMetalRHICommandContext列表的下一个.
FMetalRHICommandContext* CmdContext;
int32 Index;
int32 Num;
public:
void* operator new(size_t Size);
void operator delete(void *RawMemory);
FMetalCommandContextContainer(int32 InIndex, int32 InNum);
virtual ~FMetalCommandContextContainer() override final;
virtual IRHICommandContext* GetContext() override final;
virtual void FinishContext() override final;
// 提交并释放自己.
virtual void SubmitAndFreeContextContainer(int32 NewIndex, int32 NewNum) override final;
};
// FMetalCommandContextContainer分配器.
static TLockFreeFixedSizeAllocator<sizeof(FMetalCommandContextContainer), PLATFORM_CACHE_LINE_SIZE, FThreadSafeCounter> FMetalCommandContextContainerAllocator;
// Engine\Source\Runtime\D3D12RHI\Private\D3D12CommandContext.cpp
class FD3D12CommandContextContainer : public IRHICommandContextContainer
{
// 适配器.
FD3D12Adapter* Adapter;
// 命令上下文.
FD3D12CommandContext* CmdContext;
// 上下文重定向器.
FD3D12CommandContextRedirector* CmdContextRedirector;
FRHIGPUMask GPUMask;
// 命令队列列表.
TArray<FD3D12CommandListHandle> CommandLists;
public:
void* operator new(size_t Size);
void operator delete(void* RawMemory);
FD3D12CommandContextContainer(FD3D12Adapter* InAdapter, FRHIGPUMask InGPUMask);
virtual ~FD3D12CommandContextContainer() override
virtual IRHICommandContext* GetContext() override;
virtual void FinishContext() override;
virtual void SubmitAndFreeContextContainer(int32 Index, int32 Num) override;
};
// Engine\Source\Runtime\VulkanRHI\Private\VulkanContext.h
struct FVulkanCommandContextContainer : public IRHICommandContextContainer, public VulkanRHI::FDeviceChild
{
// 命令队列上下文.
FVulkanCommandListContext* CmdContext;
FVulkanCommandContextContainer(FVulkanDevice* InDevice);
virtual IRHICommandContext* GetContext() override final;
virtual void FinishContext() override final;
virtual void SubmitAndFreeContextContainer(int32 Index, int32 Num) override final;
void* operator new(size_t Size);
void operator delete(void* RawMemory);
};
IRHICommandContextContainer는 명령 대기열의 병렬화된 제출을 지원하기 위해 명령 컨텍스트 또는 명령 컨텍스트 집합을 저장하는 컨테이너에 해당하며, D3D12, Metal, Vulkan 등과 같은 최신 그래픽 API에서만 구현됩니다. 전체 상속 UML 다이어그램은 아래와 같습니다:
10.3.3 FDynamicRHI
FDynamicRHI는 동적으로 바인딩된 RHI에 의해 구현된 인터페이스로, CommandList 및 CommandContext와 더 유사한 인터페이스를 정의하며 부분적으로 다음과 같이 정의됩니다:
class RHI_API FDynamicRHI
{
public:
virtual ~FDynamicRHI() {}
virtual void Init() = 0;
virtual void PostInit() {}
virtual void Shutdown() = 0;
void InitPixelFormatInfo(const TArray<uint32>& PixelFormatBlockBytesIn);
// ---- RHI接口 ----
// 下列接口要求FlushType: Thread safe
virtual FSamplerStateRHIRef RHICreateSamplerState(const FSamplerStateInitializerRHI& Initializer) = 0;
virtual FRasterizerStateRHIRef RHICreateRasterizerState(const FRasterizerStateInitializerRHI& Initializer) = 0;
virtual FDepthStencilStateRHIRef RHICreateDepthStencilState(const FDepthStencilStateInitializerRHI& Initializer) = 0;
virtual FBlendStateRHIRef RHICreateBlendState(const FBlendStateInitializerRHI& Initializer) = 0;
// 下列接口要求FlushType: Wait RHI Thread
virtual FVertexDeclarationRHIRef RHICreateVertexDeclaration(const FVertexDeclarationElementList& Elements) = 0;
virtual FPixelShaderRHIRef RHICreatePixelShader(TArrayView<const uint8> Code, const FSHAHash& Hash) = 0;
virtual FVertexShaderRHIRef RHICreateVertexShader(TArrayView<const uint8> Code, const FSHAHash& Hash) = 0;
virtual FHullShaderRHIRef RHICreateHullShader(TArrayView<const uint8> Code, const FSHAHash& Hash) = 0;
virtual FDomainShaderRHIRef RHICreateDomainShader(TArrayView<const uint8> Code, const FSHAHash& Hash) = 0;
virtual FGeometryShaderRHIRef RHICreateGeometryShader(TArrayView<const uint8> Code, const FSHAHash& Hash) = 0;
virtual FComputeShaderRHIRef RHICreateComputeShader(TArrayView<const uint8> Code, const FSHAHash& Hash) = 0;
// FlushType: Must be Thread-Safe.
virtual FRenderQueryPoolRHIRef RHICreateRenderQueryPool(ERenderQueryType QueryType, uint32 NumQueries = UINT32_MAX);
inline FComputeFenceRHIRef RHICreateComputeFence(const FName& Name);
virtual FGPUFenceRHIRef RHICreateGPUFence(const FName &Name);
virtual void RHICreateTransition(FRHITransition* Transition, ERHIPipeline SrcPipelines, ERHIPipeline DstPipelines, ERHICreateTransitionFlags CreateFlags, TArrayView<const FRHITransitionInfo> Infos);
virtual void RHIReleaseTransition(FRHITransition* Transition);
// FlushType: Thread safe.
virtual FStagingBufferRHIRef RHICreateStagingBuffer();
virtual void* RHILockStagingBuffer(FRHIStagingBuffer* StagingBuffer, FRHIGPUFence* Fence, uint32 Offset, uint32 SizeRHI);
virtual void RHIUnlockStagingBuffer(FRHIStagingBuffer* StagingBuffer);
// FlushType: Thread safe, but varies depending on the RHI
virtual FBoundShaderStateRHIRef RHICreateBoundShaderState(FRHIVertexDeclaration* VertexDeclaration, FRHIVertexShader* VertexShader, FRHIHullShader* HullShader, FRHIDomainShader* DomainShader, FRHIPixelShader* PixelShader, FRHIGeometryShader* GeometryShader) = 0;
// FlushType: Thread safe
virtual FGraphicsPipelineStateRHIRef RHICreateGraphicsPipelineState(const FGraphicsPipelineStateInitializer& Initializer);
// FlushType: Thread safe, but varies depending on the RHI
virtual FUniformBufferRHIRef RHICreateUniformBuffer(const void* Contents, const FRHIUniformBufferLayout& Layout, EUniformBufferUsage Usage, EUniformBufferValidation Validation) = 0;
virtual void RHIUpdateUniformBuffer(FRHIUniformBuffer* UniformBufferRHI, const void* Contents) = 0;
// FlushType: Wait RHI Thread
virtual FIndexBufferRHIRef RHICreateIndexBuffer(uint32 Stride, uint32 Size, uint32 InUsage, ERHIAccess InResourceState, FRHIResourceCreateInfo& CreateInfo) = 0;
virtual void* RHILockIndexBuffer(FRHICommandListImmediate& RHICmdList, FRHIIndexBuffer* IndexBuffer, uint32 Offset, uint32 Size, EResourceLockMode LockMode);
virtual void RHIUnlockIndexBuffer(FRHICommandListImmediate& RHICmdList, FRHIIndexBuffer* IndexBuffer);
virtual void RHITransferIndexBufferUnderlyingResource(FRHIIndexBuffer* DestIndexBuffer, FRHIIndexBuffer* SrcIndexBuffer);
// FlushType: Wait RHI Thread
virtual FVertexBufferRHIRef RHICreateVertexBuffer(uint32 Size, uint32 InUsage, ERHIAccess InResourceState, FRHIResourceCreateInfo& CreateInfo) = 0;
// FlushType: Flush RHI Thread
virtual void* RHILockVertexBuffer(FRHICommandListImmediate& RHICmdList, FRHIVertexBuffer* VertexBuffer, uint32 Offset, uint32 SizeRHI, EResourceLockMode LockMode);
virtual void RHIUnlockVertexBuffer(FRHICommandListImmediate& RHICmdList, FRHIVertexBuffer* VertexBuffer);
// FlushType: Flush Immediate (seems dangerous)
virtual void RHICopyVertexBuffer(FRHIVertexBuffer* SourceBuffer, FRHIVertexBuffer* DestBuffer) = 0;
virtual void RHITransferVertexBufferUnderlyingResource(FRHIVertexBuffer* DestVertexBuffer, FRHIVertexBuffer* SrcVertexBuffer);
// FlushType: Wait RHI Thread
virtual FStructuredBufferRHIRef RHICreateStructuredBuffer(uint32 Stride, uint32 Size, uint32 InUsage, ERHIAccess InResourceState, FRHIResourceCreateInfo& CreateInfo) = 0;
// FlushType: Flush RHI Thread
virtual void* RHILockStructuredBuffer(FRHICommandListImmediate& RHICmdList, FRHIStructuredBuffer* StructuredBuffer, uint32 Offset, uint32 SizeRHI, EResourceLockMode LockMode);
virtual void RHIUnlockStructuredBuffer(FRHICommandListImmediate& RHICmdList, FRHIStructuredBuffer* StructuredBuffer);
// FlushType: Wait RHI Thread
virtual FUnorderedAccessViewRHIRef RHICreateUnorderedAccessView(FRHIStructuredBuffer* StructuredBuffer, bool bUseUAVCounter, bool bAppendBuffer) = 0;
// FlushType: Wait RHI Thread
virtual FUnorderedAccessViewRHIRef RHICreateUnorderedAccessView(FRHITexture* Texture, uint32 MipLevel) = 0;
// FlushType: Wait RHI Thread
virtual FUnorderedAccessViewRHIRef RHICreateUnorderedAccessView(FRHITexture* Texture, uint32 MipLevel, uint8 Format);
(......)
// RHI帧更新,须从主线程调用,FlushType: Thread safe
virtual void RHITick(float DeltaTime) = 0;
// 阻塞CPU直到GPU执行完成变成空闲. FlushType: Flush Immediate (seems wrong)
virtual void RHIBlockUntilGPUIdle() = 0;
// 开始当前帧,并确保GPU正在积极地工作 FlushType: Flush Immediate (copied from RHIBlockUntilGPUIdle)
virtual void RHISubmitCommandsAndFlushGPU() {};
// 通知RHI准备暂停它.
virtual void RHIBeginSuspendRendering() {};
// 暂停RHI渲染并将控制权交给系统的操作, FlushType: Thread safe
virtual void RHISuspendRendering() {};
// 继续RHI渲染, FlushType: Thread safe
virtual void RHIResumeRendering() {};
// FlushType: Flush Immediate
virtual bool RHIIsRenderingSuspended() { return false; };
// FlushType: called from render thread when RHI thread is flushed
// 仅在FRHIResource::FlushPendingDeletes内的延迟删除之前每帧调用.
virtual void RHIPerFrameRHIFlushComplete();
// 执行命令队列, FlushType: Wait RHI Thread
virtual void RHIExecuteCommandList(FRHICommandList* CmdList) = 0;
// FlushType: Flush RHI Thread
virtual void* RHIGetNativeDevice() = 0;
// FlushType: Flush RHI Thread
virtual void* RHIGetNativeInstance() = 0;
// 获取命令上下文. FlushType: Thread safe
virtual IRHICommandContext* RHIGetDefaultContext() = 0;
// 获取计算上下文. FlushType: Thread safe
virtual IRHIComputeContext* RHIGetDefaultAsyncComputeContext();
// FlushType: Thread safe
virtual class IRHICommandContextContainer* RHIGetCommandContextContainer(int32 Index, int32 Num) = 0;
// 直接由渲染线程调用的接口, 以优化RHI调用.
virtual FVertexBufferRHIRef CreateAndLockVertexBuffer_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 Size, uint32 InUsage, ERHIAccess InResourceState, FRHIResourceCreateInfo& CreateInfo, void*& OutDataBuffer);
virtual FIndexBufferRHIRef CreateAndLockIndexBuffer_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 Stride, uint32 Size, uint32 InUsage, ERHIAccess InResourceState, FRHIResourceCreateInfo& CreateInfo, void*& OutDataBuffer);
(......)
// Buffer Lock/Unlock
virtual void* LockVertexBuffer_BottomOfPipe(class FRHICommandListImmediate& RHICmdList, ...);
virtual void* LockIndexBuffer_BottomOfPipe(class FRHICommandListImmediate& RHICmdList, ...);
(......)
};
위에는 렌더링 스레드에서 호출해야 하는 인터페이스와 게임 스레드에서 호출해야 하는 인터페이스 중 일부만 표시되어 있습니다. 예를 들어 대부분의 인터페이스는 호출되기 전에 지정된 유형의 명령을 새로 고쳐야 합니다:
class RHI_API FDynamicRHI
{
// FlushType: Wait RHI Thread
void RHIExecuteCommandList(FRHICommandList* CmdList);
// FlushType: Flush Immediate
void RHIBlockUntilGPUIdle();
// FlushType: Thread safe
void RHITick(float DeltaTime);
};
위의 인터페이스를 호출하는 코드는 다음과 같습니다:
class RHI_API FRHICommandListImmediate : public FRHICommandList
{
void ExecuteCommandList(FRHICommandList* CmdList)
{
// 等待RHI线程.
FScopedRHIThreadStaller StallRHIThread(*this);
GDynamicRHI->RHIExecuteCommandList(CmdList);
}
void BlockUntilGPUIdle()
{
// 调用FDynamicRHI::RHIBlockUntilGPUIdle须刷新RHI.
ImmediateFlush(EImmediateFlushType::FlushRHIThread);
GDynamicRHI->RHIBlockUntilGPUIdle();
}
void Tick(float DeltaTime)
{
// 由于FDynamicRHI::RHITick是Thread Safe(线程安全), 所以不需要调用ImmediateFlush或等待事件.
GDynamicRHI->RHITick(DeltaTime);
}
};
FDynamicRHI의 서브클래스 정의로 넘어가겠습니다:
// Engine\Source\Runtime\Apple\MetalRHI\Private\MetalDynamicRHI.h
class FMetalDynamicRHI : public FDynamicRHI
{
public:
FMetalDynamicRHI(ERHIFeatureLevel::Type RequestedFeatureLevel);
~FMetalDynamicRHI();
// 필요한 내부 리소스 설정
void SetupRecursiveResources();
// FDynamicRHI interface.
virtual void Init();
virtual void Shutdown() {}
virtual const TCHAR* GetName() override { return TEXT("Metal"); }
virtual FSamplerStateRHIRef RHICreateSamplerState(const FSamplerStateInitializerRHI& Initializer) final override;
virtual FRasterizerStateRHIRef RHICreateRasterizerState(const FRasterizerStateInitializerRHI& Initializer) final override;
virtual FDepthStencilStateRHIRef RHICreateDepthStencilState(...) final override;
(......)
private:
// 즉시 모드 컨텍스트.
FMetalRHIImmediateCommandContext ImmediateContext;
// 비동기식 컴퓨팅 컨텍스트.
FMetalRHICommandContext* AsyncComputeContext;
// 버텍스 선언 캐시입니다.
TMap<uint32, FVertexDeclarationRHIRef> VertexDeclarationCache;
};
// Engine\Source\Runtime\D3D12RHI\Private\D3D12RHIPrivate.h
class FD3D12DynamicRHI : public FDynamicRHI
{
static FD3D12DynamicRHI* SingleD3DRHI;
public:
static D3D12RHI_API FD3D12DynamicRHI* GetD3DRHI() { return SingleD3DRHI; }
FD3D12DynamicRHI(const TArray<TSharedPtr<FD3D12Adapter>>& ChosenAdaptersIn, bool bInPixEventEnabled);
virtual ~FD3D12DynamicRHI();
// FDynamicRHI interface.
virtual void Init() override;
virtual void PostInit() override;
virtual void Shutdown() override;
virtual const TCHAR* GetName() override { return TEXT("D3D12"); }
virtual FSamplerStateRHIRef RHICreateSamplerState(const FSamplerStateInitializerRHI& Initializer) final override;
virtual FRasterizerStateRHIRef RHICreateRasterizerState(const FRasterizerStateInitializerRHI& Initializer) final override;
virtual FDepthStencilStateRHIRef RHICreateDepthStencilState(const FDepthStencilStateInitializerRHI& Initializer) final override;
(......)
protected:
// 선택한 어댑터.
TArray<TSharedPtr<FD3D12Adapter>> ChosenAdapters;
// AMD AGS 툴 라이브러리 컨텍스트.
AGSContext* AmdAgsContext;
// D3D12 장치.
inline FD3D12Device* GetRHIDevice(uint32 GPUIndex)
{
return GetAdapter().GetDevice(GPUIndex);
}
(......)
};
// Engine\Source\Runtime\EmptyRHI\Public\EmptyRHI.h
class FEmptyDynamicRHI : public FDynamicRHI, public IRHICommandContext
{
(......)
};
// Engine\Source\Runtime\NullDrv\Public\NullRHI.h
class FNullDynamicRHI : public FDynamicRHI , public IRHICommandContextPSOFallback
{
(......)
};
class OPENGLDRV_API FOpenGLDynamicRHI final : public FDynamicRHI, public IRHICommandContextPSOFallback
{
public:
FOpenGLDynamicRHI();
~FOpenGLDynamicRHI();
// FDynamicRHI interface.
virtual void Init();
virtual void PostInit();
virtual void Shutdown();
virtual const TCHAR* GetName() override { return TEXT("OpenGL"); }
virtual FRasterizerStateRHIRef RHICreateRasterizerState(const FRasterizerStateInitializerRHI& Initializer) final override;
virtual FDepthStencilStateRHIRef RHICreateDepthStencilState(const FDepthStencilStateInitializerRHI& Initializer) final override;
virtual FBlendStateRHIRef RHICreateBlendState(const FBlendStateInitializerRHI& Initializer) final override;
(......)
private:
// Counter.
uint32 SceneFrameCounter;
uint32 ResourceTableFrameCounter;
// 사용된 기본 OpenGL 컨텍스트와 무관한 RHI 장치 상태.
FOpenGLRHIState PendingState;
FOpenGLStreamedVertexBufferArray DynamicVertexBuffers;
FOpenGLStreamedIndexBufferArray DynamicIndexBuffers;
FSamplerStateRHIRef PointSamplerState;
// 뷰포트 생성.
TArray<FOpenGLViewport*> Viewports;
TRefCountPtr<FOpenGLViewport> DrawingViewport;
bool bRevertToSharedContextAfterDrawingViewport;
// 바운드 셰이더 상태 히스토리.
TGlobalResource< TBoundShaderStateHistory<10000> > BoundShaderStateHistory;
// 컨텍스트별 상태 캐싱.
FOpenGLContextState InvalidContextState;
FOpenGLContextState SharedContextState;
FOpenGLContextState RenderingContextState;
// 통합 버퍼.
TArray<FRHIUniformBuffer*> GlobalUniformBuffers;
TMap<GLuint, TPair<GLenum, GLenum>> TextureMipLimits;
// 기본 플랫폼과 관련된 데이터.
FPlatformOpenGLDevice* PlatformDevice;
// 관련 쿼리.
TArray<FOpenGLRenderQuery*> Queries;
FCriticalSection QueriesListCriticalSection;
// 데이터 구성 및 표시.
FOpenGLGPUProfiler GPUProfilingData;
FCriticalSection CustomPresentSection;
TRefCountPtr<class FRHICustomPresent> CustomPresent;
(......)
};
// Engine\Source\Runtime\RHI\Public\RHIValidation.h
class FValidationRHI : public FDynamicRHI
{
public:
RHI_API FValidationRHI(FDynamicRHI* InRHI);
RHI_API virtual ~FValidationRHI();
virtual FSamplerStateRHIRef RHICreateSamplerState(const FSamplerStateInitializerRHI& Initializer) override final;
virtual FRasterizerStateRHIRef RHICreateRasterizerState(const FRasterizerStateInitializerRHI& Initializer) override final;
virtual FDepthStencilStateRHIRef RHICreateDepthStencilState(const FDepthStencilStateInitializerRHI& Initializer) override final;
(......)
// RHI 예시.
FDynamicRHI* RHI;
// 해당 컨텍스트가 속한 컨텍스트.
TIndirectArray<IRHIComputeContext> OwnedContexts;
// 심층 템플릿 상태 목록.
TMap<FRHIDepthStencilState*, FDepthStencilStateInitializerRHI> DepthStencilStates;
};
// Engine\Source\Runtime\VulkanRHI\Public\VulkanDynamicRHI.h
class FVulkanDynamicRHI : public FDynamicRHI
{
public:
FVulkanDynamicRHI();
~FVulkanDynamicRHI();
// FDynamicRHI interface.
virtual void Init() final override;
virtual void PostInit() final override;
virtual void Shutdown() final override;;
virtual const TCHAR* GetName() final override { return TEXT("Vulkan"); }
void InitInstance();
virtual FSamplerStateRHIRef RHICreateSamplerState(const FSamplerStateInitializerRHI& Initializer) final override;
virtual FRasterizerStateRHIRef RHICreateRasterizerState(const FRasterizerStateInitializerRHI& Initializer) final override;
virtual FDepthStencilStateRHIRef RHICreateDepthStencilState(const FDepthStencilStateInitializerRHI& Initializer) final override;
(......)
protected:
// 예시.
VkInstance Instance;
TArray<const ANSICHAR*> InstanceExtensions;
TArray<const ANSICHAR*> InstanceLayers;
// 장치.
TArray<FVulkanDevice*> Devices;
FVulkanDevice* Device;
// 뷰포트.
TArray<FVulkanViewport*> Viewports;
TRefCountPtr<FVulkanViewport> DrawingViewport;
// 저장.
IConsoleObject* SavePipelineCacheCmd = nullptr;
IConsoleObject* RebuildPipelineCacheCmd = nullptr;
// 중요 영역.
FCriticalSection LockBufferCS;
// 내부 인터페이스.
void CreateInstance();
void SelectAndInitDevice();
void InitGPU(FVulkanDevice* Device);
void InitDevice(FVulkanDevice* Device);
(......)
};
// Engine\Source\Runtime\Windows\D3D11RHI\Private\D3D11RHIPrivate.h
class D3D11RHI_API FD3D11DynamicRHI : public FDynamicRHI, public IRHICommandContextPSOFallback
{
public:
FD3D11DynamicRHI(IDXGIFactory1* InDXGIFactory1,D3D_FEATURE_LEVEL InFeatureLevel,int32 InChosenAdapter, const DXGI_ADAPTER_DESC& ChosenDescription);
virtual ~FD3D11DynamicRHI();
virtual void InitD3DDevice();
// FDynamicRHI interface.
virtual void Init() override;
virtual void PostInit() override;
virtual void Shutdown() override;
virtual const TCHAR* GetName() override { return TEXT("D3D11"); }
// HDR display output
virtual void EnableHDR();
virtual void ShutdownHDR();
virtual FSamplerStateRHIRef RHICreateSamplerState(const FSamplerStateInitializerRHI& Initializer) final override;
virtual FRasterizerStateRHIRef RHICreateRasterizerState(const FRasterizerStateInitializerRHI& Initializer) final override;
virtual FDepthStencilStateRHIRef RHICreateDepthStencilState(const FDepthStencilStateInitializerRHI& Initializer) final override;
(......)
ID3D11Device* GetDevice() const
{
return Direct3DDevice;
}
FD3D11DeviceContext* GetDeviceContext() const
{
return Direct3DDeviceIMContext;
}
IDXGIFactory1* GetFactory() const
{
return DXGIFactory1;
}
protected:
// D3D 팩토리(인터페이스).
TRefCountPtr<IDXGIFactory1> DXGIFactory1;
// D3D 장치.
TRefCountPtr<FD3D11Device> Direct3DDevice;
// D3D 디바이스에 대한 즉각적인 컨텍스트.
TRefCountPtr<FD3D11DeviceContext> Direct3DDeviceIMContext;
// 스레드 잠금.
FD3D11LockTracker LockTracker;
FCriticalSection LockTrackerCS;
// 뷰포트.
TArray<FD3D11Viewport*> Viewports;
TRefCountPtr<FD3D11Viewport> DrawingViewport;
// AMD AGS 도구 라이브러리 컨텍스트.
AGSContext* AmdAgsContext;
// RT, UAV, 셰이더 및 기타 리소스.
TRefCountPtr<ID3D11RenderTargetView> CurrentRenderTargets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT];
TRefCountPtr<FD3D11UnorderedAccessView> CurrentUAVs[D3D11_PS_CS_UAV_REGISTER_COUNT];
ID3D11UnorderedAccessView* UAVBound[D3D11_PS_CS_UAV_REGISTER_COUNT];
TRefCountPtr<ID3D11DepthStencilView> CurrentDepthStencilTarget;
TRefCountPtr<FD3D11TextureBase> CurrentDepthTexture;
FD3D11BaseShaderResource* CurrentResourcesBoundAsSRVs[SF_NumStandardFrequencies][D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT];
FD3D11BaseShaderResource* CurrentResourcesBoundAsVBs[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
FD3D11BaseShaderResource* CurrentResourceBoundAsIB;
int32 MaxBoundShaderResourcesIndex[SF_NumStandardFrequencies];
FUniformBufferRHIRef BoundUniformBuffers[SF_NumStandardFrequencies][MAX_UNIFORM_BUFFERS_PER_SHADER_STAGE];
uint16 DirtyUniformBuffers[SF_NumStandardFrequencies];
TArray<FRHIUniformBuffer*> GlobalUniformBuffers;
// 생성된 상수 버퍼입니다.
TArray<TRefCountPtr<FD3D11ConstantBuffer> > VSConstantBuffers;
TArray<TRefCountPtr<FD3D11ConstantBuffer> > HSConstantBuffers;
TArray<TRefCountPtr<FD3D11ConstantBuffer> > DSConstantBuffers;
TArray<TRefCountPtr<FD3D11ConstantBuffer> > PSConstantBuffers;
TArray<TRefCountPtr<FD3D11ConstantBuffer> > GSConstantBuffers;
TArray<TRefCountPtr<FD3D11ConstantBuffer> > CSConstantBuffers;
// 바운드 셰이더 상태 히스토리.
TGlobalResource< TBoundShaderStateHistory<10000> > BoundShaderStateHistory;
FComputeShaderRHIRef CurrentComputeShader;
(......)
};
핵심 상속 UML 다이어그램은 아래와 같습니다:
기존 그래픽 API(D3D11, OpenGL)는 기존 및 최신 API 모두에서 PSO의 일관된 처리 동작을 보장하기 위해 후자의 인터페이스를 사용하여 PSO의 데이터와 동작을 처리해야 하므로 FDynamicRHI 외에도 IRHICommandContextPSOFallback을 상속해야 합니다. 이 때문에 최신 그래픽 API(D3D12, 벌칸, 메탈)는 IRHICommandContext에서 어떤 유형의 상속 시스템도 상속할 필요가 없으며, FDynamicRHI만 직접 상속하여 RHI 레이어의 모든 데이터와 연산을 처리할 수 있습니다.
최신 그래픽 API(D3D12, 벌칸, 메탈)의 DynamicRHI는 IRHICommandContext에서 어떤 유형의 상속 시스템도 상속하지 않기 때문에 FDynamicRHI::RHIGetDefaultContext 인터페이스는 어떻게 구현할까요? 다음은 FD3D12DynamicRHI 의 예제입니다:
IRHICommandContext* FD3D12DynamicRHI::RHIGetDefaultContext()
{
FD3D12Adapter& Adapter = GetAdapter();
IRHICommandContext* DefaultCommandContext = nullptr;
if (GNumExplicitGPUsForRendering > 1) // 멀티 GPU
{
DefaultCommandContext = static_cast<IRHICommandContext*>(&Adapter.GetDefaultContextRedirector());
}
else // 단일 CPU
{
FD3D12Device* Device = Adapter.GetDevice(0);
DefaultCommandContext = static_cast<IRHICommandContext*>(&Device->GetDefaultCommandContext());
}
return DefaultCommandContext;
}
싱글 및 멀티 GPU 모두 IRHICommandContext의 서브 서브클래스인 FD3D12CommandContext에서 변환해야 하므로 정적 유형 변환은 완벽하게 작동합니다.
10.3.3.1 FD3D11DynamicRHI
FD3D11DynamicRHI는 아래와 같이 정의된 여러 D3D11 플랫폼 관련 핵심 유형을 포함하거나 참조합니다:
// Engine\Source\Runtime\Windows\D3D11RHI\Private\D3D11RHIPrivate.h
class D3D11RHI_API FD3D11DynamicRHI : public FDynamicRHI, public IRHICommandContextPSOFallback
{
(......)
protected:
// D3D 팩토리(인터페이스).
TRefCountPtr<IDXGIFactory1> DXGIFactory1;
// D3D 장치
TRefCountPtr<FD3D11Device> Direct3DDevice;
// D3D设备的立即上下文.
TRefCountPtr<FD3D11DeviceContext> Direct3DDeviceIMContext;
// 뷰포트
TArray<FD3D11Viewport*> Viewports;
TRefCountPtr<FD3D11Viewport> DrawingViewport;
// AMD AGS 도구 라이브러리 컨텍스트.
AGSContext* AmdAgsContext;
(......)
};
// Engine\Source\Runtime\Windows\D3D11RHI\Private\Windows\D3D11RHIBasePrivate.h
typedef ID3D11DeviceContext FD3D11DeviceContext;
typedef ID3D11Device FD3D11Device;
// Engine\Source\Runtime\Windows\D3D11RHI\Public\D3D11Viewport.h
class FD3D11Viewport : public FRHIViewport
{
public:
FD3D11Viewport(class FD3D11DynamicRHI* InD3DRHI) : D3DRHI(InD3DRHI), PresentFailCount(0), ValidState (0), FrameSyncEvent(InD3DRHI);
FD3D11Viewport(class FD3D11DynamicRHI* InD3DRHI, HWND InWindowHandle, uint32 InSizeX, uint32 InSizeY, bool bInIsFullscreen, EPixelFormat InPreferredPixelFormat);
~FD3D11Viewport();
virtual void Resize(uint32 InSizeX, uint32 InSizeY, bool bInIsFullscreen, EPixelFormat PreferredPixelFormat);
void ConditionalResetSwapChain(bool bIgnoreFocus);
void CheckHDRMonitorStatus();
// 교환 체인의 프레젠테이션.
bool Present(bool bLockToVsync);
// Accessors.
FIntPoint GetSizeXY() const;
FD3D11Texture2D* GetBackBuffer() const;
EColorSpaceAndEOTF GetPixelColorSpace() const;
void WaitForFrameEventCompletion();
void IssueFrameEvent()
IDXGISwapChain* GetSwapChain() const;
virtual void* GetNativeSwapChain() const override;
virtual void* GetNativeBackBufferTexture() const override;
virtual void* GetNativeBackBufferRT() const overrid;
virtual void SetCustomPresent(FRHICustomPresent* InCustomPresent) override
virtual FRHICustomPresent* GetCustomPresent() const;
virtual void* GetNativeWindow(void** AddParam = nullptr) const override;
static FD3D11Texture2D* GetSwapChainSurface(FD3D11DynamicRHI* D3DRHI, EPixelFormat PixelFormat, uint32 SizeX, uint32 SizeY, IDXGISwapChain* SwapChain);
protected:
// 다이나믹 RHI.
FD3D11DynamicRHI* D3DRHI;
// 교환 체인
TRefCountPtr<IDXGISwapChain> SwapChain;
// 렌더링 후 버퍼
TRefCountPtr<FD3D11Texture2D> BackBuffer;
FD3D11EventQuery FrameSyncEvent;
FCustomPresentRHIRef CustomPresent;
(......)
};
C++ 축소 복사 전체 화면
FD3D11DynamicRHI를 UML 다이어그램으로 그려보면 아래와 같습니다:
10.3.3.2 FOpenGLDynamicRHI
FOpenGLDynamicRHI와 관련된 핵심 유형 정의는 다음과 같습니다:
class OPENGLDRV_API FOpenGLDynamicRHI final : public FDynamicRHI, public IRHICommandContextPSOFallback
{
(......)
private:
// 뷰포트 생성.
TArray<FOpenGLViewport*> Viewports;
// 기본 플랫폼과 관련된 데이터.
FPlatformOpenGLDevice* PlatformDevice;
};
// Engine\Source\Runtime\OpenGLDrv\Public\OpenGLResources.h
class FOpenGLViewport : public FRHIViewport
{
public:
FOpenGLViewport(class FOpenGLDynamicRHI* InOpenGLRHI,void* InWindowHandle,uint32 InSizeX,uint32 InSizeY,bool bInIsFullscreen,EPixelFormat PreferredPixelFormat);
~FOpenGLViewport();
void Resize(uint32 InSizeX,uint32 InSizeY,bool bInIsFullscreen);
// Accessors.
FIntPoint GetSizeXY() const;
FOpenGLTexture2D *GetBackBuffer() const;
bool IsFullscreen( void ) const;
void WaitForFrameEventCompletion();
void IssueFrameEvent();
virtual void* GetNativeWindow(void** AddParam) const override;
struct FPlatformOpenGLContext* GetGLContext() const;
FOpenGLDynamicRHI* GetOpenGLRHI() const;
virtual void SetCustomPresent(FRHICustomPresent* InCustomPresent) override;
FRHICustomPresent* GetCustomPresent() const;
private:
FOpenGLDynamicRHI* OpenGLRHI;
struct FPlatformOpenGLContext* OpenGLContext;
uint32 SizeX;
uint32 SizeY;
bool bIsFullscreen;
EPixelFormat PixelFormat;
bool bIsValid;
TRefCountPtr<FOpenGLTexture2D> BackBuffer;
FOpenGLEventQuery FrameSyncEvent;
FCustomPresentRHIRef CustomPresent;
};
// Engine\Source\Runtime\OpenGLDrv\Private\Android\AndroidOpenGL.cpp
// Android용 OpenGL 장치.
struct FPlatformOpenGLDevice
{
bool TargetDirty;
void SetCurrentSharedContext();
void SetCurrentRenderingContext();
void SetupCurrentContext();
void SetCurrentNULLContext();
FPlatformOpenGLDevice();
~FPlatformOpenGLDevice();
void Init();
void LoadEXT();
void Terminate();
void ReInit();
};
// Engine\Source\Runtime\OpenGLDrv\Private\Windows\OpenGLWindows.cpp
// Windows용 OpenGL 디바이스.
struct FPlatformOpenGLDevice
{
FPlatformOpenGLContext SharedContext;
FPlatformOpenGLContext RenderingContext;
TArray<FPlatformOpenGLContext*> ViewportContexts;
bool TargetDirty;
/** Guards against operating on viewport contexts from more than one thread at the same time. */
FCriticalSection* ContextUsageGuard;
};
// Engine\Source\Runtime\OpenGLDrv\Private\Lumin\LuminOpenGL.cpp
// Lumin 시스템용 OpenGL 장치.
struct FPlatformOpenGLDevice
{
void SetCurrentSharedContext();
void SetCurrentRenderingContext();
void SetCurrentNULLContext();
FPlatformOpenGLDevice();
~FPlatformOpenGLDevice();
void Init();
void LoadEXT();
void Terminate();
void ReInit();
};
// Engine\Source\Runtime\OpenGLDrv\Private\Linux\OpenGLLinux.cpp
// Linux용 OpenGL 장치.
struct FPlatformOpenGLDevice
{
FPlatformOpenGLContext SharedContext;
FPlatformOpenGLContext RenderingContext;
int32 NumUsedContexts;
FCriticalSection* ContextUsageGuard;
};
// Engine\Source\Runtime\OpenGLDrv\Private\Lumin\LuminGL4.cpp
// Lumin 시스템용 OpenGL 장치.
struct FPlatformOpenGLDevice
{
FPlatformOpenGLContext SharedContext;
FPlatformOpenGLContext RenderingContext;
TArray<FPlatformOpenGLContext*> ViewportContexts;
bool TargetDirty;
FCriticalSection* ContextUsageGuard;
};
위의 내용은 OpenGL 디바이스 객체의 정의가 운영 체제마다 다르다는 것을 보여줍니다. 실제로 OpenGL 컨텍스트도 운영 체제에 따라 다르며 다음은 Windows의 예입니다:
// Engine\Source\Runtime\OpenGLDrv\Private\Windows\OpenGLWindows.cpp
struct FPlatformOpenGLContext
{
// 윈도우 핸들
HWND WindowHandle;
// 디바이스 컨텍스트.
HDC DeviceContext;
// OpenGL 컨텍스트.
HGLRC OpenGLContext;
// 기타 실용적.
bool bReleaseWindowOnDestroy;
int32 SyncInterval;
GLuint ViewportFramebuffer;
GLuint VertexArrayObject; // one has to be generated and set for each context (OpenGL 3.2 Core requirements)
GLuint BackBufferResource;
GLenum BackBufferTarget;
};
C++ 복사 전체 화면
FOpenGLDynamicRHI가 그린 UML 다이어그램은 아래와 같습니다:
10.3.3.3 FD3D12DynamicRHI
FD3D12DynamicRHI의 핵심 유형 정의는 다음과 같습니다:
// Engine\Source\Runtime\D3D12RHI\Private\D3D12RHIPrivate.h
class FD3D12DynamicRHI : public FDynamicRHI
{
(......)
protected:
// 선택한 어댑터.
TArray<TSharedPtr<FD3D12Adapter>> ChosenAdapters;
// D3D12 장치
inline FD3D12Device* GetRHIDevice(uint32 GPUIndex)
{
return GetAdapter().GetDevice(GPUIndex);
}
(......)
};
// Engine\Source\Runtime\D3D12RHI\Private\D3D12Adapter.h
class FD3D12Adapter : public FNoncopyable
{
public:
void Initialize(FD3D12DynamicRHI* RHI);
void InitializeDevices();
void InitializeRayTracing();
// 리소스 생성.
HRESULT CreateCommittedResource(...)
HRESULT CreateBuffer(...);
template <typename BufferType>
BufferType* CreateRHIBuffer(...);
inline FD3D12CommandContextRedirector& GetDefaultContextRedirector();
inline FD3D12CommandContextRedirector& GetDefaultAsyncComputeContextRedirector();
FD3D12FastConstantAllocator& GetTransientUniformBufferAllocator();
void BlockUntilIdle();
(......)
protected:
virtual void CreateRootDevice(bool bWithDebug);
FD3D12DynamicRHI* OwningRHI;
// LDA 설정에는 ID3D12Device
TRefCountPtr<ID3D12Device> RootDevice;
TRefCountPtr<ID3D12Device1> RootDevice1;
TRefCountPtr<IDXGIAdapter> DxgiAdapter;
TRefCountPtr<IDXGIFactory> DxgiFactory;
TRefCountPtr<IDXGIFactory2> DxgiFactory2;
// 각 장치는 물리적 GPU "노드"를 나타냅니다.
FD3D12Device* Devices[MAX_NUM_GPUS];
FD3D12CommandContextRedirector DefaultContextRedirector;
FD3D12CommandContextRedirector DefaultAsyncComputeContextRedirector;
TArray<FD3D12Viewport*> Viewports;
TRefCountPtr<FD3D12Viewport> DrawingViewport;
(......)
};
// Engine\Source\Runtime\D3D12RHI\Private\D3D12RHICommon.h
class FD3D12AdapterChild
{
protected:
FD3D12Adapter* ParentAdapter;
(......)
};
class FD3D12DeviceChild
{
protected:
FD3D12Device* Parent;
(......)
};
// Engine\Source\Runtime\D3D12RHI\Private\D3D12Device.h
class FD3D12Device : public FD3D12SingleNodeGPUObject, public FNoncopyable, public FD3D12AdapterChild
{
public:
TArray<FD3D12CommandListHandle> PendingCommandLists;
void Initialize();
void CreateCommandContexts();
void InitPlatformSpecific();
virtual void Cleanup();
bool GetQueryData(FD3D12RenderQuery& Query, bool bWait);
ID3D12Device* GetDevice();
void BlockUntilIdle();
bool IsGPUIdle();
FD3D12SamplerState* CreateSampler(const FSamplerStateInitializerRHI& Initializer);
(......)
protected:
// CommandListManager
FD3D12CommandListManager* CommandListManager;
FD3D12CommandListManager* CopyCommandListManager;
FD3D12CommandListManager* AsyncCommandListManager;
FD3D12CommandAllocatorManager TextureStreamingCommandAllocatorManager;
// Allocator
FD3D12OfflineDescriptorManager RTVAllocator;
FD3D12OfflineDescriptorManager DSVAllocator;
FD3D12OfflineDescriptorManager SRVAllocator;
FD3D12OfflineDescriptorManager UAVAllocator;
FD3D12DefaultBufferAllocator DefaultBufferAllocator;
// FD3D12CommandContext
TArray<FD3D12CommandContext*> CommandContextArray;
TArray<FD3D12CommandContext*> FreeCommandContexts;
TArray<FD3D12CommandContext*> AsyncComputeContextArray;
(......)
};
// Engine\Source\Runtime\D3D12RHI\Public\D3D12Viewport.h
class FD3D12Viewport : public FRHIViewport, public FD3D12AdapterChild
{
public:
void Init();
void Resize(uint32 InSizeX, uint32 InSizeY, bool bInIsFullscreen, EPixelFormat PreferredPixelFormat);
void ConditionalResetSwapChain(bool bIgnoreFocus);
bool Present(bool bLockToVsync);
void WaitForFrameEventCompletion();
bool CurrentOutputSupportsHDR() const;
(......)
private:
HWND WindowHandle;
#if D3D12_VIEWPORT_EXPOSES_SWAP_CHAIN
TRefCountPtr<IDXGISwapChain1> SwapChain1;
TRefCountPtr<IDXGISwapChain4> SwapChain4;
#endif
TArray<TRefCountPtr<FD3D12Texture2D>> BackBuffers;
TRefCountPtr<FD3D12Texture2D> DummyBackBuffer_RenderThread;
uint32 CurrentBackBufferIndex_RHIThread;
FD3D12Texture2D* BackBuffer_RHIThread;
TArray<TRefCountPtr<FD3D12Texture2D>> SDRBackBuffers;
TRefCountPtr<FD3D12Texture2D> SDRDummyBackBuffer_RenderThread;
FD3D12Texture2D* SDRBackBuffer_RHIThread;
bool CheckHDRSupport();
void EnableHDR();
void ShutdownHDR();
(......)
};
// Engine\Source\Runtime\D3D12RHI\Private\D3D12CommandContext.h
class FD3D12CommandContextBase : public IRHICommandContext, public FD3D12AdapterChild
{
public:
FD3D12CommandContextBase(class FD3D12Adapter* InParent, FRHIGPUMask InGPUMask, bool InIsDefaultContext, bool InIsAsyncComputeContext);
void RHIBeginDrawingViewport(FRHIViewport* Viewport, FRHITexture* RenderTargetRHI) final override;
void RHIEndDrawingViewport(FRHIViewport* Viewport, bool bPresent, bool bLockToVsync) final override;
void RHIBeginFrame() final override;
void RHIEndFrame() final override;
(......)
protected:
virtual FD3D12CommandContext* GetContext(uint32 InGPUIndex) = 0;
FRHIGPUMask GPUMask;
(......)
};
class FD3D12CommandContext : public FD3D12CommandContextBase, public FD3D12DeviceChild
{
public:
FD3D12CommandContext(class FD3D12Device* InParent, bool InIsDefaultContext, bool InIsAsyncComputeContext);
virtual ~FD3D12CommandContext();
void EndFrame();
void ConditionalObtainCommandAllocator();
void ReleaseCommandAllocator();
FD3D12CommandListManager& GetCommandListManager();
void OpenCommandList();
void CloseCommandList();
FD3D12CommandListHandle FlushCommands(bool WaitForCompletion = false, EFlushCommandsExtraAction ExtraAction = FCEA_None);
void Finish(TArray<FD3D12CommandListHandle>& CommandLists);
FD3D12FastConstantAllocator ConstantsAllocator;
FD3D12CommandListHandle CommandListHandle;
FD3D12CommandAllocator* CommandAllocator;
FD3D12CommandAllocatorManager CommandAllocatorManager;
FD3D12DynamicRHI& OwningRHI;
// State Block.
FD3D12RenderTargetView* CurrentRenderTargets[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
FD3D12DepthStencilView* CurrentDepthStencilTarget;
FD3D12TextureBase* CurrentDepthTexture;
uint32 NumSimultaneousRenderTargets;
// Uniform Buffer.
FD3D12UniformBuffer* BoundUniformBuffers[SF_NumStandardFrequencies][MAX_CBS];
FUniformBufferRHIRef BoundUniformBufferRefs[SF_NumStandardFrequencies][MAX_CBS];
uint16 DirtyUniformBuffers[SF_NumStandardFrequencies];
// 상수 버퍼.
FD3D12ConstantBuffer VSConstantBuffer;
FD3D12ConstantBuffer HSConstantBuffer;
FD3D12ConstantBuffer DSConstantBuffer;
FD3D12ConstantBuffer PSConstantBuffer;
FD3D12ConstantBuffer GSConstantBuffer;
FD3D12ConstantBuffer CSConstantBuffer;
template <class ShaderType> void SetResourcesFromTables(const ShaderType* RESTRICT);
template <class ShaderType> uint32 SetUAVPSResourcesFromTables(const ShaderType* RESTRICT Shader);
void CommitGraphicsResourceTables();
void CommitComputeResourceTables(FD3D12ComputeShader* ComputeShader);
void ValidateExclusiveDepthStencilAccess(FExclusiveDepthStencil Src) const;
void CommitRenderTargetsAndUAVs();
virtual void SetDepthBounds(float MinDepth, float MaxDepth);
virtual void SetShadingRate(EVRSShadingRate ShadingRate, EVRSRateCombiner Combiner);
(......)
protected:
FD3D12CommandContext* GetContext(uint32 InGPUIndex) final override;
TArray<FRHIUniformBuffer*> GlobalUniformBuffers;
};
class FD3D12CommandContextRedirector final : public FD3D12CommandContextBase
{
public:
FD3D12CommandContextRedirector(class FD3D12Adapter* InParent, bool InIsDefaultContext, bool InIsAsyncComputeContext);
virtual void RHISetComputeShader(FRHIComputeShader* ComputeShader) final override;
virtual void RHISetComputePipelineState(FRHIComputePipelineState* ComputePipelineState) final override;
virtual void RHIDispatchComputeShader(uint32 ThreadGroupCountX, uint32 ThreadGroupCountY, uint32 ThreadGroupCountZ) final override;
(......)
private:
FRHIGPUMask PhysicalGPUMask;
FD3D12CommandContext* PhysicalContexts[MAX_NUM_GPUS];
};
// Engine\Source\Runtime\D3D12RHI\Private\D3D12CommandContext.cpp
class FD3D12CommandContextContainer : public IRHICommandContextContainer
{
FD3D12Adapter* Adapter;
FD3D12CommandContext* CmdContext;
FD3D12CommandContextRedirector* CmdContextRedirector;
FRHIGPUMask GPUMask;
TArray<FD3D12CommandListHandle> CommandLists;
(......)
};
위에서 볼 수 있듯이 D3D12는 매우 많은 수의 코어 유형과 여러 레벨의 복잡한 데이터 구조 체인을 포함하며 메모리 레이아웃은 아래와 같습니다:
[Engine]--
|
|-[RHI]--
|
|-[Adapter]-- (LDA)
| |
| |- [Device]
| |
| |- [Device]
|
|-[Adapter]--
|
|- [Device]--
|
|-[CommandContext]
|
|-[CommandContext]---
|
|-[StateCache]
이 구조에서 FD3D12Device는 1개의 물리적 어댑터에 속하는 1개의 노드를 나타냅니다. 이 구조는 예를 들어 하나의 RHI가 여러 가지 유형의 하드웨어 설정을 제어할 수 있도록 합니다:
- 단일 GPU 시스템(일반 케이스).
- LDA(크로스파이어/SLI)와 같은 멀티 GPU 시스템.
- 비대칭 멀티 GPU 시스템(예: 분리된 통합 GPU 협업 시스템).
D3D12의 핵심 클래스를 UML 다이어그램으로 추상화하면 아래와 같습니다:
10.3.3.4 FVulkanDynamicRHI
FVulkanDynamicRHI에 관련된 핵심 클래스는 다음과 같습니다:
// Engine\Source\Runtime\VulkanRHI\Public\VulkanDynamicRHI.h
class FVulkanDynamicRHI : public FDynamicRHI
{
public:
// FDynamicRHI interface.
virtual void Init() final override;
virtual void PostInit() final override;
virtual void Shutdown() final override;;
void InitInstance();
(......)
protected:
// 예시.
VkInstance Instance;
// 장치
TArray<FVulkanDevice*> Devices;
FVulkanDevice* Device;
// 뷰포트
TArray<FVulkanViewport*> Viewports;
(......)
};
// Engine\Source\Runtime\VulkanRHI\Private\VulkanDevice.h
class FVulkanDevice
{
public:
FVulkanDevice(FVulkanDynamicRHI* InRHI, VkPhysicalDevice Gpu);
~FVulkanDevice();
bool QueryGPU(int32 DeviceIndex);
void InitGPU(int32 DeviceIndex);
void CreateDevice();
void PrepareForDestroy();
void Destroy();
void WaitUntilIdle();
void PrepareForCPURead();
void SubmitCommandsAndFlushGPU();
(......)
private:
void SubmitCommands(FVulkanCommandListContext* Context);
// VK 디바이스.
VkDevice Device;
// VK 물리적 장치.
VkPhysicalDevice Gpu;
VkPhysicalDeviceProperties GpuProps;
VkPhysicalDeviceFeatures PhysicalFeatures;
// 매니저.
VulkanRHI::FDeviceMemoryManager DeviceMemoryManager;
VulkanRHI::FMemoryManager MemoryManager;
VulkanRHI::FDeferredDeletionQueue2 DeferredDeletionQueue;
VulkanRHI::FStagingManager StagingManager;
VulkanRHI::FFenceManager FenceManager;
FVulkanDescriptorPoolsManager* DescriptorPoolsManager = nullptr;
FVulkanDescriptorSetCache* DescriptorSetCache = nullptr;
FVulkanShaderFactory ShaderFactory;
// 큐.
FVulkanQueue* GfxQueue;
FVulkanQueue* ComputeQueue;
FVulkanQueue* TransferQueue;
FVulkanQueue* PresentQueue;
// GPU 브랜드.
EGpuVendorId VendorId = EGpuVendorId::NotQueried;
// 명령 대기열 컨텍스트.
FVulkanCommandListContextImmediate* ImmediateContext;
FVulkanCommandListContext* ComputeContext;
TArray<FVulkanCommandListContext*> CommandContexts;
FVulkanDynamicRHI* RHI = nullptr;
class FVulkanPipelineStateCacheManager* PipelineStateCache;
(......)
};
// Engine\Source\Runtime\VulkanRHI\Private\VulkanQueue.h
class FVulkanQueue
{
public:
FVulkanQueue(FVulkanDevice* InDevice, uint32 InFamilyIndex);
~FVulkanQueue();
void Submit(FVulkanCmdBuffer* CmdBuffer, uint32 NumSignalSemaphores = 0, VkSemaphore* SignalSemaphores = nullptr);
void Submit(FVulkanCmdBuffer* CmdBuffer, VkSemaphore SignalSemaphore);
void GetLastSubmittedInfo(FVulkanCmdBuffer*& OutCmdBuffer, uint64& OutFenceCounter) const;
(......)
private:
// VK 대기열
VkQueue Queue;
// 제품군 색인.
uint32 FamilyIndex;
// 큐 인덱스.
uint32 QueueIndex;
FVulkanDevice* Device;
// VK 명령 버퍼 .
FVulkanCmdBuffer* LastSubmittedCmdBuffer;
uint64 LastSubmittedCmdBufferFenceCounter;
uint64 SubmitCounter;
mutable FCriticalSection CS;
void UpdateLastSubmittedCommandBuffer(FVulkanCmdBuffer* CmdBuffer);
};
// Engine\Source\Runtime\VulkanRHI\Public\VulkanMemory.h
// 디바이스 하위 노드.
class FDeviceChild
{
public:
FDeviceChild(FVulkanDevice* InDevice = nullptr);
(......)
protected:
FVulkanDevice* Device;
};
// Engine\Source\Runtime\VulkanRHI\Private\VulkanContext.h
class FVulkanCommandListContext : public IRHICommandContext
{
public:
FVulkanCommandListContext(FVulkanDynamicRHI* InRHI, FVulkanDevice* InDevice, FVulkanQueue* InQueue, FVulkanCommandListContext* InImmediate);
virtual ~FVulkanCommandListContext();
static inline FVulkanCommandListContext& GetVulkanContext(IRHICommandContext& CmdContext);
inline bool IsImmediate() const;
virtual void RHISetStreamSource(uint32 StreamIndex, FRHIVertexBuffer* VertexBuffer, uint32 Offset) final override;
virtual void RHISetViewport(float MinX, float MinY, float MinZ, float MaxX, float MaxY, float MaxZ) final override;
virtual void RHISetScissorRect(bool bEnable, uint32 MinX, uint32 MinY, uint32 MaxX, uint32 MaxY) final override;
(......)
inline FVulkanDevice* GetDevice() const;
void PrepareParallelFromBase(const FVulkanCommandListContext& BaseContext);
protected:
FVulkanDynamicRHI* RHI;
FVulkanCommandListContext* Immediate;
FVulkanDevice* Device;
FVulkanQueue* Queue;
FVulkanUniformBufferUploader* UniformBufferUploader;
FVulkanCommandBufferManager* CommandBufferManager;
static FVulkanLayoutManager LayoutManager;
private:
FVulkanGPUProfiler GpuProfiler;
TArray<FRHIUniformBuffer*> GlobalUniformBuffers;
(......)
};
// 즉시 모드 명령 대기열 컨텍스트.
class FVulkanCommandListContextImmediate : public FVulkanCommandListContext
{
public:
FVulkanCommandListContextImmediate(FVulkanDynamicRHI* InRHI, FVulkanDevice* InDevice, FVulkanQueue* InQueue);
};
// 명령 컨텍스트 컨테이너.
struct FVulkanCommandContextContainer : public IRHICommandContextContainer, public VulkanRHI::FDeviceChild
{
FVulkanCommandListContext* CmdContext;
FVulkanCommandContextContainer(FVulkanDevice* InDevice);
virtual IRHICommandContext* GetContext() override final;
virtual void FinishContext() override final;
virtual void SubmitAndFreeContextContainer(int32 Index, int32 Num) override final;
void* operator new(size_t Size);
void operator delete(void* RawMemory);
(......)
};
// Engine\Source\Runtime\VulkanRHI\Private\VulkanViewport.h
class FVulkanViewport : public FRHIViewport, public VulkanRHI::FDeviceChild
{
public:
FVulkanViewport(FVulkanDynamicRHI* InRHI, FVulkanDevice* InDevice, void* InWindowHandle, uint32 InSizeX,uint32 InSizeY,bool bInIsFullscreen, EPixelFormat InPreferredPixelFormat);
~FVulkanViewport();
void AdvanceBackBufferFrame(FRHICommandListImmediate& RHICmdList);
void WaitForFrameEventCompletion();
virtual void SetCustomPresent(FRHICustomPresent* InCustomPresent) override final;
virtual FRHICustomPresent* GetCustomPresent() const override final;
virtual void Tick(float DeltaTime) override final;
bool Present(FVulkanCommandListContext* Context, FVulkanCmdBuffer* CmdBuffer, FVulkanQueue* Queue, FVulkanQueue* PresentQueue, bool bLockToVsync);
(......)
protected:
TArray<VkImage, TInlineAllocator<NUM_BUFFERS*2>> BackBufferImages;
TArray<VulkanRHI::FSemaphore*, TInlineAllocator<NUM_BUFFERS*2>> RenderingDoneSemaphores;
TArray<FVulkanTextureView, TInlineAllocator<NUM_BUFFERS*2>> TextureViews;
TRefCountPtr<FVulkanBackBuffer> RHIBackBuffer;
TRefCountPtr<FVulkanTexture2D> RenderingBackBuffer;
/** narrow-scoped section that locks access to back buffer during its recreation*/
FCriticalSection RecreatingSwapchain;
FVulkanDynamicRHI* RHI;
FVulkanSwapChain* SwapChain;
void* WindowHandle;
VulkanRHI::FSemaphore* AcquiredSemaphore;
FCustomPresentRHIRef CustomPresent;
FVulkanCmdBuffer* LastFrameCommandBuffer = nullptr;
(......)
};
Vulkan RHI의 핵심 유형을 UML 다이어그램으로 표시하면 아래와 같습니다:
10.3.3.5 FMetalDynamicRHI
FMetalDynamicRHI의 핵심 유형 정의는 다음과 같습니다:
// Engine\Source\Runtime\Apple\MetalRHI\Private\MetalDynamicRHI.h
class FMetalDynamicRHI : public FDynamicRHI
{
public:
// FDynamicRHI interface.
virtual void Init();
virtual void Shutdown() {}
(......)
private:
// 즉시 모드 컨텍스트.
FMetalRHIImmediateCommandContext ImmediateContext;
// 비동기 컴퓨팅 컨텍스트.
FMetalRHICommandContext* AsyncComputeContext;
(......)
};
// Engine\Source\Runtime\Apple\MetalRHI\Public\MetalRHIContext.h
class FMetalRHICommandContext : public IRHICommandContext
{
public:
FMetalRHICommandContext(class FMetalProfiler* InProfiler, FMetalContext* WrapContext);
virtual ~FMetalRHICommandContext();
virtual void RHISetComputeShader(FRHIComputeShader* ComputeShader) override;
virtual void RHISetComputePipelineState(FRHIComputePipelineState* ComputePipelineState) override;
virtual void RHIDispatchComputeShader(uint32 ThreadGroupCountX, uint32 ThreadGroupCountY, uint32 ThreadGroupCountZ) final override;
(......)
protected:
// 메탈 컨텍스트.
FMetalContext* Context;
TSharedPtr<FMetalCommandBufferFence, ESPMode::ThreadSafe> CommandBufferFence;
class FMetalProfiler* Profiler;
FMetalBuffer PendingVertexBuffer;
TArray<FRHIUniformBuffer*> GlobalUniformBuffers;
(......)
};
class FMetalRHIComputeContext : public FMetalRHICommandContext
{
public:
FMetalRHIComputeContext(class FMetalProfiler* InProfiler, FMetalContext* WrapContext);
virtual ~FMetalRHIComputeContext();
virtual void RHISetAsyncComputeBudget(EAsyncComputeBudget Budget) final override;
virtual void RHISetComputeShader(FRHIComputeShader* ComputeShader) final override;
virtual void RHISetComputePipelineState(FRHIComputePipelineState* ComputePipelineState) final override;
virtual void RHISubmitCommandsHint() final override;
};
class FMetalRHIImmediateCommandContext : public FMetalRHICommandContext
{
public:
FMetalRHIImmediateCommandContext(class FMetalProfiler* InProfiler, FMetalContext* WrapContext);
// FRHICommandContext API accessible only on the immediate device context
virtual void RHIBeginDrawingViewport(FRHIViewport* Viewport, FRHITexture* RenderTargetRHI) final override;
virtual void RHIEndDrawingViewport(FRHIViewport* Viewport, bool bPresent, bool bLockToVsync) final override;
(......)
};
// Engine\Source\Runtime\Apple\MetalRHI\Private\MetalContext.h
// 컨텍스트.
class FMetalContext
{
public:
FMetalContext(mtlpp::Device InDevice, FMetalCommandQueue& Queue, bool const bIsImmediate);
virtual ~FMetalContext();
mtlpp::Device& GetDevice();
bool PrepareToDraw(uint32 PrimitiveType, EMetalIndexType IndexType = EMetalIndexType_None);
void SetRenderPassInfo(const FRHIRenderPassInfo& RenderTargetsInfo, bool const bRestart = false);
void SubmitCommandsHint(uint32 const bFlags = EMetalSubmitFlagsCreateCommandBuffer);
void SubmitCommandBufferAndWait();
void ResetRenderCommandEncoder();
void DrawPrimitive(uint32 PrimitiveType, uint32 BaseVertexIndex, uint32 NumPrimitives, uint32 NumInstances);
void DrawPrimitiveIndirect(uint32 PrimitiveType, FMetalVertexBuffer* VertexBuffer, uint32 ArgumentOffset);
void DrawIndexedPrimitive(FMetalBuffer const& IndexBuffer, ...);
void DrawIndexedIndirect(FMetalIndexBuffer* IndexBufferRHI, ...);
void DrawIndexedPrimitiveIndirect(uint32 PrimitiveType, ...);
void DrawPatches(uint32 PrimitiveType, ...);
(......)
protected:
// 메탈 기본 유닛.
mtlpp::Device Device;
FMetalCommandQueue& CommandQueue;
FMetalCommandList CommandList;
FMetalStateCache StateCache;
FMetalRenderPass RenderPass;
dispatch_semaphore_t CommandBufferSemaphore;
TSharedPtr<FMetalQueryBufferPool, ESPMode::ThreadSafe> QueryBuffer;
TRefCountPtr<FMetalFence> StartFence;
TRefCountPtr<FMetalFence> EndFence;
int32 NumParallelContextsInPass;
(......)
};
// Engine\Source\Runtime\Apple\MetalRHI\Private\MetalCommandQueue.h
class FMetalCommandQueue
{
public:
FMetalCommandQueue(mtlpp::Device Device, uint32 const MaxNumCommandBuffers = 0);
~FMetalCommandQueue(void);
mtlpp::CommandBuffer CreateCommandBuffer(void);
void CommitCommandBuffer(mtlpp::CommandBuffer& CommandBuffer);
void SubmitCommandBuffers(TArray<mtlpp::CommandBuffer> BufferList, uint32 Index, uint32 Count);
FMetalFence* CreateFence(ns::String const& Label) const;
void GetCommittedCommandBufferFences(TArray<mtlpp::CommandBufferFence>& Fences);
mtlpp::Device& GetDevice(void);
static mtlpp::ResourceOptions GetCompatibleResourceOptions(mtlpp::ResourceOptions Options);
static inline bool SupportsFeature(EMetalFeatures InFeature);
static inline bool SupportsSeparateMSAAAndResolveTarget();
(......)
private:
// 디바이스.
mtlpp::Device Device;
// 명령 대기열.
mtlpp::CommandQueue CommandQueue;
// 명령 버퍼 목록입니다.(배열의 배열이라는 점에 유의하세요.)
TArray<TArray<mtlpp::CommandBuffer>> CommandBuffers;
TLockFreePointerListLIFO<mtlpp::CommandBufferFence> CommandBufferFences;
uint64 ParallelCommandLists;
};
// Engine\Source\Runtime\Apple\MetalRHI\Private\MetalCommandList.h
class FMetalCommandList
{
public:
FMetalCommandList(FMetalCommandQueue& InCommandQueue, bool const bInImmediate);
~FMetalCommandList(void);
void Commit(mtlpp::CommandBuffer& Buffer, TArray<ns::Object<mtlpp::CommandBufferHandler>> CompletionHandlers, bool const bWait, bool const bIsLastCommandBuffer);
void Submit(uint32 Index, uint32 Count);
bool IsImmediate(void) const;
bool IsParallel(void) const;
void SetParallelIndex(uint32 Index, uint32 Num);
uint32 GetParallelIndex(void) const;
uint32 GetParallelNum(void) const;
(......)
private:
// 그것이 속한 FMetalCommandQueue.
FMetalCommandQueue& CommandQueue;
// 제출된 명령의 버퍼링된 목록.
TArray<mtlpp::CommandBuffer> SubmittedBuffers;
};
FMetalDynamicRHI는 다른 최신 그래픽 API보다 개념과 인터페이스가 훨씬 더 간결합니다. UML 다이어그램은 아래와 같습니다:
10.3.4 RHI 시스템 개요
섹션 10.2와 10.3에서는 렌더링 계층의 리소스, RHI 계층의 리소스, 명령, 컨텍스트, 동적 RHI 등 RHI 시스템의 기본 개념과 상속 체계, 각 주요 그래픽 API의 구체적인 구현과 RHI 추상화 계층과의 연결에 대해 자세히 설명합니다.
그래픽 API의 구현과 수많은 RHI의 구체적인 하위 클래스에 대한 세부 사항은 제쳐두고, RHI Context/CommandList/Command/Resource 등의 최상위 개념은 다음과 같은 UML 관계 다이어그램으로 요약할 수 있습니다:
아래는 위에서 세분화된 하위 클래스가 포함된 UML입니다:
10-2 에서 계속...
원문
https://www.cnblogs.com/timlly/p/15156626.html
'TECH.ART.FLOW.IO' 카테고리의 다른 글
[번역] Optimizing AMD FSR for Mobiles (1) | 2024.09.20 |
---|---|
[소식] 유니티 2024 테크데모 공개. (2) | 2024.09.20 |
[번역] 언리얼 렌더링 시스템 해부하기(11)- RDG (1) | 2024.09.14 |
[공유] 검은신화오공 3D 오공 어셋. (0) | 2024.09.13 |
[번역] 유니티 Shader Warmup에 대하여 (6) | 2024.09.12 |