// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Graphics/GPUPipelineState.h"
#include "GPUDeviceVulkan.h"
#include "DescriptorSetVulkan.h"
#include "CmdBufferVulkan.h"
#if GRAPHICS_API_VULKAN
class PipelineLayoutVulkan;
class ComputePipelineStateVulkan
{
private:
GPUDeviceVulkan* _device;
VkPipeline _handle;
PipelineLayoutVulkan* _layout;
public:
///
/// Initializes a new instance of the class.
///
/// The graphics device.
/// The pipeline object.
/// The pipeline layout.
ComputePipelineStateVulkan(GPUDeviceVulkan* device, VkPipeline pipeline, PipelineLayoutVulkan* layout);
///
/// Finalizes an instance of the class.
///
~ComputePipelineStateVulkan();
public:
///
/// The cached shader descriptor infos for compute shader.
///
const SpirvShaderDescriptorInfo* DescriptorInfo;
DescriptorSetWriteContainerVulkan DSWriteContainer;
DescriptorSetWriterVulkan DSWriter;
const DescriptorSetLayoutVulkan* DescriptorSetsLayout = nullptr;
TypedDescriptorPoolSetVulkan* CurrentTypedDescriptorPoolSet = nullptr;
Array DescriptorSetHandles;
inline bool AcquirePoolSet(CmdBufferVulkan* cmdBuffer)
{
// Pipeline state has no current descriptor pools set or set owner is not current - acquire a new pool set
DescriptorPoolSetContainerVulkan* cmdBufferPoolSet = cmdBuffer->GetDescriptorPoolSet();
if (CurrentTypedDescriptorPoolSet == nullptr || CurrentTypedDescriptorPoolSet->GetOwner() != cmdBufferPoolSet)
{
ASSERT(cmdBufferPoolSet);
CurrentTypedDescriptorPoolSet = cmdBufferPoolSet->AcquireTypedPoolSet(*DescriptorSetsLayout);
return true;
}
return false;
}
inline bool AllocateDescriptorSets()
{
ASSERT(CurrentTypedDescriptorPoolSet);
return CurrentTypedDescriptorPoolSet->AllocateDescriptorSets(*DescriptorSetsLayout, DescriptorSetHandles.Get());
}
Array DynamicOffsets;
public:
void Bind(CmdBufferVulkan* cmdBuffer)
{
vkCmdBindDescriptorSets(
cmdBuffer->GetHandle(),
VK_PIPELINE_BIND_POINT_COMPUTE,
GetLayout()->GetHandle(),
0,
DescriptorSetHandles.Count(),
DescriptorSetHandles.Get(),
DynamicOffsets.Count(),
DynamicOffsets.Get());
}
public:
VkPipeline GetHandle() const
{
return _handle;
}
PipelineLayoutVulkan* GetLayout() const
{
return _layout;
}
};
///
/// Graphics pipeline state object for Vulkan backend.
///
class GPUPipelineStateVulkan : public GPUResourceVulkan
{
private:
Dictionary _pipelines;
VkGraphicsPipelineCreateInfo _desc;
VkPipelineShaderStageCreateInfo _shaderStages[ShaderStage_Count - 1];
VkPipelineInputAssemblyStateCreateInfo _descInputAssembly;
VkPipelineTessellationStateCreateInfo _descTessellation;
VkPipelineViewportStateCreateInfo _descViewport;
VkPipelineDynamicStateCreateInfo _descDynamic;
VkDynamicState _dynamicStates[3];
VkPipelineMultisampleStateCreateInfo _descMultisample;
VkPipelineDepthStencilStateCreateInfo _descDepthStencil;
VkPipelineRasterizationStateCreateInfo _descRasterization;
VkPipelineColorBlendStateCreateInfo _descColorBlend;
VkPipelineColorBlendAttachmentState _descColorBlendAttachments[GPU_MAX_RT_BINDED];
PipelineLayoutVulkan* _layout;
public:
///
/// Initializes a new instance of the class.
///
/// The graphics device.
GPUPipelineStateVulkan(GPUDeviceVulkan* device);
public:
///
/// The bitmask of stages that exist in this pipeline.
///
uint32 UsedStagesMask;
bool BlendEnable;
///
/// The bitmask of stages that have descriptors.
///
uint32 HasDescriptorsPerStageMask;
///
/// The cached shader bindings per stage.
///
const ShaderBindings* ShaderBindingsPerStage[DescriptorSet::GraphicsStagesCount];
///
/// The cached shader descriptor infos per stage.
///
const SpirvShaderDescriptorInfo* DescriptorInfoPerStage[DescriptorSet::GraphicsStagesCount];
const VkPipelineVertexInputStateCreateInfo* GetVertexInputState() const
{
return _desc.pVertexInputState;
}
DescriptorSetWriteContainerVulkan DSWriteContainer;
DescriptorSetWriterVulkan DSWriter[DescriptorSet::GraphicsStagesCount];
const DescriptorSetLayoutVulkan* DescriptorSetsLayout = nullptr;
TypedDescriptorPoolSetVulkan* CurrentTypedDescriptorPoolSet = nullptr;
Array DescriptorSetHandles;
inline bool AcquirePoolSet(CmdBufferVulkan* cmdBuffer)
{
// Pipeline state has no current descriptor pools set or set owner is not current - acquire a new pool set
DescriptorPoolSetContainerVulkan* cmdBufferPoolSet = cmdBuffer->GetDescriptorPoolSet();
if (CurrentTypedDescriptorPoolSet == nullptr || CurrentTypedDescriptorPoolSet->GetOwner() != cmdBufferPoolSet)
{
ASSERT(cmdBufferPoolSet);
CurrentTypedDescriptorPoolSet = cmdBufferPoolSet->AcquireTypedPoolSet(*DescriptorSetsLayout);
return true;
}
return false;
}
inline bool AllocateDescriptorSets()
{
ASSERT(CurrentTypedDescriptorPoolSet);
return CurrentTypedDescriptorPoolSet->AllocateDescriptorSets(*DescriptorSetsLayout, DescriptorSetHandles.Get());
}
Array DynamicOffsets;
public:
void Bind(CmdBufferVulkan* cmdBuffer)
{
vkCmdBindDescriptorSets(
cmdBuffer->GetHandle(),
VK_PIPELINE_BIND_POINT_GRAPHICS,
GetLayout()->GetHandle(),
0,
DescriptorSetHandles.Count(),
DescriptorSetHandles.Get(),
DynamicOffsets.Count(),
DynamicOffsets.Get());
}
///
/// Gets the Vulkan pipeline layout for this pipeline state.
///
/// The layout.
PipelineLayoutVulkan* GetLayout();
///
/// Gets the Vulkan graphics pipeline object for the given rendering state. Uses depth buffer and render targets formats and multi-sample levels to setup a proper PSO. Uses caching.
///
/// The render pass.
/// Vulkan graphics pipeline object.
VkPipeline GetState(RenderPassVulkan* renderPass);
public:
// [GPUPipelineState]
bool IsValid() const final override;
bool Init(const Description& desc) final override;
protected:
// [GPUResourceVulkan]
void OnReleaseGPU() override;
};
#endif