Files
UnrealEngine/Engine/Source/Runtime/NullDrv/Private/NullRHI.cpp
2025-05-18 13:04:45 +08:00

136 lines
4.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "NullRHI.h"
#include "Misc/CoreMisc.h"
#include "Containers/List.h"
#include "RenderResource.h"
#include "RenderUtils.h"
#include "RHICommandList.h"
#include "DataDrivenShaderPlatformInfo.h"
#include "GPUProfiler.h"
#if RHI_NEW_GPU_PROFILER
constexpr UE::RHI::GPUProfiler::FQueue NullRHIGPUProfilerQueue(UE::RHI::GPUProfiler::FQueue::EType::Graphics, 0, 0);
#endif
FNullDynamicRHI::FNullDynamicRHI()
{
GMaxRHIShaderPlatform = ShaderFormatToLegacyShaderPlatform(FName(FPlatformMisc::GetNullRHIShaderFormat()));
GMaxTextureDimensions = 16384;
GMaxTextureMipCount = FPlatformMath::CeilLogTwo(GMaxTextureDimensions) + 1;
GMaxTextureMipCount = FPlatformMath::Min<int32>( MAX_TEXTURE_MIP_COUNT, GMaxTextureMipCount );
}
void FNullDynamicRHI::Init()
{
GMaxRHIFeatureLevel = GetMaxSupportedFeatureLevel(GMaxRHIShaderPlatform);
#if PLATFORM_WINDOWS
GShaderPlatformForFeatureLevel[ERHIFeatureLevel::ES2_REMOVED] = SP_NumPlatforms;
GShaderPlatformForFeatureLevel[ERHIFeatureLevel::ES3_1] = SP_PCD3D_ES3_1;
GShaderPlatformForFeatureLevel[ERHIFeatureLevel::SM4_REMOVED] = SP_NumPlatforms;
GShaderPlatformForFeatureLevel[ERHIFeatureLevel::SM5] = SP_PCD3D_SM5;
GShaderPlatformForFeatureLevel[ERHIFeatureLevel::SM6] = SP_PCD3D_SM6;
#elif PLATFORM_MAC
GShaderPlatformForFeatureLevel[ERHIFeatureLevel::ES2_REMOVED] = SP_NumPlatforms;
GShaderPlatformForFeatureLevel[ERHIFeatureLevel::ES3_1] = SP_METAL_ES3_1;
GShaderPlatformForFeatureLevel[ERHIFeatureLevel::SM4_REMOVED] = SP_NumPlatforms;
GShaderPlatformForFeatureLevel[ERHIFeatureLevel::SM5] = SP_METAL_SM5;
GShaderPlatformForFeatureLevel[ERHIFeatureLevel::SM6] = SP_METAL_SM6;
#elif PLATFORM_LINUX // (see FVulkanGenericPlatform::SetupFeatureLevels)
GShaderPlatformForFeatureLevel[ERHIFeatureLevel::ES2_REMOVED] = SP_NumPlatforms;
GShaderPlatformForFeatureLevel[ERHIFeatureLevel::ES3_1] = SP_VULKAN_PCES3_1;
GShaderPlatformForFeatureLevel[ERHIFeatureLevel::SM4_REMOVED] = SP_NumPlatforms;
GShaderPlatformForFeatureLevel[ERHIFeatureLevel::SM5] = SP_VULKAN_SM5;
GShaderPlatformForFeatureLevel[ERHIFeatureLevel::SM6] = SP_VULKAN_SM6;
#else
GShaderPlatformForFeatureLevel[GMaxRHIFeatureLevel] = GMaxRHIShaderPlatform;
#endif
GRHIVendorId = 1;
check(!GIsRHIInitialized);
// do not do this at least on dedicated server; clients with -NullRHI may need additional consideration
#if !WITH_EDITOR
if (!IsRunningDedicatedServer())
#endif
{
FRenderResource::InitPreRHIResources();
}
GIsRHIInitialized = true;
#if RHI_NEW_GPU_PROFILER
// Register a single dummy graphics GPU queue. This is required so that we can still submit the frame boundary events in RHIEndFrame.
UE::RHI::GPUProfiler::InitializeQueues(MakeConstArrayView(&NullRHIGPUProfilerQueue, 1));
#endif
}
void FNullDynamicRHI::Shutdown()
{
}
/**
* Return a shared large static buffer that can be used to return from any
* function that needs to return a valid pointer (but can be garbage data)
*/
void* FNullDynamicRHI::GetStaticBuffer(size_t Size)
{
#if !WITH_EDITOR
static bool bLogOnce = false;
if (!bLogOnce && (IsRunningDedicatedServer()))
{
UE_LOG(LogRHI, Log, TEXT("NullRHI preferably does not allocate memory on the server. Try to change the caller to avoid doing allocs in when FApp::ShouldUseNullRHI() is true."));
bLogOnce = true;
}
#endif
MemoryBuffer.Reserve(Size);
return MemoryBuffer.GetData();
}
void* FNullDynamicRHI::GetStaticTextureBuffer(int32 SizeX, int32 SizeY, EPixelFormat Format, uint32& DestStride, uint64* OutLockedByteCount)
{
size_t Size = CalculateImageBytes(SizeX, SizeY, 0, Format);
if (OutLockedByteCount)
{
*OutLockedByteCount = Size;
}
DestStride = Size / SizeY;
return GetStaticBuffer(Size);
}
void FNullDynamicRHI::RHIEndFrame(const FRHIEndFrameArgs& Args)
{
// The RHI must publish the frame boundary events for engine stats to work correctly.
#if RHI_NEW_GPU_PROFILER
UE::RHI::GPUProfiler::FEventStream EventStream(NullRHIGPUProfilerQueue);
EventStream.Emplace<UE::RHI::GPUProfiler::FEvent::FFrameBoundary>(FPlatformTime::Cycles64(), Args.FrameNumber
#if WITH_RHI_BREADCRUMBS
, Args.GPUBreadcrumbs[ERHIPipeline::Graphics]
#endif
#if STATS
, Args.StatsFrame
#endif
);
UE::RHI::GPUProfiler::ProcessEvents(MakeArrayView(&EventStream, 1));
#endif
}
/** Value between 0-100 that determines the percentage of the vertical scan that is allowed to pass while still allowing us to swap when VSYNC'ed.
This is used to get the same behavior as the old *_OR_IMMEDIATE present modes. */
uint32 GPresentImmediateThreshold = 100;
// Suppress linker warning "warning LNK4221: no public symbols found; archive member will be inaccessible"
int32 NullRHILinkerHelper;