Files
funnygame/materialsystem/vulkan/vulkan_state.h

497 lines
15 KiB
C++

#ifndef VULKAN_STATE_H
#define VULKAN_STATE_H
#include "shadercompiler/icompiler.h"
#include "volk.h"
#include "vk_mem_alloc.h"
#include "tier0/platform.h"
#include "tier1/utlvector.h"
#include "tier1/utlstring.h"
#include "tier2/iappsystem.h"
#include "materialsystem/imaterialsystem.h"
#include "materialsystem/shaderinternals.h"
#include "materialsystem/vulkan_shadermeta.h"
#define REQUIRED_EXTENSION(ext) bool bIsSupported_##ext;
#define OPTIONAL_EXTENSION(ext) bool bIsSupported_##ext;
extern struct SupportedVulkanExtensions_t
{
#include "device_extensions.h"
} g_vkAvailableExtensions;
#undef REQUIRED_EXTENSION
#undef OPTIONAL_EXTENSION
#define FRAMES_IN_FLIGHT 2
enum EVulkanCommandType
{
COMMAND_TYPE_GENERAL,
COMMAND_TYPE_BEGIN,
COMMAND_TYPE_DRAW,
COMMAND_TYPE_END,
};
enum EVulkanCommandParameterType
{
VULKAN_PARAMETER_TYPE_UINT32,
VULKAN_PARAMETER_TYPE_FLOAT,
VULKAN_PARAMETER_TYPE_BUFFER,
VULKAN_PARAMETER_TYPE_IMAGE,
};
enum EDependencyMode
{
DEPENDENCY_MODE_JUST_CREATED,
DEPENDENCY_MODE_SHADER_IMAGE_READ,
DEPENDENCY_MODE_SHADER_BUFFER_READ,
DEPENDENCY_MODE_SHADER_IMAGE_WRITE,
DEPENDENCY_MODE_SHADER_BUFFER_WRITE,
DEPENDENCY_MODE_SHADER_ACCELERATION_STRUCTURE,
DEPENDENCY_MODE_DRAWCALL_VERTEX_BUFFER,
DEPENDENCY_MODE_DRAWCALL_INDEX_BUFFER,
DEPENDENCY_MODE_DRAWCALL_OUTPUT_IMAGE,
DEPENDENCY_MODE_DRAWCALL_OUTPUT_DEPTH_IMAGE,
DEPENDENCY_MODE_DRAWCALL_INPUT_IMAGE,
DEPENDENCY_MODE_DRAWCALL_MIXED_IMAGE,
DEPENDENCY_MODE_BUFFER_SOURCE,
DEPENDENCY_MODE_IMAGE_SOURCE,
DEPENDENCY_MODE_IMAGE_DESTINATION,
DEPENDENCY_MODE_BUFFER_DESTINATION,
DEPENDENCY_MODE_BLIT_IMAGE_SOURCE,
DEPENDENCY_MODE_BLIT_IMAGE_DESTINATION,
DEPENDENCY_MODE_COLOR_CLEAR_SOURCE,
DEPENDENCY_MODE_COLOR_CLEAR_DESTINATION,
DEPENDENCY_MODE_ALL_COMMANDS,
DEPENDENCY_MODE_IMAGE_PRESENT,
DEPENDENCY_MODE_NEXT_STAGE,
DEPENDENCY_MODE_COUNT,
};
struct VulkanCommandDepenency_t {
IRenderingObject *m_pObject;
EDependencyMode m_eDependencyMode;
};
struct VulkanCommandSwapchainDepenency_t {
IRenderingObject **m_ppObjects;
EDependencyMode m_eDependencyMode;
};
struct VulkanCommandParameter_t
{
const char *m_szName;
const EVulkanCommandParameterType m_eParameterType;
union {
uint32_t uint32_Data;
IImage *pImageData;
};
};
abstract_class CVkCommand
{
public:
virtual void Execute( VkCommandBuffer hCommandBuffer, int iCurrentFrame ) = 0;
virtual ~CVkCommand() = default;
//virtual const char *GetName();
CUtlVector<VulkanCommandDepenency_t> m_dependencies = {};
CUtlVector<VulkanCommandSwapchainDepenency_t> m_swapchainDependencies = {};
EVulkanCommandType m_eType;
void AddDependency( IRenderingObject *pObject, EDependencyMode eDependencyMode );
void AddSwapchainDependency( IRenderingObject **ppObjects, EDependencyMode eDependencyMode );
};
class IVkCommandBufferManager;
abstract_class IVkCommandBuffer
{
public:
virtual void SetVulkanHandlers( VkDevice hDevice, IVkCommandBufferManager *pManager ) = 0;
virtual void AddCommand( CVkCommand *pCommand ) = 0;
virtual void Reset() = 0;
virtual void Submit( int iFrameIndex = 0 ) = 0;
virtual void Render() = 0;
};
typedef CVkCommand *(*fnCreateVulkanCommand_t)();
abstract_class IVkCommandBufferManager: public IAppSystem
{
public:
virtual void SetVulkanHandlers( VkInstance hInstance, VkDevice hDevice ) = 0;
virtual IVkCommandBuffer *CreateCommandBuffer() = 0;
virtual CVkCommand *CreateCommand( const char *szName ) = 0;
virtual CUtlVector<VkCommandBuffer> &GetVulkanCommands() = 0;
virtual void FreeCommandBufferWithCommands(IVkCommandBuffer* pCommandBuffer) = 0;
virtual void RenderingFinished() = 0;
};
#define VULKAN_COMMAND_BUFFER_MANAGER_INTERFACE_NAME "VulkanCommandBufferManager"
class CVkCommandRegistry
{
public:
CVkCommandRegistry( const char *szName, fnCreateVulkanCommand_t pfnCreate );
};
#define CREATE_COMMAND(cb, name) \
(CVk##name##Command*)cb->CreateCommand(#name)
#define BEGIN_VULKAN_COMMAND( name ) \
class CVk##name##Command : public CVkCommand \
{ \
public: \
virtual void Execute( VkCommandBuffer hCommandBuffer, int iCurrentFrame ) override; \
#define END_VULKAN_COMMAND( name ) \
}; \
#define DECLARE_VULKAN_COMMAND(name) \
CVkCommand *_VulkanCommandCreate_##name() { return new CVk##name##Command; } \
CVkCommandRegistry _VulkanCommandRegistry_##name( #name, _VulkanCommandCreate_##name ); \
void CVk##name##Command::Execute( VkCommandBuffer hCommandBuffer, int iCurrentFrame ) \
#undef __cplusplus
#include "vulkan/vk_enum_string_helper.h"
#define __cplusplus 202400L
#define VULKAN_RESULT_PRINT(r, func) \
if (r != VK_SUCCESS) \
Plat_FatalErrorFunc(#func " failed: %s\n", string_VkResult(r))
class CVkImage: public IImage
{
public:
CVkImage();
CVkImage( uint32_t nWidth, uint32_t nHeight, uint32_t nDepth, EImageFormat eFormat, EMultisampleType eMultisampleType, EImageType eImageType, VkImageUsageFlagBits eUsage );
~CVkImage();
virtual void SetDebugName( const char *szName ) override;
virtual uint32_t GetImageWidth() override;
virtual uint32_t GetImageHeight() override;
virtual EImageFormat GetImageFormat() override;
virtual EMultisampleType GetMultisampleType() override;
void CreateImage( uint32_t nWidth, uint32_t nHeight, EImageFormat eFormat, EMultisampleType eMultisampleType, VkImageUsageFlagBits eUsage );
void CreateImageView();
static VkImageViewType GetImageViewType( enum EImageType eImageType );
static VkFormat GetImageFormat( enum EImageFormat eImageFormat );
static VkSampleCountFlagBits GetMultisampling( enum EMultisampleType eImageFormat );
uint32_t m_nWidth;
uint32_t m_nHeight;
EImageFormat m_eFormat;
EMultisampleType m_eMultisampleType;
EImageType m_eImageType;
VkImage m_image;
VkImageView m_imageView;
VmaAllocation m_allocation;
VkImageSubresourceRange m_range;
VkImageLayout m_ePreferredLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkImageLayout m_eImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
EDependencyMode m_eLastUsage = DEPENDENCY_MODE_JUST_CREATED;
};
class CVkBuffer: public IBuffer
{
public:
CVkBuffer( uint32_t nSize, VkBufferUsageFlags2 eUsage, uint32_t nAlignment );
~CVkBuffer();
virtual void SetDebugName( const char *szName ) override;
virtual void Lock() override;
virtual void Unlock() override;
virtual void *Map() override;
virtual void Unmap() override;
virtual uint32_t GetSize() override;
VmaAllocation m_allocation;
VkBuffer m_buffer;
VkDescriptorType m_eDescriptorType;
VkDeviceAddress m_address;
uint32_t m_nSize;
};
class CVkPipelineLibrary
{
public:
virtual void Build() = 0;
VkPipeline m_hPipeline = NULL;
VkDevice m_hDevice;
};
#define BEGIN_DEFINE_PIPELINE_LIBRARY(name) \
class CVk##name##PipelineLibrary: public CVkPipelineLibrary \
{ \
public: \
virtual void Build() override; \
#define END_DEFINE_PIPELINE_LIBRARY() \
};
extern VkPipelineLayout g_pLibraryEmptyLayout;
#define BEGIN_BUILD_PIPELINE_LIBRARY(name) \
void CVk##name##PipelineLibrary::Build() \
{ \
VkGraphicsPipelineCreateInfo pipeline = {}; \
VkGraphicsPipelineLibraryCreateInfoEXT library = {}; \
pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; \
library.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT; \
pipeline.pNext = &library; \
pipeline.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR | VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT; \
pipeline.layout = g_pLibraryEmptyLayout;
#define END_BUILD_PIPELINE_LIBRARY() \
vkCreateGraphicsPipelines(m_hDevice, NULL, 1, &pipeline, NULL, &m_hPipeline); \
}
class CVkShader : public IShader
{
public:
virtual uint32_t GetResourceByName( const char *szName ) override;
virtual void AddLayout( int iIndex, int iStride ) override;
virtual void AddAttribute( int iBufferIndex, int iLocation, EVertexFormat eFormat, int iOffset ) override;
virtual void SetTopology( ETopologyMode eTopology ) override;
virtual void AddOutputImage( int iImageIndex, EImageFormat eFormat ) override;
virtual void SetDepthImage( EImageFormat eFormat ) override;
virtual void SetMultisampling( EMultisampleType eFormat ) override;
virtual void DisablePixelShader( bool bDisable ) override;
virtual void Build() override;
VkPipeline m_hPipeline = NULL;
VkPipelineLayout m_hPipelineLayout;
CUtlVector<CVkPipelineLibrary*> m_libraries;
VkDevice m_hDevice;
CCompiledShader m_shader;
CUtlVector<VkDescriptorSetLayout> m_setLayouts;
CUtlVector<VulkanDescriptor_t> m_bindings;
private:
CUtlVector<VkVertexInputBindingDescription> m_layouts;
CUtlVector<VkVertexInputAttributeDescription> m_attributes;
CUtlVector<VkFormat> m_eFormats;
EMultisampleType m_eMultiSampling;
VkFormat m_eDepthFormat;
bool m_bIsFragmentEnabled;
};
class CVkComputeShader : public IComputeShader
{
public:
virtual void Build() override;
void BuildCompute();
void BuildTrace();
VkDevice m_hDevice;
CCompiledShader m_shader;
VkPipeline m_hPipeline = NULL;
VkPipelineLayout m_hPipelineLayout;
CUtlVector<VkDescriptorSetLayout> m_setLayouts;
CUtlVector<VulkanDescriptor_t> m_bindings;
private:
struct ShaderBinding_t
{
CUtlString m_szName;
CCompiledShader m_shader;
};
CUtlVector<ShaderBinding_t> m_callableShaders = {};
};
class CVkRayTracingShader : public IRayTracingShader
{
public:
virtual uint32_t GetMissShaderBinding( const char *szName ) override;
virtual uint32_t GetClosestHitShaderBinding( const char *szName ) override;
virtual uint32_t GetCallableShaderBinding( const char *szName ) override;
virtual void AddShader( const char *szName, const char *szPath ) override;
virtual void RemoveShader( const char *szName ) override;
virtual void Build() override;
void BuildCompute();
void BuildTrace();
VkDevice m_hDevice;
CCompiledShader m_shader;
VkPipeline m_hPipeline = NULL;
VkPipelineLayout m_hPipelineLayout;
CUtlVector<VkDescriptorSetLayout> m_setLayouts;
CUtlVector<VulkanDescriptor_t> m_bindings;
private:
struct ShaderBinding_t
{
CUtlString m_szName;
CCompiledShader m_shader;
};
CUtlVector<ShaderBinding_t> m_callableShaders = {};
};
#define MAX_TEXTURES 4096
class CVkTextureArray: public ITextureArray
{
public:
~CVkTextureArray();
CVkTextureArray();
virtual void Build() override;
virtual void SetDebugName( const char *szName ) override;
virtual uint32_t LoadTexture( const char *szPath ) override;
virtual uint32_t GetTextureID( const char *szPath ) override;
virtual void UnloadTexture( uint32_t uTextureID ) override;
void Frame();
uint32_t CreateTexture( uint32_t i, const char *szPath );
VkDevice m_hDevice;
IRenderContext *m_pRenderContext;
IVkCommandBufferManager *m_pCommandBufferManager;
VkSampler m_hSampler;
CVkImage *m_pImages[MAX_TEXTURES];
};
class CVkMaterial: public IMaterial
{
public:
CVkMaterial( IShader *pShader );
virtual ~CVkMaterial() override;
void Frame();
virtual void VSSetShaderResource( uint32_t uRegister, IRenderingObject *pResource ) override;
virtual void VSSetConstantsBuffer( uint32_t uRegister, IBuffer *pConstants ) override;
virtual void PSSetShaderResource( uint32_t uRegister, IRenderingObject *pResource ) override;
virtual void PSSetConstantsBuffer( uint32_t uRegister, IBuffer *pConstants ) override;
virtual void PSSetTextureArray( uint32_t uSet, ITextureArray *pArray ) override;
CVkShader *m_pVkShader;
CUtlVector<VkDescriptorSet> m_hSets;
ITextureArray *m_pTextureArray;
private:
VkDescriptorPool m_hPool;
CUtlVector<VkWriteDescriptorSet> m_writes = {};
void SetShaderResource( uint32_t uRegister, uint32_t uSet, IRenderingObject *pObject);
};
enum EVulkanRenderingStage
{
RENDERING_STAGE_SETUP_RASTER,
RENDERING_STAGE_RASTER,
RENDERING_STAGE_POST_RASTER,
RENDERING_STAGE_FINISHED,
};
struct VulkanMaterialCommandBuffer_t
{
IMaterial *m_pMaterial;
IVkCommandBuffer *m_pCommandBuffer;
};
enum EVkFrameObjectType_t
{
FRAME_OBJECT_TYPE_SINGLE,
FRAME_OBJECT_TYPE_SWAPPED,
};
struct VkFrameObject_t
{
EVkFrameObjectType_t m_eObjectType;
union {
IRenderingObject *m_pSingle;
IRenderingObject **m_ppSwapped;
};
};
struct VulkanRenderOutput_t {
VkFrameObject_t m_stImage;
VkFrameObject_t m_stResolveImage;
float m_fClearColor[4];
float m_fClearDepth;
uint32_t m_uIndex;
EResolveMode m_eResolveMode;
ELoadMode m_eLoadMode;
EStoreMode m_eStoreMode;
};
class CVkRenderCommandList: public IRenderCommandList
{
public:
~CVkRenderCommandList();
virtual void ResetRendering() override;
virtual void SetRenderTarget( uint32_t uIndex, IImage *pImage ) override;
virtual void SetClearColor( uint32_t uIndex, float r, float g, float b, float a ) override;
virtual void SetDepthTarget( IImage *pDepth ) override;
virtual void SetClearDepth( float fVal ) override;
virtual void SetRenderResolution( uint32_t iWidth, uint32_t iHeight ) override;
// Should they apply per material or for all?
virtual void SetScissors( uint32_t uX, uint32_t uY, uint32_t uWidth, uint32_t uHeight ) override;
virtual void SetViewport( uint32_t uX, uint32_t uY, uint32_t uWidth, uint32_t uHeight, float fMinDepth, float fMaxDepth ) override;
virtual void SetMaterial( IMaterial *pMaterial ) override;
virtual void SetVertexBuffer( uint32_t uBinding, IVertexBuffer *pBuffer ) override;
virtual void SetIndexBuffer( IVertexBuffer *pBuffer ) override;
virtual void DrawPrimitives( uint32_t nVertexCount, uint32_t nFirstVertex, uint32_t nInstanceCount, uint32_t nFirstInstance ) override;
virtual void DrawPrimitivesIndexed( uint32_t nIndexCount, uint32_t nFirstIndex, uint32_t nVertexOffset, uint32_t nInstanceCount, uint32_t nFirstInstance ) override;
virtual void ResolveImage( IImage *pOriginal, IImage *pResolved ) override;
virtual void StartRecording() override;
virtual void EndRecording() override;
void Submit();
IVkCommandBufferManager *m_pCommandBufferManager;
private:
void SwitchRenderingStage( EVulkanRenderingStage eStage );
VulkanRenderOutput_t *FindOrCreateRenderOutput( uint32_t uIndex );
IVkCommandBuffer *FindOrCreateMaterialCommandBuffer( IMaterial *pMaterial, bool *pbWasCreated = NULL );
bool m_bDepthEnabled = false;
VulkanRenderOutput_t m_depth = {};
CUtlVector<VulkanRenderOutput_t> m_pOutput = {};
CUtlVector<VulkanMaterialCommandBuffer_t> m_materials = {};
IVkCommandBuffer *m_pPostRaster = NULL;
IVkCommandBuffer *m_pCurrentMaterialBuffer = NULL;
uint32_t m_uWidth;
uint32_t m_uHeight;
CUtlVector<IVkCommandBuffer*> m_pCommandBuffers = {};
CUtlVector<IVkCommandBuffer*> m_pScheduledDestroyPostRaster = {};
};
IRenderingObject *VulkanGetObject( VkFrameObject_t stObject, int iIndex );
VkAccessFlags2 VulkanGetAccessFlags( EDependencyMode eMode );
VkPipelineStageFlags2 VulkanGetStageFlags( EDependencyMode eMode );
VkImageLayout VulkanGetImageLayout( EDependencyMode eMode );
VkFormat VulkanGetVertexFormat( EVertexFormat eFormat );
VkPrimitiveTopology VulkanGetTopology( ETopologyMode eMode );
VkShaderStageFlagBits VulkanGetShaderStage( EShaderStage eStage );
#endif