Files
carl lloyd edd3b69886 VulkanRHI: Fixes for PSO compilation
Added VkPipelineShaderStageRequiredSubgroupSizeCreateInfo
Added VkAttachmentReferenceStencilLayout
Added more nullptr checks for pNext

#rb Allan.Bentham

[CL 25551558 by carl lloyd in ue5-main branch]
2023-05-19 16:24:28 -04:00

869 lines
30 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
PSOService.cpp: Vulkan PSO compilation service
=============================================================================*/
#include <jni.h>
#include <android/log.h>
#include "vulkan/vulkan.h"
#include <vector>
#include <list>
#include <string>
#define APPNAME "UEPSOService"
#define JNI_METHOD __attribute__ ((visibility ("default"))) extern "C"
VKAPI_ATTR VkBool32 VKAPI_CALL VKValidationCallback(
VkDebugReportFlagsEXT flags,
VkDebugReportObjectTypeEXT objectType,
uint64_t object,
size_t location,
int32_t messageCode,
const char* pLayerPrefix,
const char* pMessage,
void* pUserData)
{
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "VK Validation: %s", pMessage);
return VK_FALSE;
}
class FVulkanPSOCompiler
{
bool bInitialized = false;
VkDevice Device = VK_NULL_HANDLE;
VkInstance Instance = VK_NULL_HANDLE;
std::vector<VkPhysicalDevice> devices;
PFN_vkCreateRenderPass2KHR vkCreateRenderPass2;
size_t PSOCacheSize = 0;
char * PSOCacheData = nullptr;
bool bSinglePSOPerCache = true;
VkPipelineCache PipelineCache = VK_NULL_HANDLE;
public:
static FVulkanPSOCompiler& Get()
{
static FVulkanPSOCompiler Single;
return Single;
}
void InitDevice(std::vector<const char*>& InstanceLayers, std::vector<const char*>& InstanceExtensions, std::vector<const char*>& DeviceExtensions)
{
if (bInitialized)
return;
bInitialized = true;
VkApplicationInfo appInfo{};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = APPNAME;
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = nullptr;
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_0;
VkInstanceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo;
createInfo.enabledExtensionCount = InstanceExtensions.size();
createInfo.ppEnabledExtensionNames = InstanceExtensions.data();
createInfo.enabledLayerCount = InstanceLayers.size();
createInfo.ppEnabledLayerNames = InstanceLayers.data();
bool bEnableValidation = false;
for (uint32_t Idx; Idx < InstanceLayers.size(); ++Idx)
{
bEnableValidation = strcmp(InstanceLayers[Idx], "VK_LAYER_KHRONOS_validation") == 0;
if (bEnableValidation)
{
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, " VK_LAYER_KHRONOS_validation Validation Enabled");
break;
}
}
VkResult Result;
Result = vkCreateInstance(&createInfo, NULL, &Instance);
if (Result != VK_SUCCESS)
{
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, " Failed to Create VKInstance %d ", Result);
exit(-1);
}
/* Load VK_EXT_debug_report entry points in debug builds */
if (bEnableValidation)
{
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(vkGetInstanceProcAddr(Instance, "vkCreateDebugReportCallbackEXT"));
PFN_vkDebugReportMessageEXT vkDebugReportMessageEXT = reinterpret_cast<PFN_vkDebugReportMessageEXT>(vkGetInstanceProcAddr(Instance, "vkDebugReportMessageEXT"));
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(vkGetInstanceProcAddr(Instance, "vkDestroyDebugReportCallbackEXT"));
VkDebugReportCallbackCreateInfoEXT CallbackCreateInfo;
CallbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
CallbackCreateInfo.pNext = nullptr;
CallbackCreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
CallbackCreateInfo.pfnCallback = &VKValidationCallback;
CallbackCreateInfo.pUserData = nullptr;
/* Register the callback */
VkDebugReportCallbackEXT Callback;
Result = vkCreateDebugReportCallbackEXT(Instance, &CallbackCreateInfo, nullptr, &Callback);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, " Created Debug Hooks %d ", Result);
}
// Get the number of devices (GPUs) available.
uint32_t gpu_count = 0;
Result = vkEnumeratePhysicalDevices(Instance, &gpu_count, NULL);
if (Result != VK_SUCCESS)
{
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, " Failed to Enumerate Physical Devices 1 %d ", Result);
exit(-1);
}
// Allocate space and get the list of devices.
devices.resize(gpu_count);
Result = vkEnumeratePhysicalDevices(Instance, &gpu_count, devices.data());
if (Result != VK_SUCCESS)
{
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, " Failed to Enumerate Physical Devices 2 %d ", Result);
}
uint32_t queue_count = 0;
vkGetPhysicalDeviceQueueFamilyProperties(devices[0], &queue_count, nullptr);
std::vector<VkQueueFamilyProperties> queues(queue_count);
vkGetPhysicalDeviceQueueFamilyProperties(devices[0], &queue_count, queues.data());
uint32_t gfx_queue_idx = 0;
bool found = false;
for (unsigned int i = 0; i < queue_count; i++)
{
if (queues[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
gfx_queue_idx = i;
found = true;
break;
}
}
VkPhysicalDeviceFeatures PhysicalFeatures;
vkGetPhysicalDeviceFeatures(devices[0], &PhysicalFeatures);
PhysicalFeatures.shaderResourceResidency = VK_FALSE;
PhysicalFeatures.shaderResourceMinLod = VK_FALSE;
PhysicalFeatures.sparseBinding = VK_FALSE;
PhysicalFeatures.sparseResidencyBuffer = VK_FALSE;
PhysicalFeatures.sparseResidencyImage2D = VK_FALSE;
PhysicalFeatures.sparseResidencyImage3D = VK_FALSE;
PhysicalFeatures.sparseResidency2Samples = VK_FALSE;
PhysicalFeatures.sparseResidency4Samples = VK_FALSE;
PhysicalFeatures.sparseResidency8Samples = VK_FALSE;
PhysicalFeatures.sparseResidencyAliased = VK_FALSE;
VkDeviceQueueCreateInfo queueCreateInfo{};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = gfx_queue_idx;
queueCreateInfo.queueCount = queues[gfx_queue_idx].queueCount;
float* QueuePriorities = (float*)alloca(queues[gfx_queue_idx].queueCount * sizeof(float));
memset(QueuePriorities, 0, queues[gfx_queue_idx].queueCount * sizeof(float));
queueCreateInfo.pQueuePriorities = QueuePriorities;
VkDeviceCreateInfo device_info = {};
device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device_info.pNext = NULL;
device_info.queueCreateInfoCount = 1;
device_info.pQueueCreateInfos = &queueCreateInfo;
device_info.enabledLayerCount = 0;
device_info.ppEnabledLayerNames = NULL;
device_info.enabledExtensionCount = DeviceExtensions.size();
device_info.ppEnabledExtensionNames = DeviceExtensions.data();
device_info.pEnabledFeatures = &PhysicalFeatures;
Result = vkCreateDevice(devices[0], &device_info, NULL, &Device);
if (Result != VK_SUCCESS)
{
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, " Failed to Create Device %d ", Result);
}
vkCreateRenderPass2 = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(Device, "vkCreateRenderPass2KHR");
if (vkCreateRenderPass2 == nullptr)
{
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Failed getting pointer to vkCreateRenderPass2 ");
}
}
void ShutDownDevice()
{
bInitialized = false;
if (Device == VK_NULL_HANDLE)
{
return;
}
if (PipelineCache != VK_NULL_HANDLE)
{
vkDestroyPipelineCache(Device, PipelineCache, nullptr);
PipelineCache = VK_NULL_HANDLE;
}
vkDestroyDevice(Device, nullptr);
vkDestroyInstance(Instance, nullptr);
}
struct GraphicsPipelineCreateInfo
{
VkPipelineCreateFlags PipelineCreateFlags;
uint32_t StageCount;
bool bHasVkPipelineVertexInputStateCreateInfo;
bool bHasVkPipelineInputAssemblyStateCreateInfo;
bool bHasVkPipelineTessellationStateCreateInfo;
bool bHasVkPipelineViewportStateCreateInfo;
bool bHasVkPipelineRasterizationStateCreateInfo;
bool bHasVkPipelineMultisampleStateCreateInfo;
bool bHasVkPipelineDepthStencilStateCreateInfo;
bool bHasVkPipelineColorBlendStateCreateInfo;
bool bHasVkPipelineDynamicStateCreateInfo;
uint32_t subpass;
};
#define COPY_FROM_BUFFER(Dst, Src, Offset, Size) \
memcpy(Dst, &Src[Offset], Size); \
Offset += Size;
void BufferToCharArray(std::vector<const char*>& CharArray, const uint8_t* MemoryStream, uint32_t& MemoryOffset)
{
uint32_t Count;
COPY_FROM_BUFFER(&Count, MemoryStream, MemoryOffset, sizeof(uint32_t));
for (uint32_t Idx = 0; Idx < Count; ++Idx)
{
uint32_t StrLength;
COPY_FROM_BUFFER(&StrLength, MemoryStream, MemoryOffset, sizeof(uint32_t));
CharArray.push_back((const char*)&MemoryStream[MemoryOffset]);
MemoryOffset += StrLength;
}
}
std::string CompileGFXPSO(const uint8_t* VS, uint64_t VSSize, const uint8_t* PS, uint64_t PSSize, const uint8_t* PSO, uint64_t PSOSize)
{
std::string errorLog;
uint32_t MemoryOffset = 0;
// Read extensions and layers
std::vector<const char*> InstanceLayers;
BufferToCharArray(InstanceLayers, PSO, MemoryOffset);
std::vector<const char*> InstanceExtensions;
BufferToCharArray(InstanceExtensions, PSO, MemoryOffset);
std::vector<const char*> DeviceExtensions;
BufferToCharArray(DeviceExtensions, PSO, MemoryOffset);
InitDevice(InstanceLayers, InstanceExtensions, DeviceExtensions);
// Free PSO Cache
VkResult Result;
GraphicsPipelineCreateInfo PipelineCreateInfo;
VkGraphicsPipelineCreateInfo CreateInfo;
//__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "CompileGFXPSO: VSSize %d, PSSize %d, PSOSize %d", (uint32_t)VSSize, (uint32_t)PSSize, (uint32_t)PSOSize);
if (bSinglePSOPerCache && PSOCacheData)
{
free(PSOCacheData);
PSOCacheSize = 0;
PSOCacheData = nullptr;
vkDestroyPipelineCache(Device, PipelineCache, nullptr);
PipelineCache = VK_NULL_HANDLE;
}
// Create PSO
COPY_FROM_BUFFER(&PipelineCreateInfo, PSO, MemoryOffset, sizeof(GraphicsPipelineCreateInfo));
memset(&CreateInfo, 0, sizeof(VkGraphicsPipelineCreateInfo));
CreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
CreateInfo.flags = PipelineCreateInfo.PipelineCreateFlags;
CreateInfo.stageCount = PipelineCreateInfo.StageCount;
CreateInfo.subpass = PipelineCreateInfo.subpass;
// FSR
bool bHasFSRCreateInfo = false;
COPY_FROM_BUFFER(&bHasFSRCreateInfo, PSO, MemoryOffset, sizeof(bool));
VkPipelineFragmentShadingRateStateCreateInfoKHR FSRCreateInfo;
if (bHasFSRCreateInfo)
{
COPY_FROM_BUFFER(&FSRCreateInfo, PSO, MemoryOffset, sizeof(VkPipelineFragmentShadingRateStateCreateInfoKHR));
FSRCreateInfo.pNext = nullptr;
CreateInfo.pNext = &FSRCreateInfo;
}
VkPipelineShaderStageCreateInfo ShaderStages[2];
// VkPipelineShaderStageCreateInfo
for (int32_t Idx = 0; Idx < PipelineCreateInfo.StageCount; ++Idx)
{
bool bHasSubGroupSizeInfo = false;
COPY_FROM_BUFFER(&bHasSubGroupSizeInfo, PSO, MemoryOffset, sizeof(bool));
void* PipelineShaderStageCreatePNext = nullptr;
if (bHasSubGroupSizeInfo)
{
PipelineShaderStageCreatePNext = (void*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkPipelineShaderStageRequiredSubgroupSizeCreateInfo);
}
COPY_FROM_BUFFER(&ShaderStages[Idx], PSO, MemoryOffset, sizeof(VkPipelineShaderStageCreateInfo));
uint32_t NameLength;
COPY_FROM_BUFFER(&NameLength, PSO, MemoryOffset, sizeof(uint32_t));
ShaderStages[Idx].pName = (const char*)&PSO[MemoryOffset];
ShaderStages[Idx].pNext = PipelineShaderStageCreatePNext;
MemoryOffset += NameLength;
}
CreateInfo.pStages = ShaderStages;
VkPipelineVertexInputStateCreateInfo VertexInputState;
if (PipelineCreateInfo.bHasVkPipelineVertexInputStateCreateInfo)
{
COPY_FROM_BUFFER(&VertexInputState, PSO, MemoryOffset, sizeof(VkPipelineVertexInputStateCreateInfo));
if (VertexInputState.vertexBindingDescriptionCount > 0)
{
uint32_t Length = VertexInputState.vertexBindingDescriptionCount * sizeof(VkVertexInputBindingDescription);
VertexInputState.pVertexBindingDescriptions = (VkVertexInputBindingDescription*)&PSO[MemoryOffset];
MemoryOffset += Length;
}
if (VertexInputState.vertexAttributeDescriptionCount > 0)
{
uint32_t Length = VertexInputState.vertexAttributeDescriptionCount * sizeof(VkVertexInputAttributeDescription);
VertexInputState.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription*)&PSO[MemoryOffset];
MemoryOffset += Length;
}
CreateInfo.pVertexInputState = &VertexInputState;
}
VkPipelineInputAssemblyStateCreateInfo InputAssemblyCreateInfo;
if (PipelineCreateInfo.bHasVkPipelineInputAssemblyStateCreateInfo)
{
COPY_FROM_BUFFER(&InputAssemblyCreateInfo, PSO, MemoryOffset, sizeof(VkPipelineInputAssemblyStateCreateInfo));
CreateInfo.pInputAssemblyState = &InputAssemblyCreateInfo;
}
VkPipelineTessellationStateCreateInfo TesselationCreateInfo;
if (PipelineCreateInfo.bHasVkPipelineTessellationStateCreateInfo)
{
COPY_FROM_BUFFER(&TesselationCreateInfo, PSO, MemoryOffset, sizeof(VkPipelineTessellationStateCreateInfo));
CreateInfo.pTessellationState = &TesselationCreateInfo;
}
VkPipelineViewportStateCreateInfo ViewportState;
if (PipelineCreateInfo.bHasVkPipelineViewportStateCreateInfo)
{
COPY_FROM_BUFFER(&ViewportState, PSO, MemoryOffset, sizeof(VkPipelineViewportStateCreateInfo));
uint32_t ViewportCount;
COPY_FROM_BUFFER(&ViewportCount, PSO, MemoryOffset, sizeof(uint32_t));
if (ViewportCount > 0)
{
ViewportState.pViewports = (VkViewport*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkViewport) * ViewportCount;
}
uint32_t ScissorCount;
COPY_FROM_BUFFER(&ScissorCount, PSO, MemoryOffset, sizeof(uint32_t));
if (ScissorCount > 0)
{
ViewportState.pScissors = (VkRect2D*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkRect2D) * ScissorCount;
}
CreateInfo.pViewportState = &ViewportState;
}
if (PipelineCreateInfo.bHasVkPipelineRasterizationStateCreateInfo)
{
CreateInfo.pRasterizationState = (VkPipelineRasterizationStateCreateInfo*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkPipelineRasterizationStateCreateInfo);
}
if (PipelineCreateInfo.bHasVkPipelineMultisampleStateCreateInfo)
{
CreateInfo.pMultisampleState = (VkPipelineMultisampleStateCreateInfo*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkPipelineMultisampleStateCreateInfo);
}
if (PipelineCreateInfo.bHasVkPipelineDepthStencilStateCreateInfo)
{
CreateInfo.pDepthStencilState = (VkPipelineDepthStencilStateCreateInfo*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkPipelineDepthStencilStateCreateInfo);
}
VkPipelineColorBlendStateCreateInfo ColorBlendState;
if (PipelineCreateInfo.bHasVkPipelineColorBlendStateCreateInfo)
{
COPY_FROM_BUFFER(&ColorBlendState, PSO, MemoryOffset, sizeof(VkPipelineColorBlendStateCreateInfo));
if (ColorBlendState.attachmentCount > 0)
{
ColorBlendState.pAttachments = (VkPipelineColorBlendAttachmentState*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkPipelineColorBlendAttachmentState) * ColorBlendState.attachmentCount;
}
CreateInfo.pColorBlendState = &ColorBlendState;
}
VkPipelineDynamicStateCreateInfo DynamicState;
if (PipelineCreateInfo.bHasVkPipelineDynamicStateCreateInfo)
{
COPY_FROM_BUFFER(&DynamicState, PSO, MemoryOffset, sizeof(VkPipelineDynamicStateCreateInfo));
if (DynamicState.dynamicStateCount > 0)
{
DynamicState.pDynamicStates = (VkDynamicState*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkDynamicState) * DynamicState.dynamicStateCount;
}
CreateInfo.pDynamicState = &DynamicState;
}
VkPipelineLayoutCreateInfo PipelineLayoutCreateInfo;
COPY_FROM_BUFFER(&PipelineLayoutCreateInfo, PSO, MemoryOffset, sizeof(VkPipelineLayoutCreateInfo));
VkDescriptorSetLayoutCreateInfo* DescriptorSetLayoutInfos = nullptr;
VkDescriptorSetLayout* DescriptorSetLayouts = nullptr;
if (PipelineLayoutCreateInfo.setLayoutCount > 0)
{
DescriptorSetLayoutInfos = new VkDescriptorSetLayoutCreateInfo[PipelineLayoutCreateInfo.setLayoutCount];
DescriptorSetLayouts = new VkDescriptorSetLayout[PipelineLayoutCreateInfo.setLayoutCount];
for (uint32_t Idx = 0; Idx < PipelineLayoutCreateInfo.setLayoutCount; ++Idx)
{
uint32_t SetBindingsCount;
COPY_FROM_BUFFER(&SetBindingsCount, PSO, MemoryOffset, sizeof(uint32_t));
DescriptorSetLayoutInfos[Idx].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
DescriptorSetLayoutInfos[Idx].pNext = nullptr;
DescriptorSetLayoutInfos[Idx].flags = 0;
DescriptorSetLayoutInfos[Idx].bindingCount = SetBindingsCount;
DescriptorSetLayoutInfos[Idx].pBindings = (VkDescriptorSetLayoutBinding*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkDescriptorSetLayoutBinding) * SetBindingsCount;
vkCreateDescriptorSetLayout(Device, &DescriptorSetLayoutInfos[Idx], nullptr, &DescriptorSetLayouts[Idx]);
}
PipelineLayoutCreateInfo.pSetLayouts = DescriptorSetLayouts;
}
VkPipelineLayout PipelineLayout;
Result = vkCreatePipelineLayout(Device, &PipelineLayoutCreateInfo, nullptr, &PipelineLayout);
if (Result != VK_SUCCESS)
{
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, " vkCreatePipelineLayout Failed %d ", Result);
exit(-1);
}
CreateInfo.layout = PipelineLayout;
VkRenderPass RenderPass;
bool bUseRenderPass2;
COPY_FROM_BUFFER(&bUseRenderPass2, PSO, MemoryOffset, sizeof(bool));
if (bUseRenderPass2)
{
// Render pass
VkRenderPassCreateInfo2KHR RenderPassCreateInfo;
COPY_FROM_BUFFER(&RenderPassCreateInfo, PSO, MemoryOffset, sizeof(VkRenderPassCreateInfo2KHR));
// Check for VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT
bool bHasCreateInfoNext = false;
COPY_FROM_BUFFER(&bHasCreateInfoNext, PSO, MemoryOffset, sizeof(bool));
if (bHasCreateInfoNext)
{
RenderPassCreateInfo.pNext = &PSO[MemoryOffset];
MemoryOffset += sizeof(VkRenderPassFragmentDensityMapCreateInfoEXT);
}
if (RenderPassCreateInfo.attachmentCount > 0)
{
RenderPassCreateInfo.pAttachments = (VkAttachmentDescription2KHR*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkAttachmentDescription2KHR) * RenderPassCreateInfo.attachmentCount;
}
if (RenderPassCreateInfo.dependencyCount > 0)
{
RenderPassCreateInfo.pDependencies = (VkSubpassDependency2KHR*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkSubpassDependency2KHR) * RenderPassCreateInfo.dependencyCount;
}
VkSubpassDescription2KHR* SubpassDescriptions = new VkSubpassDescription2KHR[RenderPassCreateInfo.subpassCount];
std::vector<VkFragmentShadingRateAttachmentInfoKHR> FSRAttachmentInfos;
std::vector<VkAttachmentReference2KHR> DepthStencilAttachments;
FSRAttachmentInfos.resize(RenderPassCreateInfo.subpassCount);
DepthStencilAttachments.resize(RenderPassCreateInfo.subpassCount);
for (uint32_t Idx = 0; Idx < RenderPassCreateInfo.subpassCount; ++Idx)
{
COPY_FROM_BUFFER(&SubpassDescriptions[Idx], PSO, MemoryOffset, sizeof(VkSubpassDescription2KHR));
// Add additional pNext structs
// FSR
bool bHasFSRAttachmentInfo = false;
COPY_FROM_BUFFER(&bHasFSRAttachmentInfo, PSO, MemoryOffset, sizeof(bool));;
if (bHasFSRAttachmentInfo)
{
FSRAttachmentInfos[Idx] = VkFragmentShadingRateAttachmentInfoKHR();
auto& FSRAttachmentInfo = FSRAttachmentInfos[Idx];
FSRAttachmentInfo.pNext = nullptr;
FSRAttachmentInfo.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
FSRAttachmentInfo.pFragmentShadingRateAttachment = (VkAttachmentReference2KHR*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkAttachmentReference2KHR);
FSRAttachmentInfo.shadingRateAttachmentTexelSize = *(VkExtent2D*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkExtent2D);
SubpassDescriptions[Idx].pNext = &FSRAttachmentInfo;
}
if (SubpassDescriptions[Idx].colorAttachmentCount > 0)
{
SubpassDescriptions[Idx].pColorAttachments = (VkAttachmentReference2KHR*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkAttachmentReference2KHR) * SubpassDescriptions[Idx].colorAttachmentCount;
}
if (SubpassDescriptions[Idx].inputAttachmentCount > 0)
{
SubpassDescriptions[Idx].pInputAttachments = (VkAttachmentReference2KHR*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkAttachmentReference2KHR) * SubpassDescriptions[Idx].inputAttachmentCount;
}
bool bHasResolveAttachment;
COPY_FROM_BUFFER(&bHasResolveAttachment, PSO, MemoryOffset, sizeof(bool));
if (bHasResolveAttachment)
{
if (SubpassDescriptions[Idx].colorAttachmentCount > 0)
{
SubpassDescriptions[Idx].pResolveAttachments = (VkAttachmentReference2KHR*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkAttachmentReference2KHR) * SubpassDescriptions[Idx].colorAttachmentCount;
}
}
bool bHasDepthStencilAttachment;
COPY_FROM_BUFFER(&bHasDepthStencilAttachment, PSO, MemoryOffset, sizeof(bool));
if (bHasDepthStencilAttachment)
{
bool bHasStencilLayout;
COPY_FROM_BUFFER(&bHasStencilLayout, PSO, MemoryOffset, sizeof(bool));
void* pDepthStencilAttachmentPNext = nullptr;
if(bHasStencilLayout)
{
pDepthStencilAttachmentPNext = (void*) & PSO[MemoryOffset];
MemoryOffset += sizeof(VkAttachmentReferenceStencilLayout);
}
DepthStencilAttachments[Idx] = *(VkAttachmentReference2KHR*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkAttachmentReference2KHR);
auto& DepthStencilAttachment = DepthStencilAttachments.back();
DepthStencilAttachments[Idx].pNext = pDepthStencilAttachmentPNext;
SubpassDescriptions[Idx].pDepthStencilAttachment = &DepthStencilAttachments[Idx];
}
}
RenderPassCreateInfo.pSubpasses = SubpassDescriptions;
if (RenderPassCreateInfo.correlatedViewMaskCount > 0)
{
RenderPassCreateInfo.pCorrelatedViewMasks = (uint32_t*)&PSO[MemoryOffset];
MemoryOffset += sizeof(uint32_t) * RenderPassCreateInfo.correlatedViewMaskCount;
}
Result = vkCreateRenderPass2(Device, &RenderPassCreateInfo, nullptr, &RenderPass);
if (Result != VK_SUCCESS)
{
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, " vkCreateRenderPass2 Failed %d ", Result);
exit(-1);
}
delete[] SubpassDescriptions;
}
else
{
// Render pass
VkRenderPassCreateInfo RenderPassCreateInfo;
COPY_FROM_BUFFER(&RenderPassCreateInfo, PSO, MemoryOffset, sizeof(VkRenderPassCreateInfo));
// Check for VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT
bool bHasCreateInfoNext = false;
COPY_FROM_BUFFER(&bHasCreateInfoNext, PSO, MemoryOffset, sizeof(bool));
if (bHasCreateInfoNext)
{
RenderPassCreateInfo.pNext = &PSO[MemoryOffset];
MemoryOffset += sizeof(VkRenderPassFragmentDensityMapCreateInfoEXT);
}
if (RenderPassCreateInfo.attachmentCount > 0)
{
RenderPassCreateInfo.pAttachments = (VkAttachmentDescription*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkAttachmentDescription) * RenderPassCreateInfo.attachmentCount;
}
if (RenderPassCreateInfo.dependencyCount > 0)
{
RenderPassCreateInfo.pDependencies = (VkSubpassDependency*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkSubpassDependency) * RenderPassCreateInfo.dependencyCount;
}
VkSubpassDescription* SubpassDescriptions = new VkSubpassDescription[RenderPassCreateInfo.subpassCount];
for (uint32_t Idx = 0; Idx < RenderPassCreateInfo.subpassCount; ++Idx)
{
COPY_FROM_BUFFER(&SubpassDescriptions[Idx], PSO, MemoryOffset, sizeof(VkSubpassDescription));
if (SubpassDescriptions[Idx].colorAttachmentCount > 0)
{
SubpassDescriptions[Idx].pColorAttachments = (VkAttachmentReference*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkAttachmentReference) * SubpassDescriptions[Idx].colorAttachmentCount;
}
if (SubpassDescriptions[Idx].inputAttachmentCount > 0)
{
SubpassDescriptions[Idx].pInputAttachments = (VkAttachmentReference*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkAttachmentReference) * SubpassDescriptions[Idx].inputAttachmentCount;
}
bool bHasResolveAttachment;
COPY_FROM_BUFFER(&bHasResolveAttachment, PSO, MemoryOffset, sizeof(bool));
if (bHasResolveAttachment)
{
if (SubpassDescriptions[Idx].colorAttachmentCount > 0)
{
SubpassDescriptions[Idx].pResolveAttachments = (VkAttachmentReference*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkAttachmentReference) * SubpassDescriptions[Idx].colorAttachmentCount;
}
}
bool bHasDepthStencilAttachment;
COPY_FROM_BUFFER(&bHasDepthStencilAttachment, PSO, MemoryOffset, sizeof(bool));
if (bHasDepthStencilAttachment)
{
SubpassDescriptions[Idx].pDepthStencilAttachment = (VkAttachmentReference*)&PSO[MemoryOffset];
MemoryOffset += sizeof(VkAttachmentReference);
}
}
RenderPassCreateInfo.pSubpasses = SubpassDescriptions;
Result = vkCreateRenderPass(Device, &RenderPassCreateInfo, nullptr, &RenderPass);
if (Result != VK_SUCCESS)
{
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, " vkCreateRenderPass2 Failed %d ", Result);
exit(-1);
}
delete[] SubpassDescriptions;
}
CreateInfo.renderPass = RenderPass;
VkPipeline Pipeline;
VkShaderModule VSModule;
VkShaderModule PSModule;
{
VkShaderModuleCreateInfo ModuleCreateInfo;
ModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
ModuleCreateInfo.pCode = (const uint32_t *)VS;
ModuleCreateInfo.codeSize = VSSize;
ModuleCreateInfo.flags = 0;
ModuleCreateInfo.pNext = nullptr;
Result = vkCreateShaderModule(Device, &ModuleCreateInfo, nullptr, &VSModule);
if (Result != VK_SUCCESS)
{
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, " vkCreateShaderModule VS Failed %d ", Result);
exit(-1);
}
ShaderStages[0].module = VSModule;
}
{
VkShaderModuleCreateInfo ModuleCreateInfo;
ModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
ModuleCreateInfo.pCode = (const uint32_t*)PS;
ModuleCreateInfo.codeSize = PSSize;
ModuleCreateInfo.flags = 0;
ModuleCreateInfo.pNext = nullptr;
Result = vkCreateShaderModule(Device, &ModuleCreateInfo, nullptr, &PSModule);
if (Result != VK_SUCCESS)
{
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, " vkCreateShaderModule PS Failed %d ", Result);
exit(-1);
}
ShaderStages[1].module = PSModule;
}
if (PipelineCache == VK_NULL_HANDLE)
{
VkPipelineCacheCreateInfo PipelineCacheCreateInfo;
memset(&PipelineCacheCreateInfo, 0, sizeof(VkPipelineCacheCreateInfo));
PipelineCacheCreateInfo.flags = 0;
PipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
Result = vkCreatePipelineCache(Device, &PipelineCacheCreateInfo, nullptr, &PipelineCache);
if (Result != VK_SUCCESS)
{
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, " vkCreatePipelineCache Failed %d ", Result);
exit(-1);
}
}
Result = vkCreateGraphicsPipelines(Device, PipelineCache, 1, &CreateInfo, nullptr, &Pipeline);
if (Result != VK_SUCCESS)
{
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, " vkCreateGraphicsPipelines Failed %d ", Result);
exit(-1);
}
for (uint32_t Idx = 0; Idx < PipelineLayoutCreateInfo.setLayoutCount; ++Idx)
{
vkDestroyDescriptorSetLayout(Device, DescriptorSetLayouts[Idx], nullptr);
}
vkDestroyShaderModule(Device, VSModule, nullptr);
vkDestroyShaderModule(Device, PSModule, nullptr);
vkDestroyRenderPass(Device, RenderPass, nullptr);
vkDestroyPipelineLayout(Device, PipelineLayout, nullptr);
vkDestroyPipeline(Device, Pipeline, nullptr);
if (DescriptorSetLayoutInfos)
{
delete[] DescriptorSetLayoutInfos;
}
if (DescriptorSetLayouts)
{
delete[] DescriptorSetLayouts;
}
return errorLog;
}
void GetPSOBinary(char* & BinaryData, uint32_t& Size, bool bCompileThread)
{
if (bCompileThread && !bSinglePSOPerCache)
{
Size = 0;
BinaryData = nullptr;
return;
}
if (PSOCacheData)
{
free(PSOCacheData);
PSOCacheData = nullptr;
PSOCacheSize = 0;
}
PSOCacheSize = 0;
VkResult Result = vkGetPipelineCacheData(Device, PipelineCache, &PSOCacheSize, nullptr);
if (Result != VK_SUCCESS)
{
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, " vkGetPipelineCacheData 1 Failed %d ", Result);
exit(-1);
}
PSOCacheData = (char*)malloc(PSOCacheSize);
Result = vkGetPipelineCacheData(Device, PipelineCache, &PSOCacheSize, PSOCacheData);
if (Result != VK_SUCCESS)
{
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, " vkGetPipelineCacheData 2 Failed %d ", Result);
exit(-1);
}
Size = PSOCacheSize;
BinaryData = PSOCacheData;
}
};
JNI_METHOD void Java_com_epicgames_unreal_psoservices_PSOProgramService_InitVKDevice(JNIEnv* jenv, jobject thiz)
{
}
JNI_METHOD void Java_com_epicgames_unreal_psoservices_PSOProgramService_ShutdownVKDevice(JNIEnv* jenv, jobject thiz)
{
FVulkanPSOCompiler::Get().ShutDownDevice();
}
JNI_METHOD jobject Java_com_epicgames_unreal_psoservices_PSOProgramService_CompileVKGFXPSO(JNIEnv* jenv, jobject thiz, jbyteArray jVS, jbyteArray jPS, jbyteArray jPSO)
{
const uint8_t* VS = (const uint8_t*)jenv->GetByteArrayElements(jVS, nullptr);
uint64_t VSSize = jenv->GetArrayLength(jVS);
const uint8_t* PS = (const uint8_t*)jenv->GetByteArrayElements(jPS, nullptr);
uint64_t PSSize = jenv->GetArrayLength(jPS);
const uint8_t* PSO = (const uint8_t*)jenv->GetByteArrayElements(jPSO, nullptr);
uint64_t PSOSize = jenv->GetArrayLength(jPSO);
;
FVulkanPSOCompiler::Get().CompileGFXPSO(VS, VSSize, PS, PSSize, PSO, PSOSize);
char* BinaryData;
uint32_t Size = 0;
FVulkanPSOCompiler::Get().GetPSOBinary(BinaryData, Size, true);
jbyteArray Data = jenv->NewByteArray(Size);
if (Size > 0)
{
jenv->SetByteArrayRegion(Data, 0, Size, (jbyte*)BinaryData);
}
return Data;
}
JNI_METHOD jobject Java_com_epicgames_unreal_psoservices_PSOProgramService_GetVKPSOCacheData(JNIEnv* jenv, jobject thiz)
{
char* BinaryData;
uint32_t Size = 0;
FVulkanPSOCompiler::Get().GetPSOBinary(BinaryData, Size, false);
jbyteArray Data = jenv->NewByteArray(Size);
if (Size > 0)
{
jenv->SetByteArrayRegion(Data, 0, Size, (jbyte*)BinaryData);
}
return Data;
}