452 lines
13 KiB
C++
452 lines
13 KiB
C++
#include "materialsystem/imaterialsystem.h"
|
|
#include "tier0/platform.h"
|
|
#include "tier1/interface.h"
|
|
#include "tier1/utlvector.h"
|
|
#include "vulkan_state.h"
|
|
|
|
struct VulkanCommandLastUsage_t
|
|
{
|
|
uint32_t m_nLastUsedCommand;
|
|
EDependencyMode m_eLastUsage;
|
|
VulkanCommandDepenency_t m_dependency;
|
|
};
|
|
|
|
struct VulkanSwapchainCommandLastUsage_t
|
|
{
|
|
uint32_t m_nLastUsedCommand;
|
|
EDependencyMode m_eLastUsage;
|
|
VulkanCommandSwapchainDepenency_t m_dependency;
|
|
};
|
|
|
|
class CVkCommandBuffer: public IVkCommandBuffer
|
|
{
|
|
public:
|
|
virtual void SetVulkanHandlers( VkDevice hDevice, IVkCommandBufferManager *pManager ) override;
|
|
virtual void AddCommand( CVkCommand *pCommand ) override;
|
|
virtual void Reset() override;
|
|
virtual void Submit( int iFrameIndex ) override;
|
|
virtual void Render() override;
|
|
void FreeWithCommands();
|
|
private:
|
|
void SortDependencies();
|
|
void TryBarrier( int iCurrent, int iCurrentBuffer );
|
|
VulkanCommandDepenency_t *FindLastObjectDependency( IRenderingObject *pObject );
|
|
|
|
CUtlVector<CVkCommand*> m_commands;
|
|
CUtlVector<VkCommandBuffer> m_hBuffers = NULL;
|
|
CUtlVector<VulkanCommandLastUsage_t> m_usedDependencies;
|
|
CUtlVector<CUtlVector<VulkanCommandLastUsage_t>> m_dependencies;
|
|
CUtlVector<VulkanSwapchainCommandLastUsage_t> m_usedSwapchainDependencies;
|
|
CUtlVector<CUtlVector<VulkanSwapchainCommandLastUsage_t>> m_swapchainDependencies;
|
|
|
|
VkDevice m_hDevice;
|
|
IVkCommandBufferManager *m_pMgr;
|
|
VkCommandPool m_hPool = NULL;
|
|
};
|
|
|
|
void CVkCommandBuffer::FreeWithCommands()
|
|
{
|
|
if (m_hPool)
|
|
{
|
|
for ( auto &c: m_commands)
|
|
{
|
|
delete c;
|
|
};
|
|
vkFreeCommandBuffers(m_hDevice, m_hPool, m_hBuffers.GetSize(), m_hBuffers.GetData());
|
|
vkDestroyCommandPool(m_hDevice, m_hPool, NULL);
|
|
m_hPool = NULL;
|
|
}
|
|
}
|
|
|
|
void CVkCommandBuffer::SetVulkanHandlers( VkDevice hDevice, IVkCommandBufferManager *pManager )
|
|
{
|
|
m_hDevice = hDevice;
|
|
m_pMgr = pManager;
|
|
}
|
|
|
|
void CVkCommandBuffer::Reset()
|
|
{
|
|
VkCommandBufferAllocateInfo commandBufferAllocInfo = {};
|
|
VkCommandPoolCreateInfo stCreateInfo = {};
|
|
|
|
FreeWithCommands();
|
|
|
|
stCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
|
stCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
|
vkCreateCommandPool(m_hDevice, &stCreateInfo, NULL, &m_hPool);
|
|
m_hBuffers = {};
|
|
m_hBuffers.Resize(FRAMES_IN_FLIGHT);
|
|
|
|
commandBufferAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
|
commandBufferAllocInfo.commandPool = m_hPool;
|
|
commandBufferAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
|
commandBufferAllocInfo.commandBufferCount = FRAMES_IN_FLIGHT;
|
|
vkAllocateCommandBuffers(m_hDevice, &commandBufferAllocInfo, m_hBuffers.GetData());
|
|
|
|
m_commands = {};
|
|
}
|
|
|
|
void CVkCommandBuffer::AddCommand( CVkCommand *pCommand )
|
|
{
|
|
m_commands.AppendTail(pCommand);
|
|
}
|
|
|
|
void CVkCommandBuffer::Submit( int iFrameIndex )
|
|
{
|
|
m_pMgr->GetVulkanCommands().AppendTail(m_hBuffers[iFrameIndex]);
|
|
};
|
|
|
|
struct VulkanBarrierObjects_t
|
|
{
|
|
VulkanCommandDepenency_t m_dependency;
|
|
};
|
|
|
|
void CVkCommandBuffer::Render()
|
|
{
|
|
|
|
uint32_t nNumDependencies;
|
|
int i = 0;
|
|
int y = 0;
|
|
|
|
SortDependencies();
|
|
|
|
for (auto hBuffer: m_hBuffers)
|
|
{
|
|
y = 0;
|
|
VkCommandBufferBeginInfo stCommandBufferBeginInfo = {};
|
|
stCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
vkBeginCommandBuffer(hBuffer, &stCommandBufferBeginInfo);
|
|
|
|
for (auto &pCommand: m_commands)
|
|
{
|
|
TryBarrier(y,i);
|
|
pCommand->Execute(hBuffer, i);
|
|
y++;
|
|
};
|
|
TryBarrier(y, i);
|
|
vkEndCommandBuffer(hBuffer);
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
struct VulkanCommandBarrier_t
|
|
{
|
|
EDependencyMode m_eOldDependency;
|
|
EDependencyMode m_eNewDependency;
|
|
IRenderingObject *m_pObject;
|
|
};
|
|
|
|
void CVkCommandBuffer::SortDependencies()
|
|
{
|
|
m_dependencies = {};
|
|
m_swapchainDependencies = {};
|
|
m_dependencies.Resize(m_commands.GetSize()+1);
|
|
m_swapchainDependencies.Resize(m_commands.GetSize()+1);
|
|
m_usedDependencies = {};
|
|
m_usedSwapchainDependencies = {};
|
|
|
|
int i = 0;
|
|
for ( auto dependency: m_dependencies)
|
|
{
|
|
dependency = NULL;
|
|
}
|
|
|
|
for (auto &pCommand: m_commands)
|
|
{
|
|
for ( auto dependency: pCommand->m_dependencies)
|
|
{
|
|
VulkanCommandLastUsage_t *pLastUsage = NULL;
|
|
|
|
for ( auto &dep: m_usedDependencies )
|
|
{
|
|
if (dep.m_dependency.m_pObject == dependency.m_pObject)
|
|
pLastUsage = &dep;
|
|
}
|
|
|
|
VulkanCommandLastUsage_t stLastUsage = {};
|
|
stLastUsage.m_nLastUsedCommand = i;
|
|
stLastUsage.m_dependency = dependency;
|
|
stLastUsage.m_eLastUsage = DEPENDENCY_MODE_NEXT_STAGE;
|
|
|
|
if (pLastUsage)
|
|
stLastUsage.m_eLastUsage = pLastUsage->m_dependency.m_eDependencyMode;
|
|
|
|
if (pLastUsage)
|
|
m_dependencies[pLastUsage->m_nLastUsedCommand+1].AppendTail(stLastUsage);
|
|
else
|
|
m_dependencies[0].AppendTail(stLastUsage);
|
|
|
|
m_usedDependencies.AppendTail(stLastUsage);
|
|
}
|
|
for ( auto dependency: pCommand->m_swapchainDependencies)
|
|
{
|
|
VulkanSwapchainCommandLastUsage_t *pLastUsage = NULL;
|
|
|
|
for ( auto &dep: m_usedSwapchainDependencies )
|
|
{
|
|
if (dep.m_dependency.m_ppObjects == dependency.m_ppObjects)
|
|
pLastUsage = &dep;
|
|
}
|
|
|
|
VulkanSwapchainCommandLastUsage_t stLastUsage = {};
|
|
stLastUsage.m_nLastUsedCommand = i;
|
|
stLastUsage.m_dependency = dependency;
|
|
stLastUsage.m_eLastUsage = DEPENDENCY_MODE_NEXT_STAGE;
|
|
|
|
if (pLastUsage)
|
|
stLastUsage.m_eLastUsage = pLastUsage->m_dependency.m_eDependencyMode;
|
|
|
|
if (pLastUsage)
|
|
m_swapchainDependencies[pLastUsage->m_nLastUsedCommand+1].AppendTail(stLastUsage);
|
|
else
|
|
m_swapchainDependencies[0].AppendTail(stLastUsage);
|
|
|
|
m_usedSwapchainDependencies.AppendTail(stLastUsage);
|
|
}
|
|
i++;
|
|
}
|
|
|
|
|
|
for (auto &pCommand: m_commands)
|
|
{
|
|
for ( auto dependency: pCommand->m_dependencies)
|
|
{
|
|
VulkanCommandLastUsage_t *pLastUsage = NULL;
|
|
|
|
for ( auto &dep: m_usedDependencies )
|
|
{
|
|
if (dep.m_dependency.m_pObject == dependency.m_pObject)
|
|
pLastUsage = &dep;
|
|
}
|
|
|
|
VulkanCommandLastUsage_t stLastUsage = {};
|
|
stLastUsage.m_nLastUsedCommand = i;
|
|
stLastUsage.m_dependency = dependency;
|
|
stLastUsage.m_dependency.m_eDependencyMode = DEPENDENCY_MODE_NEXT_STAGE;
|
|
stLastUsage.m_eLastUsage = DEPENDENCY_MODE_NEXT_STAGE;
|
|
|
|
if (pLastUsage)
|
|
{
|
|
stLastUsage.m_eLastUsage = pLastUsage->m_dependency.m_eDependencyMode;
|
|
if (pLastUsage->m_nLastUsedCommand == i)
|
|
continue;
|
|
m_dependencies[i].AppendTail(stLastUsage);
|
|
m_usedDependencies.AppendTail(stLastUsage);
|
|
}
|
|
|
|
}
|
|
for ( auto dependency: pCommand->m_swapchainDependencies)
|
|
{
|
|
VulkanSwapchainCommandLastUsage_t *pLastUsage = NULL;
|
|
|
|
for ( auto &dep: m_usedSwapchainDependencies )
|
|
{
|
|
if (dep.m_dependency.m_ppObjects == dependency.m_ppObjects)
|
|
pLastUsage = &dep;
|
|
}
|
|
|
|
VulkanSwapchainCommandLastUsage_t stLastUsage = {};
|
|
stLastUsage.m_nLastUsedCommand = i;
|
|
stLastUsage.m_dependency = dependency;
|
|
stLastUsage.m_dependency.m_eDependencyMode = DEPENDENCY_MODE_NEXT_STAGE;
|
|
stLastUsage.m_eLastUsage = DEPENDENCY_MODE_NEXT_STAGE;
|
|
|
|
if (pLastUsage)
|
|
{
|
|
stLastUsage.m_eLastUsage = pLastUsage->m_dependency.m_eDependencyMode;
|
|
if (pLastUsage->m_nLastUsedCommand == i)
|
|
continue;
|
|
m_swapchainDependencies[i].AppendTail(stLastUsage);
|
|
m_usedSwapchainDependencies.AppendTail(stLastUsage);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CVkCommandBuffer::TryBarrier( int iCurrent, int iCurrentBuffer )
|
|
{
|
|
int x = 0;
|
|
CUtlVector<VulkanCommandLastUsage_t> dependency = m_dependencies[iCurrent];
|
|
CUtlVector<VulkanSwapchainCommandLastUsage_t> swapchainDependency = m_swapchainDependencies[iCurrent];
|
|
CUtlVector<VulkanCommandBarrier_t> barriers;
|
|
|
|
VkDependencyInfo stDependencyInfo = {};
|
|
stDependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
|
|
CUtlVector<VkMemoryBarrier2> memoryBarriers = {};
|
|
CUtlVector<VkImageMemoryBarrier2> imageBarriers = {};
|
|
CUtlVector<VkBufferMemoryBarrier2> bufferBarriers = {};
|
|
|
|
for (auto barrier: dependency)
|
|
{
|
|
VulkanCommandBarrier_t stBarrier = {};
|
|
stBarrier.m_eOldDependency = barrier.m_eLastUsage;
|
|
stBarrier.m_eNewDependency = barrier.m_dependency.m_eDependencyMode;
|
|
stBarrier.m_pObject = barrier.m_dependency.m_pObject;
|
|
barriers.AppendTail(stBarrier);
|
|
x++;
|
|
};
|
|
x = 0;
|
|
for (auto barrier: swapchainDependency)
|
|
{
|
|
VulkanCommandBarrier_t stBarrier = {};
|
|
stBarrier.m_eOldDependency = barrier.m_eLastUsage;
|
|
stBarrier.m_eNewDependency = barrier.m_dependency.m_eDependencyMode;
|
|
stBarrier.m_pObject = barrier.m_dependency.m_ppObjects[iCurrentBuffer];
|
|
barriers.AppendTail(stBarrier);
|
|
x++;
|
|
};
|
|
for ( auto barrier: barriers )
|
|
{
|
|
union {
|
|
IRenderingObject *pObject;
|
|
CVkImage *pImage;
|
|
CVkBuffer *pBuffer;
|
|
};
|
|
|
|
pObject = barrier.m_pObject;
|
|
|
|
if (dynamic_cast<CVkImage*>(pObject))
|
|
{
|
|
|
|
VkImageMemoryBarrier2 imageMemoryBarrier = {};
|
|
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
|
|
imageMemoryBarrier.image = pImage->m_image;
|
|
imageMemoryBarrier.subresourceRange = pImage->m_range;
|
|
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
if (barrier.m_eNewDependency == DEPENDENCY_MODE_NEXT_STAGE)
|
|
imageMemoryBarrier.newLayout = pImage->m_ePreferredLayout;
|
|
else
|
|
imageMemoryBarrier.newLayout = VulkanGetImageLayout(barrier.m_eNewDependency);
|
|
imageMemoryBarrier.dstStageMask = VulkanGetStageFlags(barrier.m_eNewDependency);
|
|
imageMemoryBarrier.dstAccessMask = VulkanGetAccessFlags(barrier.m_eNewDependency);
|
|
if (barrier.m_eOldDependency == DEPENDENCY_MODE_NEXT_STAGE)
|
|
{
|
|
imageMemoryBarrier.oldLayout = pImage->m_ePreferredLayout;
|
|
imageMemoryBarrier.srcStageMask = VulkanGetStageFlags(DEPENDENCY_MODE_NEXT_STAGE);
|
|
imageMemoryBarrier.srcAccessMask = VulkanGetAccessFlags(DEPENDENCY_MODE_NEXT_STAGE);
|
|
} else {
|
|
imageMemoryBarrier.oldLayout = VulkanGetImageLayout(barrier.m_eOldDependency);
|
|
imageMemoryBarrier.srcStageMask = VulkanGetStageFlags(barrier.m_eOldDependency);
|
|
imageMemoryBarrier.srcAccessMask = VulkanGetAccessFlags(barrier.m_eOldDependency);
|
|
}
|
|
imageBarriers.AppendTail(imageMemoryBarrier);
|
|
|
|
pImage->m_eLastUsage = barrier.m_eNewDependency;
|
|
}
|
|
if (dynamic_cast<CVkBuffer*>(pObject))
|
|
{
|
|
}
|
|
}
|
|
|
|
if (imageBarriers.GetSize() == 0 && bufferBarriers.GetSize() == 0 )
|
|
return;
|
|
|
|
stDependencyInfo.imageMemoryBarrierCount = imageBarriers.GetSize();
|
|
stDependencyInfo.bufferMemoryBarrierCount = bufferBarriers.GetSize();
|
|
stDependencyInfo.pImageMemoryBarriers = imageBarriers.GetData();
|
|
stDependencyInfo.pBufferMemoryBarriers = bufferBarriers.GetData();
|
|
vkCmdPipelineBarrier2(m_hBuffers[iCurrentBuffer], &stDependencyInfo);
|
|
};
|
|
|
|
class CVkCommandBufferManager: public IVkCommandBufferManager
|
|
{
|
|
public:
|
|
virtual void Init() override;
|
|
virtual void Shutdown() override;
|
|
virtual void SetVulkanHandlers( VkInstance hInstance, VkDevice hDevice ) override;
|
|
virtual IVkCommandBuffer *CreateCommandBuffer() override;
|
|
virtual CVkCommand *CreateCommand( const char *szName ) override;
|
|
virtual CUtlVector<VkCommandBuffer> &GetVulkanCommands() override;
|
|
virtual void FreeCommandBufferWithCommands(IVkCommandBuffer* pCommandBuffer) override;
|
|
virtual void RenderingFinished() override;
|
|
private:
|
|
|
|
VkDevice m_hDevice;
|
|
CUtlVector<VkCommandBuffer> m_commands;
|
|
};
|
|
|
|
EXPOSE_INTERFACE(CVkCommandBufferManager, IVkCommandBufferManager, VULKAN_COMMAND_BUFFER_MANAGER_INTERFACE_NAME);
|
|
|
|
void CVkCommandBufferManager::Init()
|
|
{
|
|
|
|
}
|
|
|
|
void CVkCommandBufferManager::Shutdown()
|
|
{
|
|
|
|
}
|
|
|
|
void CVkCommandBufferManager::SetVulkanHandlers( VkInstance hInstance, VkDevice hDevice )
|
|
{
|
|
m_hDevice = hDevice;
|
|
}
|
|
|
|
|
|
IVkCommandBuffer *CVkCommandBufferManager::CreateCommandBuffer()
|
|
{
|
|
IVkCommandBuffer *pBuffer = new CVkCommandBuffer;
|
|
pBuffer->SetVulkanHandlers(m_hDevice, this);
|
|
return pBuffer;
|
|
}
|
|
|
|
|
|
struct VulkanCommandRegistry_t
|
|
{
|
|
const char *m_szName;
|
|
fnCreateVulkanCommand_t m_pfnCreate;
|
|
struct VulkanCommandRegistry_t *m_pNext;
|
|
} *s_pVulkanCommands = NULL;
|
|
|
|
CVkCommand *CVkCommandBufferManager::CreateCommand( const char *szName )
|
|
{
|
|
VulkanCommandRegistry_t *pCommand;
|
|
for ( pCommand = s_pVulkanCommands; pCommand; pCommand = pCommand->m_pNext )
|
|
{
|
|
if (!V_strcmp(pCommand->m_szName, szName))
|
|
return pCommand->m_pfnCreate();
|
|
}
|
|
Plat_FatalErrorFunc("Command %s not found\n", szName);
|
|
return NULL;
|
|
}
|
|
|
|
CUtlVector<VkCommandBuffer> &CVkCommandBufferManager::GetVulkanCommands()
|
|
{
|
|
return m_commands;
|
|
}
|
|
void CVkCommandBufferManager::FreeCommandBufferWithCommands(IVkCommandBuffer* pCommandBuffer)
|
|
{
|
|
CVkCommandBuffer *pVkBuffer = (CVkCommandBuffer*)pCommandBuffer;
|
|
pVkBuffer->FreeWithCommands();
|
|
delete pVkBuffer;
|
|
};
|
|
|
|
void CVkCommandBufferManager::RenderingFinished()
|
|
{
|
|
m_commands = {};
|
|
}
|
|
|
|
|
|
CVkCommandRegistry::CVkCommandRegistry( const char *szName, fnCreateVulkanCommand_t pfnCreate )
|
|
{
|
|
VulkanCommandRegistry_t *pCommand = new VulkanCommandRegistry_t;
|
|
pCommand->m_szName = szName;
|
|
pCommand->m_pfnCreate = pfnCreate;
|
|
pCommand->m_pNext = s_pVulkanCommands;
|
|
s_pVulkanCommands = pCommand;
|
|
}
|
|
|
|
|
|
void CVkCommand::AddDependency( IRenderingObject *pObject, EDependencyMode eDependencyMode )
|
|
{
|
|
m_dependencies.AppendTail({ pObject, eDependencyMode });
|
|
}
|
|
void CVkCommand::AddSwapchainDependency( IRenderingObject **ppObject, EDependencyMode eDependencyMode )
|
|
{
|
|
m_swapchainDependencies.AppendTail({ ppObject, eDependencyMode });
|
|
}
|
|
|