203 lines
7.8 KiB
C++
203 lines
7.8 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "VulkanGenericPlatform.h"
|
|
#include "VulkanCommandWrappers.h"
|
|
#include "VulkanDevice.h"
|
|
#include "HAL/FileManager.h"
|
|
#include "Misc/CommandLine.h"
|
|
#include "VulkanCommandBuffer.h"
|
|
|
|
static TAutoConsoleVariable<int32> CVarVulkanUseProfileCheck(
|
|
TEXT("r.Vulkan.UseProfileCheck"),
|
|
1,
|
|
TEXT("0 to assume all requested feature levels are supported.\n")
|
|
TEXT("1 to verify feature level support using a profile check (default)\n"),
|
|
ECVF_ReadOnly
|
|
);
|
|
|
|
void FVulkanGenericPlatform::SetupFeatureLevels(TArrayView<EShaderPlatform> ShaderPlatformForFeatureLevel)
|
|
{
|
|
checkf(ERHIFeatureLevel::Num == ShaderPlatformForFeatureLevel.Num(), TEXT("ShaderPlatformForFeatureLevel is not the right size to fit all Feature Level values."));
|
|
|
|
ShaderPlatformForFeatureLevel[ERHIFeatureLevel::ES2_REMOVED] = SP_NumPlatforms;
|
|
ShaderPlatformForFeatureLevel[ERHIFeatureLevel::ES3_1] = SP_VULKAN_PCES3_1;
|
|
ShaderPlatformForFeatureLevel[ERHIFeatureLevel::SM4_REMOVED] = SP_NumPlatforms;
|
|
ShaderPlatformForFeatureLevel[ERHIFeatureLevel::SM5] = SP_VULKAN_SM5;
|
|
ShaderPlatformForFeatureLevel[ERHIFeatureLevel::SM6] = SP_VULKAN_SM6;
|
|
}
|
|
|
|
ERHIFeatureLevel::Type FVulkanGenericPlatform::GetFeatureLevel(ERHIFeatureLevel::Type InRequestedFeatureLevel)
|
|
{
|
|
const bool bForceES3_1 = (FVulkanPlatform::RequiresMobileRenderer() ||
|
|
(InRequestedFeatureLevel == ERHIFeatureLevel::ES3_1) ||
|
|
FParse::Param(FCommandLine::Get(), TEXT("FeatureLevelES31")) || FParse::Param(FCommandLine::Get(), TEXT("FeatureLevelES3_1")));
|
|
|
|
return (!GIsEditor && bForceES3_1) ? ERHIFeatureLevel::ES3_1 : InRequestedFeatureLevel;
|
|
}
|
|
|
|
bool FVulkanGenericPlatform::PSOBinaryCacheMatches(FVulkanDevice* Device, const TArray<uint8>& DeviceCache)
|
|
{
|
|
if (DeviceCache.Num() > 4)
|
|
{
|
|
uint32* Data = (uint32*)DeviceCache.GetData();
|
|
uint32 HeaderSize = *Data++;
|
|
// 16 is HeaderSize + HeaderVersion
|
|
if (HeaderSize == 16 + VK_UUID_SIZE)
|
|
{
|
|
uint32 HeaderVersion = *Data++;
|
|
if (HeaderVersion == VK_PIPELINE_CACHE_HEADER_VERSION_ONE)
|
|
{
|
|
uint32 VendorID = *Data++;
|
|
const VkPhysicalDeviceProperties& DeviceProperties = Device->GetDeviceProperties();
|
|
if (VendorID == DeviceProperties.vendorID)
|
|
{
|
|
uint32 DeviceID = *Data++;
|
|
if (DeviceID == DeviceProperties.deviceID)
|
|
{
|
|
uint8* Uuid = (uint8*)Data;
|
|
if (FMemory::Memcmp(DeviceProperties.pipelineCacheUUID, Uuid, VK_UUID_SIZE) == 0)
|
|
{
|
|
// This particular binary cache matches this device
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
FString FVulkanGenericPlatform::CreatePSOBinaryCacheFilename(FVulkanDevice* Device, FString CacheFilename)
|
|
{
|
|
const VkPhysicalDeviceProperties& DeviceProperties = Device->GetDeviceProperties();
|
|
FString BinaryCacheAppendage = FString::Printf(TEXT(".%x.%x"), DeviceProperties.vendorID, DeviceProperties.deviceID);
|
|
if (!CacheFilename.EndsWith(BinaryCacheAppendage))
|
|
{
|
|
CacheFilename += BinaryCacheAppendage;
|
|
}
|
|
|
|
return CacheFilename;
|
|
}
|
|
|
|
TArray<FString> FVulkanGenericPlatform::GetPSOCacheFilenames()
|
|
{
|
|
TArray<FString> CacheFilenames;
|
|
FString StagedCacheDirectory = FPaths::ProjectDir() / TEXT("Build") / TEXT("ShaderCaches") / FPlatformProperties::IniPlatformName();
|
|
|
|
// look for any staged caches
|
|
TArray<FString> StagedCaches;
|
|
IFileManager::Get().FindFiles(StagedCaches, *StagedCacheDirectory, TEXT("cache"));
|
|
// FindFiles returns the filenames without directory, so prepend the stage directory
|
|
for (const FString& Filename : StagedCaches)
|
|
{
|
|
CacheFilenames.Add(StagedCacheDirectory / Filename);
|
|
}
|
|
|
|
return CacheFilenames;
|
|
}
|
|
|
|
void FVulkanGenericPlatform::RestrictEnabledPhysicalDeviceFeatures(FVulkanPhysicalDeviceFeatures* InOutFeaturesToEnable)
|
|
{
|
|
// Disable everything sparse-related
|
|
InOutFeaturesToEnable->Core_1_0.shaderResourceResidency = VK_FALSE;
|
|
InOutFeaturesToEnable->Core_1_0.shaderResourceMinLod = VK_FALSE;
|
|
InOutFeaturesToEnable->Core_1_0.sparseBinding = VK_FALSE;
|
|
InOutFeaturesToEnable->Core_1_0.sparseResidencyBuffer = VK_FALSE;
|
|
InOutFeaturesToEnable->Core_1_0.sparseResidencyImage2D = VK_FALSE;
|
|
InOutFeaturesToEnable->Core_1_0.sparseResidencyImage3D = VK_FALSE;
|
|
InOutFeaturesToEnable->Core_1_0.sparseResidency2Samples = VK_FALSE;
|
|
InOutFeaturesToEnable->Core_1_0.sparseResidency4Samples = VK_FALSE;
|
|
InOutFeaturesToEnable->Core_1_0.sparseResidency8Samples = VK_FALSE;
|
|
InOutFeaturesToEnable->Core_1_0.sparseResidencyAliased = VK_FALSE;
|
|
}
|
|
|
|
VkResult FVulkanGenericPlatform::Present(VkQueue Queue, VkPresentInfoKHR& PresentInfo)
|
|
{
|
|
return VulkanRHI::vkQueuePresentKHR(Queue, &PresentInfo);
|
|
}
|
|
|
|
VkResult FVulkanGenericPlatform::CreateSwapchainKHR(FVulkanGenericPlatformWindowContext& WindowContext, VkPhysicalDevice PhysicalDevice, VkDevice Device, const VkSwapchainCreateInfoKHR* CreateInfo, const VkAllocationCallbacks* Allocator, VkSwapchainKHR* Swapchain)
|
|
{
|
|
return VulkanRHI::vkCreateSwapchainKHR(Device, CreateInfo, Allocator, Swapchain);
|
|
}
|
|
|
|
void FVulkanGenericPlatform::DestroySwapchainKHR(VkDevice Device, VkSwapchainKHR Swapchain, const VkAllocationCallbacks* Allocator)
|
|
{
|
|
VulkanRHI::vkDestroySwapchainKHR(Device, Swapchain, Allocator);
|
|
}
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable : 4191) // warning C4191: 'type cast': unsafe conversion
|
|
bool FVulkanGenericPlatform::LoadVulkanInstanceFunctions(VkInstance InInstance)
|
|
{
|
|
if (VulkanDynamicAPI::vkGetInstanceProcAddr != nullptr)
|
|
{
|
|
bool bFoundAllEntryPoints = true;
|
|
|
|
#define GETINSTANCE_VK_ENTRYPOINTS(Type, Func) VulkanDynamicAPI::Func = (Type)VulkanDynamicAPI::vkGetInstanceProcAddr(InInstance, #Func);
|
|
#define CHECK_VK_ENTRYPOINTS(Type,Func) if (VulkanDynamicAPI::Func == nullptr) { bFoundAllEntryPoints = false; UE_LOG(LogRHI, Warning, TEXT("Failed to find entry point for %s"), TEXT(#Func)); }
|
|
|
|
// Initialize basic common instance entrypoints and verify they are all present
|
|
ENUM_VK_ENTRYPOINTS_INSTANCE(GETINSTANCE_VK_ENTRYPOINTS);
|
|
ENUM_VK_ENTRYPOINTS_INSTANCE(CHECK_VK_ENTRYPOINTS);
|
|
|
|
// Initialize optional instance entrypoints
|
|
ENUM_VK_ENTRYPOINTS_OPTIONAL_INSTANCE(GETINSTANCE_VK_ENTRYPOINTS);
|
|
|
|
#undef GETINSTANCE_VK_ENTRYPOINTS
|
|
#undef CHECK_VK_ENTRYPOINTS
|
|
|
|
return bFoundAllEntryPoints;
|
|
}
|
|
return false;
|
|
}
|
|
#pragma warning(pop) // restore 4191
|
|
|
|
|
|
void FVulkanGenericPlatform::ClearVulkanInstanceFunctions()
|
|
{
|
|
// Initialize all of the entry points we have to query manually
|
|
#define CLEAR_VK_ENTRYPOINTS(Type, Func) VulkanDynamicAPI::Func = nullptr;
|
|
ENUM_VK_ENTRYPOINTS_INSTANCE(CLEAR_VK_ENTRYPOINTS);
|
|
ENUM_VK_ENTRYPOINTS_OPTIONAL_INSTANCE(CLEAR_VK_ENTRYPOINTS);
|
|
#undef CLEAR_VK_ENTRYPOINTS
|
|
}
|
|
|
|
bool FVulkanGenericPlatform::SupportsProfileChecks()
|
|
{
|
|
return (CVarVulkanUseProfileCheck.GetValueOnAnyThread() != 0) &&
|
|
!FParse::Param(FCommandLine::Get(), TEXT("SkipVulkanProfileCheck"));
|
|
}
|
|
|
|
FString FVulkanGenericPlatform::GetVulkanProfileNameForFeatureLevel(ERHIFeatureLevel::Type FeatureLevel, bool bRaytracing)
|
|
{
|
|
FString ProfileName = TEXT("VP_UE_Vulkan_") + LexToString(FeatureLevel);
|
|
if (bRaytracing)
|
|
{
|
|
ProfileName += TEXT("_RT");
|
|
}
|
|
return ProfileName;
|
|
}
|
|
|
|
void FVulkanGenericPlatform::WriteCrashMarkerWithoutExtensions(FVulkanCommandBuffer* CmdBuffer, VkBuffer DestBuffer, const TArrayView<uint32>& Entries, bool bAdding)
|
|
{
|
|
// Buffer writes cannot be recorded inside of a render pass
|
|
if (CmdBuffer->IsOutsideRenderPass())
|
|
{
|
|
// execution barrier
|
|
VulkanDynamicAPI::vkCmdPipelineBarrier(CmdBuffer->GetHandle(), VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 0, nullptr);
|
|
|
|
VulkanDynamicAPI::vkCmdFillBuffer(CmdBuffer->GetHandle(), DestBuffer, 0, sizeof(uint32), Entries.Num());
|
|
if (bAdding)
|
|
{
|
|
int32 LastIndex = Entries.Num() - 1;
|
|
VulkanDynamicAPI::vkCmdFillBuffer(CmdBuffer->GetHandle(), DestBuffer, (1 + LastIndex) * sizeof(uint32), sizeof(uint32), Entries[LastIndex]);
|
|
}
|
|
|
|
// execution barrier
|
|
VulkanDynamicAPI::vkCmdPipelineBarrier(CmdBuffer->GetHandle(), VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 0, nullptr);
|
|
}
|
|
}
|