1167 lines
37 KiB
C++
1167 lines
37 KiB
C++
#include "commands.h"
|
|
#include "materialsystem/imaterialsystem.h"
|
|
#include "shadercompiler/icompiler.h"
|
|
#include "tier0/lib.h"
|
|
#include "tier0/platform.h"
|
|
#include "tier1/interface.h"
|
|
#include "tier1/utlstring.h"
|
|
#include "tier1/utlvector.h"
|
|
#include "tier2/ifilesystem.h"
|
|
#define VK_NO_PROTOTYPES
|
|
#include "vulkan/vulkan_core.h"
|
|
#include "vulkan_state.h"
|
|
#include "materialsystem/igamewindow.h"
|
|
#include "libraries.h"
|
|
#include "stb/stb_image.h"
|
|
|
|
|
|
#define REQUIRED_EXTENSION(ext) ext##_EXTENSION_NAME,
|
|
#define OPTIONAL_EXTENSION(ext) ext##_EXTENSION_NAME,
|
|
static const char *s_vkDeviceExtensions[] = {
|
|
#include "device_extensions.h"
|
|
};
|
|
#undef REQUIRED_EXTENSION
|
|
#undef OPTIONAL_EXTENSION
|
|
|
|
SupportedVulkanExtensions_t g_vkAvailableExtensions;
|
|
|
|
|
|
uint32_t g_iDrawFamily;
|
|
uint32_t g_iPresentFamily;
|
|
|
|
VkQueue s_vkDrawQueue;
|
|
VkQueue s_vkPresentQueue;
|
|
|
|
VkInstance s_vkInstance;
|
|
VmaAllocator s_vkAllocator;
|
|
VkPhysicalDevice s_vkPhysicalDevice;
|
|
VkDevice s_vkDevice;
|
|
VkSwapchainKHR s_vkSwapchain;
|
|
|
|
struct VulkanWindow_t
|
|
{
|
|
IGameWindow *m_pWindow;
|
|
VkSurfaceKHR m_surface;
|
|
VkSwapchainKHR m_swapchain;
|
|
VkFormat m_eFormat;
|
|
VkFence m_fences[FRAMES_IN_FLIGHT];
|
|
VkSemaphore m_imageAvailable[FRAMES_IN_FLIGHT];
|
|
VkSemaphore m_renderFinished[FRAMES_IN_FLIGHT];
|
|
CUtlVector<IImage*> m_images;
|
|
uint32_t m_uCurrentFrame;
|
|
};
|
|
|
|
|
|
CVkImage::CVkImage()
|
|
{
|
|
|
|
}
|
|
|
|
CVkImage::CVkImage( uint32_t nWidth, uint32_t nHeight, uint32_t nDepth, EImageFormat eFormat, EMultisampleType eMultisampleType, EImageType eImageType, VkImageUsageFlagBits eUsage )
|
|
{
|
|
m_nWidth = nWidth;
|
|
m_nHeight = nHeight;
|
|
m_eMultisampleType = eMultisampleType;
|
|
m_eImageType = eImageType;
|
|
m_eFormat = eFormat;
|
|
if (eFormat == IMAGE_FORMAT_D32_SFLOAT)
|
|
m_ePreferredLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
|
|
else
|
|
m_ePreferredLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
|
|
|
CreateImage(nWidth, nHeight, eFormat, eMultisampleType, eUsage);
|
|
CreateImageView();
|
|
}
|
|
|
|
CVkImage::~CVkImage()
|
|
{
|
|
|
|
}
|
|
|
|
VkImageViewType CVkImage::GetImageViewType( enum EImageType eImageType )
|
|
{
|
|
switch ( eImageType )
|
|
{
|
|
case IMAGE_TYPE_1D:
|
|
return VK_IMAGE_VIEW_TYPE_1D;
|
|
case IMAGE_TYPE_2D:
|
|
return VK_IMAGE_VIEW_TYPE_2D;
|
|
case IMAGE_TYPE_3D:
|
|
return VK_IMAGE_VIEW_TYPE_3D;
|
|
case IMAGE_TYPE_CUBE:
|
|
return VK_IMAGE_VIEW_TYPE_CUBE;
|
|
case IMAGE_TYPE_1D_ARRAY:
|
|
return VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
|
case IMAGE_TYPE_2D_ARRAY:
|
|
return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
|
case IMAGE_TYPE_CUBE_ARRAY:
|
|
return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
|
|
}
|
|
}
|
|
|
|
VkFormat CVkImage::GetImageFormat( enum EImageFormat eImageFormat )
|
|
{
|
|
switch ( eImageFormat )
|
|
{
|
|
case IMAGE_FORMAT_R8_UINT:
|
|
return VK_FORMAT_R8_UINT;
|
|
case IMAGE_FORMAT_RGB8_UINT:
|
|
return VK_FORMAT_R8G8B8_UINT;
|
|
case IMAGE_FORMAT_RGB8_SINT:
|
|
return VK_FORMAT_R8G8B8_SINT;
|
|
case IMAGE_FORMAT_RGB8_UNORM:
|
|
return VK_FORMAT_R8G8B8_UNORM;
|
|
case IMAGE_FORMAT_RGB8_SNORM:
|
|
return VK_FORMAT_R8G8B8_SNORM;
|
|
|
|
case IMAGE_FORMAT_RGB16_UINT:
|
|
return VK_FORMAT_R16G16B16_UINT;
|
|
case IMAGE_FORMAT_RGB16_SINT:
|
|
return VK_FORMAT_R16G16B16_SINT;
|
|
case IMAGE_FORMAT_RGB16_UNORM:
|
|
return VK_FORMAT_R16G16B16_UNORM;
|
|
case IMAGE_FORMAT_RGB16_SNORM:
|
|
return VK_FORMAT_R16G16B16_SNORM;
|
|
case IMAGE_FORMAT_RGB16_SFLOAT:
|
|
return VK_FORMAT_R16G16B16_SFLOAT;
|
|
|
|
case IMAGE_FORMAT_RGB32_SFLOAT:
|
|
return VK_FORMAT_R32G32B32_SFLOAT;
|
|
|
|
case IMAGE_FORMAT_RGBA8_UNORM:
|
|
return VK_FORMAT_R8G8B8A8_UNORM;
|
|
case IMAGE_FORMAT_BGRA8_UNORM:
|
|
return VK_FORMAT_B8G8R8A8_UNORM;
|
|
|
|
case IMAGE_FORMAT_RGBA8_UINT:
|
|
return VK_FORMAT_R8G8B8A8_UINT;
|
|
case IMAGE_FORMAT_RGBA8_SINT:
|
|
return VK_FORMAT_R8G8B8A8_SINT;
|
|
|
|
case IMAGE_FORMAT_RGBA16_UINT:
|
|
return VK_FORMAT_R16G16B16A16_UINT;
|
|
case IMAGE_FORMAT_RGBA16_SINT:
|
|
return VK_FORMAT_R16G16B16A16_SINT;
|
|
case IMAGE_FORMAT_RGBA16_UNORM:
|
|
return VK_FORMAT_R16G16B16A16_UNORM;
|
|
case IMAGE_FORMAT_RGBA16_SNORM:
|
|
return VK_FORMAT_R16G16B16A16_SNORM;
|
|
case IMAGE_FORMAT_RGBA16_SFLOAT:
|
|
return VK_FORMAT_R16G16B16A16_SFLOAT;
|
|
|
|
case IMAGE_FORMAT_RGBA32_SFLOAT:
|
|
return VK_FORMAT_R32G32B32A32_SFLOAT;
|
|
|
|
case IMAGE_FORMAT_BC1:
|
|
return VK_FORMAT_BC1_RGB_UNORM_BLOCK;
|
|
case IMAGE_FORMAT_BC3:
|
|
return VK_FORMAT_BC3_UNORM_BLOCK;
|
|
case IMAGE_FORMAT_BC7:
|
|
return VK_FORMAT_BC7_UNORM_BLOCK;
|
|
|
|
case IMAGE_FORMAT_D32_SFLOAT:
|
|
return VK_FORMAT_D32_SFLOAT;
|
|
}
|
|
return VK_FORMAT_UNDEFINED;
|
|
}
|
|
|
|
VkSampleCountFlagBits CVkImage::GetMultisampling( enum EMultisampleType eImageFormat )
|
|
{
|
|
switch ( eImageFormat )
|
|
{
|
|
case MULTISAMPLE_TYPE_1_SAMPLES:
|
|
return VK_SAMPLE_COUNT_1_BIT;
|
|
case MULTISAMPLE_TYPE_2_SAMPLES:
|
|
return VK_SAMPLE_COUNT_2_BIT;
|
|
case MULTISAMPLE_TYPE_4_SAMPLES:
|
|
return VK_SAMPLE_COUNT_4_BIT;
|
|
case MULTISAMPLE_TYPE_8_SAMPLES:
|
|
return VK_SAMPLE_COUNT_8_BIT;
|
|
}
|
|
}
|
|
|
|
void CVkImage::CreateImage( uint32_t nWidth, uint32_t nHeight, EImageFormat eFormat, EMultisampleType eMultisampleType, VkImageUsageFlagBits eUsage )
|
|
{
|
|
VkImageCreateInfo stCreateInfo = {};
|
|
VmaAllocationCreateInfo stAlloc = {};
|
|
stCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
stCreateInfo.imageType = VK_IMAGE_TYPE_2D;
|
|
stCreateInfo.extent.width = nWidth;
|
|
stCreateInfo.extent.height = nHeight;
|
|
stCreateInfo.extent.depth = 1;
|
|
stCreateInfo.mipLevels = 1;
|
|
stCreateInfo.arrayLayers = 1;
|
|
stCreateInfo.usage = eUsage | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
|
stCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
stCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
stCreateInfo.format = GetImageFormat(eFormat);
|
|
stCreateInfo.samples = GetMultisampling(eMultisampleType);
|
|
|
|
stAlloc.usage = VMA_MEMORY_USAGE_AUTO;
|
|
|
|
vmaCreateImage(s_vkAllocator, &stCreateInfo, &stAlloc, &m_image, &m_allocation, NULL);
|
|
}
|
|
|
|
void CVkImage::CreateImageView()
|
|
{
|
|
VkImageViewCreateInfo stImageViewCreateInfo = {};
|
|
VkImageViewType eImageViewType;
|
|
|
|
stImageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
stImageViewCreateInfo.image = m_image;
|
|
stImageViewCreateInfo.viewType = GetImageViewType(m_eImageType);
|
|
stImageViewCreateInfo.format = GetImageFormat(m_eFormat);
|
|
if (m_eFormat == IMAGE_FORMAT_D32_SFLOAT)
|
|
stImageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
|
else
|
|
stImageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
stImageViewCreateInfo.subresourceRange.layerCount = 1;
|
|
stImageViewCreateInfo.subresourceRange.levelCount = 1;
|
|
m_range = stImageViewCreateInfo.subresourceRange;
|
|
vkCreateImageView(s_vkDevice, &stImageViewCreateInfo, NULL, &m_imageView);
|
|
}
|
|
void CVkImage::SetDebugName( const char *szName )
|
|
{
|
|
|
|
}
|
|
|
|
|
|
uint32_t CVkImage::GetImageWidth()
|
|
{
|
|
return m_nWidth;
|
|
}
|
|
|
|
uint32_t CVkImage::GetImageHeight()
|
|
{
|
|
return m_nHeight;
|
|
}
|
|
|
|
EImageFormat CVkImage::GetImageFormat()
|
|
{
|
|
return m_eFormat;
|
|
}
|
|
|
|
EMultisampleType CVkImage::GetMultisampleType()
|
|
{
|
|
return m_eMultisampleType;
|
|
}
|
|
|
|
|
|
CVkBuffer::CVkBuffer( uint32_t nSize, VkBufferUsageFlags2 eUsage, uint32_t nAlignment )
|
|
{
|
|
VkBufferUsageFlags2CreateInfo stUsage = {};
|
|
VkBufferCreateInfo stBufferInfo = {};
|
|
VmaAllocationCreateInfo stAllocInfo = {};
|
|
VkBufferDeviceAddressInfo stAddress = {};
|
|
|
|
stUsage.sType = VK_STRUCTURE_TYPE_BUFFER_USAGE_FLAGS_2_CREATE_INFO;
|
|
stUsage.usage = eUsage | VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT;
|
|
if (eUsage & VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT)
|
|
{
|
|
m_eDescriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
|
}
|
|
if (eUsage & VK_BUFFER_USAGE_2_UNIFORM_BUFFER_BIT)
|
|
{
|
|
m_eDescriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
|
}
|
|
|
|
stBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
|
stBufferInfo.size = nSize;
|
|
stBufferInfo.pNext = &stUsage;
|
|
|
|
stAllocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
|
stAllocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
|
|
|
VkResult r = vmaCreateBuffer(s_vkAllocator, &stBufferInfo, &stAllocInfo, &m_buffer, &m_allocation, NULL);
|
|
|
|
|
|
stAddress.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
|
|
stAddress.buffer = m_buffer;
|
|
m_address = vkGetBufferDeviceAddress(s_vkDevice, &stAddress);
|
|
|
|
m_nSize = nSize;
|
|
}
|
|
|
|
CVkBuffer::~CVkBuffer()
|
|
{
|
|
vmaDestroyBuffer(s_vkAllocator, m_buffer, m_allocation);
|
|
}
|
|
|
|
|
|
void CVkBuffer::SetDebugName( const char *szName )
|
|
{
|
|
}
|
|
|
|
void CVkBuffer::Lock()
|
|
{
|
|
}
|
|
|
|
void CVkBuffer::Unlock()
|
|
{
|
|
|
|
}
|
|
|
|
void *CVkBuffer::Map()
|
|
{
|
|
void *pData;
|
|
|
|
pData = NULL;
|
|
VkResult r = vmaMapMemory(s_vkAllocator, m_allocation, &pData);
|
|
VULKAN_RESULT_PRINT(r, vmaMapMemory);
|
|
|
|
return pData;
|
|
}
|
|
|
|
void CVkBuffer::Unmap()
|
|
{
|
|
vmaUnmapMemory(s_vkAllocator, m_allocation);
|
|
}
|
|
|
|
uint32_t CVkBuffer::GetSize()
|
|
{
|
|
return m_nSize;
|
|
}
|
|
|
|
CVkTextureArray::~CVkTextureArray()
|
|
{
|
|
|
|
}
|
|
|
|
CVkTextureArray::CVkTextureArray()
|
|
{
|
|
for (uint32_t i = 0; i < 128; i++ )
|
|
m_pImages[i] = NULL;
|
|
|
|
}
|
|
|
|
void CVkTextureArray::Build()
|
|
{
|
|
for (uint32_t i = 0; i < 128; i++ )
|
|
m_pImages[i] = NULL;
|
|
|
|
VkSamplerCreateInfo samplerInfo = {};
|
|
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
|
samplerInfo.magFilter = VK_FILTER_LINEAR;
|
|
samplerInfo.minFilter = VK_FILTER_LINEAR;
|
|
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
|
|
samplerInfo.unnormalizedCoordinates = VK_FALSE;
|
|
samplerInfo.compareEnable = VK_FALSE;
|
|
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
|
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
samplerInfo.mipLodBias = 0.0f;
|
|
samplerInfo.minLod = 0.0f;
|
|
samplerInfo.maxLod = VK_LOD_CLAMP_NONE;
|
|
|
|
vkCreateSampler(m_hDevice, &samplerInfo, nullptr, &m_hSampler);
|
|
|
|
LoadTexture("game/core/textures/error.png");
|
|
}
|
|
|
|
void CVkTextureArray::SetDebugName( const char *szPath )
|
|
{
|
|
|
|
}
|
|
|
|
uint32_t CVkTextureArray::LoadTexture( const char *szPath )
|
|
{
|
|
for (uint32_t i = 0; i < 128; i++ )
|
|
{
|
|
if (m_pImages[i] == NULL)
|
|
return CreateTexture(i, szPath);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
extern IFileSystem *filesystem;
|
|
uint32_t CVkTextureArray::CreateTexture( uint32_t i, const char *szPath )
|
|
{
|
|
if ( filesystem == NULL )
|
|
{
|
|
CreateInterfaceFn pFilesystemFactory = Sys_GetFactory("filesystem_std");
|
|
filesystem = (IFileSystem*)pFilesystemFactory(FILESYSTEM_INTERFACE_VERSION, NULL);
|
|
}
|
|
IFileHandle *pHandle = filesystem->Open(szPath, FILEMODE_READ);
|
|
CUtlBuffer<unsigned char> data = filesystem->Size(pHandle);
|
|
filesystem->Read(pHandle, data.GetMemory(), data.GetSize());
|
|
filesystem->Close(pHandle);
|
|
int uWidth = 0;
|
|
int uHeight = 0;
|
|
int uChannels = 0;
|
|
unsigned char *pImg = stbi_load_from_memory(data.GetMemory(), data.GetSize(), &uWidth, &uHeight, &uChannels, 4);
|
|
IBuffer *pBuffer = m_pRenderContext->CreateStorageBuffer(uWidth*uHeight*uChannels);
|
|
pBuffer->Lock();
|
|
void *pData = pBuffer->Map();
|
|
V_memcpy(pData, pImg, uWidth*uHeight*uChannels);
|
|
pBuffer->Unmap();
|
|
pBuffer->Unlock();
|
|
IImage *pImage = m_pRenderContext->CreateTexture(uWidth, uHeight, IMAGE_FORMAT_RGBA8_UNORM, MULTISAMPLE_TYPE_NONE);
|
|
IImage *pCompressedImage = m_pRenderContext->CreateTexture(uWidth, uHeight, IMAGE_FORMAT_BC1, MULTISAMPLE_TYPE_NONE);
|
|
m_pImages[i] = (CVkImage*)pImage;
|
|
stbi_image_free(pImg);
|
|
|
|
|
|
CVkCopyBufferToImageCommand *pCopyCommand = NULL;
|
|
IVkCommandBuffer *pCommandBuffer = m_pCommandBufferManager->CreateCommandBuffer();
|
|
pCommandBuffer->Reset();
|
|
pCopyCommand = CREATE_COMMAND(m_pCommandBufferManager, CopyBufferToImage);
|
|
pCopyCommand->AddDependency((IRenderingObject*)pBuffer, DEPENDENCY_MODE_BUFFER_SOURCE);
|
|
pCopyCommand->AddDependency((IRenderingObject*)pImage, DEPENDENCY_MODE_IMAGE_DESTINATION);
|
|
pCopyCommand->pBuffer = pBuffer;
|
|
pCopyCommand->stOutputImage.m_eObjectType = FRAME_OBJECT_TYPE_SINGLE;
|
|
pCopyCommand->stOutputImage.m_pSingle = pImage;
|
|
pCopyCommand->iImageX = uWidth;
|
|
pCopyCommand->iImageY = uWidth;
|
|
pCommandBuffer->AddCommand(pCopyCommand);
|
|
pCommandBuffer->Render();
|
|
pCommandBuffer->Submit();
|
|
return i;
|
|
}
|
|
|
|
uint32_t CVkTextureArray::GetTextureID( const char *szPath )
|
|
{
|
|
}
|
|
|
|
void CVkTextureArray::UnloadTexture( uint32_t uTextureID )
|
|
{
|
|
|
|
}
|
|
void CVkTextureArray::Frame()
|
|
{
|
|
}
|
|
|
|
|
|
class CVkRenderContext: public IRenderContext
|
|
{
|
|
public:
|
|
virtual void Init() override;
|
|
virtual void Frame( float fDeltaTime ) override;
|
|
virtual void Shutdown() override;
|
|
|
|
virtual IVertexBuffer *CreateVertexBuffer( uint32_t nSize ) override;
|
|
virtual IIndexBuffer *CreateIndexBuffer( uint32_t nSize ) override;
|
|
virtual IBuffer *CreateConstantBuffer( uint32_t nSize ) override;
|
|
virtual IBuffer *CreateStorageBuffer( uint32_t nSize ) override;
|
|
virtual void DestroyBuffer( IBuffer *pBuffer ) override;
|
|
|
|
virtual IImage *CreateRenderTarget( uint32_t x, uint32_t y, EImageFormat eFormat, EMultisampleType eMultisampleType ) override;
|
|
virtual IImage *CreateTexture( uint32_t x, uint32_t y, EImageFormat eFormat, EMultisampleType eMultisampleType ) override;
|
|
virtual IImage *CreateStorageImage( uint32_t x, uint32_t y, EImageFormat eFormat, EMultisampleType eMultisampleType ) override;
|
|
virtual void DestroyImage( IImage *pImage ) override;
|
|
|
|
IBuffer *CreateBuffer( uint32_t nSize, VkBufferUsageFlags2 eUsage );
|
|
IBuffer *CreateBufferAligned( uint32_t nSize, uint32_t nAlignment, VkBufferUsageFlags2 eUsage );
|
|
|
|
virtual IShader *CreateShader( const char *szName ) override;
|
|
virtual void DestroyShader( IShader *pShader ) override;
|
|
|
|
virtual IMaterial *CreateMaterial( IShader *pShader ) override;
|
|
virtual void DestroyMaterial( IMaterial *pMaterial ) override;
|
|
|
|
virtual IRenderCommandList *CreateCommandList() override;
|
|
virtual void DestroyCommandList( IRenderCommandList *pCommandList ) override;
|
|
virtual void SubmitCommandList(IRenderCommandList *pList) override;
|
|
|
|
virtual void SetMainWindowManager( IGameWindowManager *pWindowManager ) override;
|
|
|
|
virtual void RenderGameWindow( IGameWindow *pWindow ) override;
|
|
virtual void RegisterGameWindow( IGameWindow *pWindow ) override;
|
|
virtual void UnregisterGameWindow( IGameWindow *pWindow ) override;
|
|
|
|
virtual ITextureArray *CreateTextureArray() override;
|
|
virtual void DestroyTextureArray() override;
|
|
private:
|
|
VkPhysicalDevice SelectPhysicalDevice( CUtlVector<VkPhysicalDevice> physicalDevices );
|
|
CUtlVector<const char *> GetDeviceExtensions();
|
|
|
|
VkCommandBuffer GetCommandBuffer();
|
|
|
|
VulkanWindow_t CreateSwapchain( IGameWindow *pWindow );
|
|
void DestroySwapchain( uint32_t uIndex );
|
|
|
|
IGameWindowManager *m_pWindowManager;
|
|
IVkCommandBufferManager *m_pCommandBufferManager;
|
|
IVkCommandBufferManager *m_pAssetsCommandBufferManager;
|
|
|
|
CUtlVector<VulkanWindow_t> m_renderWindows;
|
|
CUtlVector<CVkMaterial*> m_pMaterials;
|
|
CUtlVector<CVkTextureArray*> m_pTextureArrays;
|
|
|
|
CUtlVector<CVkRenderCommandList*> m_scheduledRemovalLists;
|
|
CUtlVector<CVkTextureArray*> m_scheduledRemovalTextureArrays;
|
|
CUtlVector<CVkBuffer*> m_scheduledRemovalBuffers;
|
|
CUtlVector<CVkImage*> m_scheduledRemovalImages;
|
|
};
|
|
EXPOSE_INTERFACE(CVkRenderContext, IRenderContext, RENDER_CONTEXT_INTERFACE_VERSION);
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Creates vertex buffer. Wrapper over CreateBuffer
|
|
//-----------------------------------------------------------------------------
|
|
IVertexBuffer *CVkRenderContext::CreateVertexBuffer( uint32_t nSize )
|
|
{
|
|
return (IVertexBuffer*)CreateBuffer(nSize, VK_BUFFER_USAGE_2_VERTEX_BUFFER_BIT |VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Creates index buffer. Wrapper over CreateBuffer
|
|
//-----------------------------------------------------------------------------
|
|
IIndexBuffer *CVkRenderContext::CreateIndexBuffer( uint32_t nSize )
|
|
{
|
|
return (IIndexBuffer*)CreateBuffer(nSize, VK_BUFFER_USAGE_2_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
// Creates storage buffer. Wrapper over CreateBuffer
|
|
//-----------------------------------------------------------------------------
|
|
IBuffer *CVkRenderContext::CreateStorageBuffer( uint32_t nSize )
|
|
{
|
|
return (IVertexBuffer*)CreateBuffer(nSize, VK_BUFFER_USAGE_2_STORAGE_BUFFER_BIT);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Creates constant buffer. Wrapper over CreateBuffer
|
|
//-----------------------------------------------------------------------------
|
|
IBuffer *CVkRenderContext::CreateConstantBuffer( uint32_t nSize )
|
|
{
|
|
return (IIndexBuffer*)CreateBuffer(nSize, VK_BUFFER_USAGE_2_UNIFORM_BUFFER_BIT);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Creates basic vulkan buffer
|
|
//-----------------------------------------------------------------------------
|
|
IBuffer *CVkRenderContext::CreateBuffer( uint32_t nSize, VkBufferUsageFlags2 eUsage )
|
|
{
|
|
CVkBuffer *pBuffer = new CVkBuffer(nSize, eUsage, 0);
|
|
return pBuffer;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Creates vulkan buffer aligned to the nAlignment
|
|
// Useful for everything eg: ray tracing, which requires them to be aligned
|
|
// to the groupBaseAlignment.
|
|
//-----------------------------------------------------------------------------
|
|
IBuffer *CVkRenderContext::CreateBufferAligned( uint32_t nSize, uint32_t nAlignment, VkBufferUsageFlags2 eUsage )
|
|
{
|
|
|
|
}
|
|
|
|
|
|
IImage *CVkRenderContext::CreateRenderTarget( uint32_t x, uint32_t y, EImageFormat eFormat, EMultisampleType eMultisampleType )
|
|
{
|
|
if (eFormat == IMAGE_FORMAT_D32_SFLOAT)
|
|
return new CVkImage(x, y, 1, eFormat, eMultisampleType, IMAGE_TYPE_2D, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
|
else
|
|
return new CVkImage(x, y, 1, eFormat, eMultisampleType, IMAGE_TYPE_2D, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
|
|
}
|
|
IImage *CVkRenderContext::CreateTexture( uint32_t x, uint32_t y, EImageFormat eFormat, EMultisampleType eMultisampleType )
|
|
{
|
|
return new CVkImage(x, y, 1, eFormat, eMultisampleType, IMAGE_TYPE_2D, VK_IMAGE_USAGE_SAMPLED_BIT);
|
|
}
|
|
|
|
IImage *CVkRenderContext::CreateStorageImage( uint32_t x, uint32_t y, EImageFormat eFormat, EMultisampleType eMultisampleType )
|
|
{
|
|
return new CVkImage(x, y, 1, eFormat, eMultisampleType, IMAGE_TYPE_2D, VK_IMAGE_USAGE_STORAGE_BIT);
|
|
}
|
|
|
|
|
|
void CVkRenderContext::DestroyBuffer( IBuffer *pBuffer )
|
|
{
|
|
m_scheduledRemovalBuffers.AppendTail((CVkBuffer*)pBuffer);
|
|
}
|
|
|
|
void CVkRenderContext::DestroyImage( IImage *pImage )
|
|
{
|
|
|
|
}
|
|
|
|
IShader *CVkRenderContext::CreateShader( const char *szName )
|
|
{
|
|
|
|
|
|
CVkShader *pShader = new CVkShader();
|
|
VkGraphicsPipelineCreateInfo stPipelineCreateInfo = {};
|
|
ICompiledShaderManager *pCompiledShaderManager = (ICompiledShaderManager*)CreateInterface(COMPILED_SHADER_MANAGER_INTERFACE_VERSION, NULL);
|
|
pCompiledShaderManager->ReadFromFile(&pShader->m_shader, szName);
|
|
pShader->m_hDevice = s_vkDevice;
|
|
return pShader;
|
|
}
|
|
|
|
void CVkRenderContext::DestroyShader( IShader *pShader )
|
|
{
|
|
delete pShader;
|
|
}
|
|
|
|
IMaterial *CVkRenderContext::CreateMaterial( IShader *pShader )
|
|
{
|
|
CVkMaterial *pMaterial = new CVkMaterial(pShader);
|
|
m_pMaterials.AppendTail(pMaterial);
|
|
return pMaterial;
|
|
}
|
|
|
|
void CVkRenderContext::DestroyMaterial( IMaterial *pMaterial )
|
|
{
|
|
delete pMaterial;
|
|
}
|
|
|
|
IRenderCommandList *CVkRenderContext::CreateCommandList()
|
|
{
|
|
CVkRenderCommandList *pList = new CVkRenderCommandList;
|
|
pList->m_pCommandBufferManager = m_pCommandBufferManager;
|
|
return pList;
|
|
}
|
|
|
|
void CVkRenderContext::DestroyCommandList( IRenderCommandList *pCommandList )
|
|
{
|
|
m_scheduledRemovalLists.AppendTail((CVkRenderCommandList*)pCommandList);
|
|
}
|
|
|
|
void CVkRenderContext::SubmitCommandList(IRenderCommandList *pList)
|
|
{
|
|
CVkRenderCommandList *pVkList = (CVkRenderCommandList*)pList;
|
|
pVkList->Submit();
|
|
}
|
|
void CVkRenderContext::RenderGameWindow( IGameWindow *pWindow )
|
|
{
|
|
}
|
|
|
|
void CVkRenderContext::SetMainWindowManager( IGameWindowManager *pWindowManager )
|
|
{
|
|
m_pWindowManager = pWindowManager;
|
|
}
|
|
|
|
void CVkRenderContext::RegisterGameWindow( IGameWindow *pWindow )
|
|
{
|
|
VulkanWindow_t window = CreateSwapchain(pWindow);
|
|
m_renderWindows.AppendTail(window);
|
|
}
|
|
|
|
void CVkRenderContext::UnregisterGameWindow( IGameWindow *pWindow )
|
|
{
|
|
|
|
}
|
|
|
|
ITextureArray *CVkRenderContext::CreateTextureArray()
|
|
{
|
|
CVkTextureArray *pArray = new CVkTextureArray();
|
|
pArray->m_hDevice = s_vkDevice;
|
|
pArray->m_pRenderContext = this;
|
|
pArray->m_pCommandBufferManager = m_pCommandBufferManager;
|
|
pArray->Build();
|
|
return pArray;
|
|
}
|
|
|
|
void CVkRenderContext::DestroyTextureArray()
|
|
{
|
|
}
|
|
|
|
|
|
|
|
VkPipelineLayout g_pLibraryEmptyLayout;
|
|
static IVkCommandBuffer *s_pPresentCommandBuffer;
|
|
void CVkRenderContext::Init()
|
|
{
|
|
VkResult r;
|
|
|
|
int nExtensionCount;
|
|
|
|
CUtlVector<const char *> enabledInstanceExtensions;
|
|
CUtlVector<const char *> enabledDeviceExtensions;
|
|
|
|
uint32_t nPhysicalDevicesCount;
|
|
CUtlVector<VkPhysicalDevice> physicalDevices;
|
|
|
|
uint32_t nNumQueueFamilies = 0;
|
|
CUtlVector<VkQueueFamilyProperties> queueFamilyProperties;
|
|
|
|
VkApplicationInfo stApplicationInfo = {};
|
|
VkInstanceCreateInfo stInstanceCreateInfo = {};
|
|
|
|
VkDeviceQueueCreateInfo stDeviceQueueCreateInfo = {};
|
|
VkDeviceCreateInfo stDeviceCreateInfo = {};
|
|
|
|
float fPriority = 1.0;
|
|
|
|
r = volkInitialize();
|
|
VULKAN_RESULT_PRINT(r, volkInitialize);
|
|
|
|
if (m_pWindowManager)
|
|
{
|
|
nExtensionCount = m_pWindowManager->GetVulkanInstanceExtensionCount();
|
|
enabledInstanceExtensions.Resize(nExtensionCount);
|
|
V_memcpy(
|
|
enabledInstanceExtensions.GetData(),
|
|
m_pWindowManager->GetVulkanInstanceExtensions(),
|
|
nExtensionCount*sizeof(const char*)
|
|
);
|
|
|
|
}
|
|
|
|
// Create instance
|
|
stApplicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
|
stApplicationInfo.apiVersion = VK_API_VERSION_1_4;
|
|
stApplicationInfo.pApplicationName = "funny";
|
|
stApplicationInfo.pEngineName = "funny";
|
|
|
|
stInstanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
|
stInstanceCreateInfo.pApplicationInfo = &stApplicationInfo;
|
|
stInstanceCreateInfo.enabledExtensionCount = enabledInstanceExtensions.GetSize();
|
|
stInstanceCreateInfo.ppEnabledExtensionNames = enabledInstanceExtensions.GetData();
|
|
|
|
r = vkCreateInstance(&stInstanceCreateInfo, NULL, &s_vkInstance);
|
|
VULKAN_RESULT_PRINT(r, vkCreateInstance);
|
|
|
|
// volk requires to load instance this way
|
|
volkLoadInstance(s_vkInstance);
|
|
|
|
|
|
// Get amount of physical devices
|
|
r = vkEnumeratePhysicalDevices(s_vkInstance, &nPhysicalDevicesCount, NULL);
|
|
VULKAN_RESULT_PRINT(r, vkEnumeratePhysicalDevices);
|
|
physicalDevices.Resize(nPhysicalDevicesCount);
|
|
|
|
// Read all physical devices
|
|
r = vkEnumeratePhysicalDevices(s_vkInstance, &nPhysicalDevicesCount, physicalDevices.GetData());
|
|
VULKAN_RESULT_PRINT(r, vkEnumeratePhysicalDevices);
|
|
|
|
s_vkPhysicalDevice = SelectPhysicalDevice(physicalDevices);
|
|
|
|
enabledDeviceExtensions = GetDeviceExtensions();
|
|
|
|
|
|
// Get all queues
|
|
vkGetPhysicalDeviceQueueFamilyProperties(s_vkPhysicalDevice, &nNumQueueFamilies, NULL);
|
|
queueFamilyProperties.Resize(nNumQueueFamilies);
|
|
|
|
uint32_t i = 0;
|
|
vkGetPhysicalDeviceQueueFamilyProperties(s_vkPhysicalDevice, &nNumQueueFamilies, queueFamilyProperties.GetData());
|
|
|
|
for (auto &family: queueFamilyProperties)
|
|
{
|
|
if (family.queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
|
{
|
|
g_iDrawFamily = i;
|
|
g_iPresentFamily = i;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
// Create device
|
|
stDeviceQueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
stDeviceQueueCreateInfo.queueCount = 1;
|
|
stDeviceQueueCreateInfo.pQueuePriorities = &fPriority;
|
|
stDeviceQueueCreateInfo.queueFamilyIndex = g_iDrawFamily;
|
|
|
|
VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT gplFeatures = {};
|
|
gplFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT;
|
|
gplFeatures.graphicsPipelineLibrary = VK_TRUE;
|
|
|
|
VkPhysicalDeviceVulkan13Features vk13Features = {};
|
|
vk13Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
|
|
vk13Features.pNext = &gplFeatures;
|
|
vk13Features.synchronization2 = VK_TRUE;
|
|
vk13Features.dynamicRendering = VK_TRUE;
|
|
|
|
VkPhysicalDeviceVulkan12Features vk12Features = {};
|
|
vk12Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
|
|
vk12Features.pNext = &vk13Features;
|
|
vk12Features.bufferDeviceAddress = VK_TRUE;
|
|
vk12Features.runtimeDescriptorArray = VK_TRUE;
|
|
vk12Features.descriptorBindingPartiallyBound = VK_TRUE;
|
|
vk12Features.descriptorBindingVariableDescriptorCount = VK_TRUE;
|
|
VkPhysicalDeviceVulkan11Features vk11Features = {};
|
|
vk11Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
|
|
vk11Features.pNext = &vk12Features;
|
|
vk11Features.shaderDrawParameters = VK_TRUE;
|
|
|
|
|
|
stDeviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
|
stDeviceCreateInfo.queueCreateInfoCount = 1;
|
|
stDeviceCreateInfo.pQueueCreateInfos = &stDeviceQueueCreateInfo;
|
|
stDeviceCreateInfo.enabledExtensionCount = enabledDeviceExtensions.GetSize();
|
|
stDeviceCreateInfo.ppEnabledExtensionNames = enabledDeviceExtensions.GetData();
|
|
stDeviceCreateInfo.pNext = &vk11Features;
|
|
r = vkCreateDevice(s_vkPhysicalDevice, &stDeviceCreateInfo, NULL, &s_vkDevice);
|
|
VULKAN_RESULT_PRINT(r, vkEnumeratePhysicalDevices);
|
|
for (auto &extension: enabledDeviceExtensions)
|
|
V_printf("%s\n", extension);
|
|
vkGetDeviceQueue(s_vkDevice, g_iDrawFamily, 0, &s_vkDrawQueue);
|
|
vkGetDeviceQueue(s_vkDevice, g_iPresentFamily, 0, &s_vkPresentQueue);
|
|
volkLoadDevice(s_vkDevice);
|
|
|
|
VmaAllocatorCreateInfo stAllocatorInfo = {};
|
|
stAllocatorInfo.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT
|
|
| VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT
|
|
;
|
|
stAllocatorInfo.vulkanApiVersion = VK_API_VERSION_1_4;
|
|
stAllocatorInfo.physicalDevice = s_vkPhysicalDevice;
|
|
stAllocatorInfo.device = s_vkDevice;
|
|
stAllocatorInfo.instance = s_vkInstance;
|
|
|
|
VmaVulkanFunctions vulkanFunctions;
|
|
vmaImportVulkanFunctionsFromVolk(&stAllocatorInfo, &vulkanFunctions);
|
|
|
|
stAllocatorInfo.pVulkanFunctions = &vulkanFunctions;
|
|
vmaCreateAllocator(&stAllocatorInfo, &s_vkAllocator);
|
|
|
|
VkPipelineLayoutCreateInfo stPipelineLayout = {};
|
|
stPipelineLayout.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
|
stPipelineLayout.flags = VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT;
|
|
vkCreatePipelineLayout(s_vkDevice, &stPipelineLayout, NULL, &g_pLibraryEmptyLayout);
|
|
|
|
m_pCommandBufferManager = (IVkCommandBufferManager*)CreateInterface(VULKAN_COMMAND_BUFFER_MANAGER_INTERFACE_NAME, NULL);
|
|
m_pCommandBufferManager->SetVulkanHandlers(s_vkInstance, s_vkDevice);
|
|
m_pCommandBufferManager->Init();
|
|
}
|
|
|
|
void CVkRenderContext::Frame( float fDeltaTime )
|
|
{
|
|
|
|
uint32_t i;
|
|
CUtlVector<VkFence> fences = {};
|
|
CUtlVector<VkSemaphore> imageReady = {};
|
|
CUtlVector<VkSemaphore> renderFinish = {};
|
|
CUtlVector<VkSwapchainKHR> swapchains = {};
|
|
CUtlVector<uint32_t> uImageIndexes = {};
|
|
CUtlVector<uint32_t> uSwapchainImageIndexes = {};
|
|
CUtlVector<VulkanWindow_t> recreatedWindows = {};
|
|
vkDeviceWaitIdle(s_vkDevice);
|
|
|
|
for ( auto &m: m_pMaterials)
|
|
{
|
|
m->Frame();
|
|
}
|
|
|
|
i = 0;
|
|
for ( auto &s: m_renderWindows)
|
|
{
|
|
if ( !s.m_pWindow->BRenderSizeUpdated() )
|
|
{
|
|
i++;
|
|
continue;
|
|
}
|
|
DestroySwapchain(i);
|
|
m_renderWindows.RemoveAt(i);
|
|
recreatedWindows.AppendTail(CreateSwapchain(s.m_pWindow));
|
|
}
|
|
for ( auto &s: recreatedWindows)
|
|
{
|
|
m_renderWindows.AppendTail(s);
|
|
}
|
|
vkDeviceWaitIdle(s_vkDevice);
|
|
|
|
for ( auto &s: m_renderWindows)
|
|
{
|
|
fences.AppendTail(s.m_fences[s.m_uCurrentFrame]);
|
|
imageReady.AppendTail(s.m_imageAvailable[s.m_uCurrentFrame]);
|
|
renderFinish.AppendTail(s.m_renderFinished[s.m_uCurrentFrame]);
|
|
swapchains.AppendTail(s.m_swapchain);
|
|
uImageIndexes.AppendTail(s.m_uCurrentFrame);
|
|
}
|
|
uSwapchainImageIndexes.Resize(m_renderWindows.GetSize());
|
|
|
|
vkWaitForFences(s_vkDevice, fences.GetSize(), fences.GetData(), VK_TRUE, UINT64_MAX);
|
|
vkResetFences(s_vkDevice, fences.GetSize(), fences.GetData());
|
|
|
|
i = 0;
|
|
for ( auto &s: m_renderWindows )
|
|
{
|
|
VkResult r = vkAcquireNextImageKHR(s_vkDevice, s.m_swapchain, UINT64_MAX, s.m_imageAvailable[s.m_uCurrentFrame], NULL, &uSwapchainImageIndexes[i]);
|
|
i++;
|
|
}
|
|
|
|
|
|
s_pPresentCommandBuffer = m_pCommandBufferManager->CreateCommandBuffer();
|
|
s_pPresentCommandBuffer->Reset();
|
|
|
|
i = 0;
|
|
for ( auto &s: m_renderWindows )
|
|
{
|
|
|
|
|
|
CVkBlitCommand *pBlitCommand = NULL;
|
|
if (s.m_pWindow->GetOutputImage())
|
|
{
|
|
pBlitCommand = CREATE_COMMAND(m_pCommandBufferManager, Blit);
|
|
pBlitCommand->AddDependency(s.m_pWindow->GetOutputImage(), DEPENDENCY_MODE_BLIT_IMAGE_SOURCE);
|
|
pBlitCommand->AddDependency((IRenderingObject*)s.m_images[uSwapchainImageIndexes[i]], DEPENDENCY_MODE_BLIT_IMAGE_DESTINATION);
|
|
pBlitCommand->stInputImage.m_eObjectType = FRAME_OBJECT_TYPE_SINGLE;
|
|
pBlitCommand->stInputImage.m_pSingle = s.m_pWindow->GetOutputImage();
|
|
pBlitCommand->stOutputImage.m_eObjectType = FRAME_OBJECT_TYPE_SINGLE;
|
|
pBlitCommand->stOutputImage.m_pSingle = (IRenderingObject*)s.m_images[uSwapchainImageIndexes[i]];
|
|
pBlitCommand->iSrcMax[0] = s.m_pWindow->GetOutputImage()->GetImageWidth();
|
|
pBlitCommand->iSrcMax[1] = s.m_pWindow->GetOutputImage()->GetImageHeight();
|
|
pBlitCommand->iSrcMax[2] = 1;
|
|
pBlitCommand->iDstMax[0] = s.m_pWindow->GetRenderWidth();
|
|
pBlitCommand->iDstMax[1] = s.m_pWindow->GetRenderHeight();
|
|
pBlitCommand->iDstMax[2] = 1;
|
|
}
|
|
if (pBlitCommand != NULL)
|
|
s_pPresentCommandBuffer->AddCommand(pBlitCommand);
|
|
i++;
|
|
}
|
|
|
|
s_pPresentCommandBuffer->Render();
|
|
s_pPresentCommandBuffer->Submit(0);
|
|
|
|
|
|
VkPipelineStageFlags uPipelineStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
VkSubmitInfo stSubmitInfo = {};
|
|
stSubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
stSubmitInfo.waitSemaphoreCount = imageReady.GetSize();
|
|
stSubmitInfo.pWaitSemaphores = imageReady.GetData();
|
|
stSubmitInfo.pWaitDstStageMask = &uPipelineStageFlags;
|
|
|
|
stSubmitInfo.commandBufferCount = m_pCommandBufferManager->GetVulkanCommands().GetSize();
|
|
stSubmitInfo.pCommandBuffers = m_pCommandBufferManager->GetVulkanCommands().GetData();
|
|
|
|
stSubmitInfo.signalSemaphoreCount = renderFinish.GetSize();
|
|
stSubmitInfo.pSignalSemaphores = renderFinish.GetData();
|
|
|
|
|
|
vkQueueSubmit(s_vkDrawQueue, 1, &stSubmitInfo, fences[0]);
|
|
|
|
VkPresentInfoKHR stPresentInfo = {};
|
|
stPresentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
|
stPresentInfo.waitSemaphoreCount = renderFinish.GetSize();
|
|
stPresentInfo.pWaitSemaphores = renderFinish.GetData();
|
|
stPresentInfo.swapchainCount = swapchains.GetSize();
|
|
stPresentInfo.pSwapchains = swapchains.GetData();
|
|
stPresentInfo.pImageIndices = uImageIndexes.GetData();
|
|
|
|
vkQueuePresentKHR(s_vkPresentQueue, &stPresentInfo);
|
|
|
|
for ( auto &s: m_renderWindows )
|
|
{
|
|
s.m_uCurrentFrame = (s.m_uCurrentFrame + 1) % FRAMES_IN_FLIGHT;
|
|
}
|
|
m_pCommandBufferManager->RenderingFinished();
|
|
vkDeviceWaitIdle(s_vkDevice);
|
|
|
|
for (auto &a: m_scheduledRemovalBuffers)
|
|
{
|
|
delete a;
|
|
}
|
|
for (auto &a: m_scheduledRemovalLists)
|
|
{
|
|
delete a;
|
|
}
|
|
m_scheduledRemovalLists = {};
|
|
m_scheduledRemovalBuffers = {};
|
|
m_pCommandBufferManager->FreeCommandBufferWithCommands(s_pPresentCommandBuffer);
|
|
vkDeviceWaitIdle(s_vkDevice);
|
|
|
|
}
|
|
|
|
VulkanWindow_t CVkRenderContext::CreateSwapchain( IGameWindow *pWindow )
|
|
{
|
|
uint32_t numSurfaceFormats = 0;
|
|
CUtlVector<VkSurfaceFormatKHR> surfaceFormats;
|
|
|
|
VkSurfaceCapabilitiesKHR surfaceCapatibilities = {};
|
|
|
|
uint32_t nSurfacePresentModes = 0;
|
|
CUtlVector<VkPresentModeKHR> surfacePresentModes;
|
|
|
|
const VkFormat preferedSurfaceFormats[] = {
|
|
VK_FORMAT_B8G8R8A8_UNORM,
|
|
VK_FORMAT_R8G8B8A8_UNORM,
|
|
};
|
|
VkSurfaceFormatKHR stSelectedFormat;
|
|
|
|
VkSwapchainCreateInfoKHR stSwapchainCreateInfo = {};
|
|
VkFenceCreateInfo stFenceCreateInfo = {};
|
|
VkSemaphoreCreateInfo stSemaphoreCreateInfo = {};
|
|
|
|
uint32_t nSwapchainImages;
|
|
CUtlVector<VkImage> swapchainImages;
|
|
|
|
VulkanWindow_t window = {};
|
|
|
|
window.m_surface = (VkSurfaceKHR)pWindow->CreateVulkanSurface(s_vkInstance);
|
|
|
|
|
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(s_vkPhysicalDevice, (VkSurfaceKHR)window.m_surface, &surfaceCapatibilities);
|
|
|
|
|
|
vkGetPhysicalDeviceSurfaceFormatsKHR(s_vkPhysicalDevice, (VkSurfaceKHR)window.m_surface, &numSurfaceFormats, NULL);
|
|
surfaceFormats.Resize(numSurfaceFormats);
|
|
vkGetPhysicalDeviceSurfaceFormatsKHR(s_vkPhysicalDevice, (VkSurfaceKHR)window.m_surface, &numSurfaceFormats, surfaceFormats.GetData());
|
|
|
|
stSelectedFormat = surfaceFormats[0];
|
|
|
|
for (auto &format: surfaceFormats)
|
|
{
|
|
for (int i = 0; i < sizeof(preferedSurfaceFormats)/sizeof(VkFormat); i++)
|
|
{
|
|
if (format.format == preferedSurfaceFormats[i])
|
|
{
|
|
stSelectedFormat = format;
|
|
goto formatPicked;
|
|
}
|
|
}
|
|
}
|
|
formatPicked:
|
|
|
|
vkGetPhysicalDeviceSurfacePresentModesKHR(s_vkPhysicalDevice, window.m_surface, &nSurfacePresentModes, NULL);
|
|
surfacePresentModes.Resize(nSurfacePresentModes);
|
|
vkGetPhysicalDeviceSurfacePresentModesKHR(s_vkPhysicalDevice, window.m_surface, &nSurfacePresentModes, surfacePresentModes.GetData());
|
|
|
|
stSwapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
|
stSwapchainCreateInfo.surface = window.m_surface;
|
|
stSwapchainCreateInfo.imageFormat = stSelectedFormat.format;
|
|
stSwapchainCreateInfo.imageColorSpace = stSelectedFormat.colorSpace;
|
|
stSwapchainCreateInfo.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
|
stSwapchainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
stSwapchainCreateInfo.preTransform = surfaceCapatibilities.currentTransform;
|
|
stSwapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
|
stSwapchainCreateInfo.imageArrayLayers = 1;
|
|
stSwapchainCreateInfo.imageExtent = {pWindow->GetRenderWidth(), pWindow->GetRenderHeight()};
|
|
if (stSwapchainCreateInfo.imageExtent.width == 0)
|
|
stSwapchainCreateInfo.imageExtent.width = 1;
|
|
if (stSwapchainCreateInfo.imageExtent.height == 0)
|
|
stSwapchainCreateInfo.imageExtent.height = 1;
|
|
stSwapchainCreateInfo.minImageCount = surfaceCapatibilities.minImageCount;
|
|
vkCreateSwapchainKHR(s_vkDevice, &stSwapchainCreateInfo, NULL, &window.m_swapchain);
|
|
|
|
window.m_eFormat = stSwapchainCreateInfo.imageFormat;
|
|
|
|
vkGetSwapchainImagesKHR(s_vkDevice, window.m_swapchain, &nSwapchainImages, NULL);
|
|
window.m_images.Resize(nSwapchainImages);
|
|
swapchainImages.Resize(nSwapchainImages);
|
|
vkGetSwapchainImagesKHR(s_vkDevice, window.m_swapchain, &nSwapchainImages, swapchainImages.GetData());
|
|
|
|
for ( int i = 0; i < swapchainImages.GetSize(); i++ )
|
|
{
|
|
CVkImage *pImage;
|
|
pImage = new CVkImage;
|
|
pImage->m_image = swapchainImages[i];
|
|
pImage->m_eImageType = IMAGE_TYPE_2D;
|
|
pImage->m_eMultisampleType = MULTISAMPLE_TYPE_NONE;
|
|
pImage->m_eFormat = IMAGE_FORMAT_BGRA8_UNORM;
|
|
pImage->m_nHeight = 1280;
|
|
pImage->m_nWidth = 720;
|
|
pImage->m_ePreferredLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
|
pImage->CreateImageView();
|
|
window.m_images[i] = pImage;
|
|
}
|
|
for ( int i = 0; i < FRAMES_IN_FLIGHT; i++ )
|
|
{
|
|
stFenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
|
stFenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
|
vkCreateFence(s_vkDevice, &stFenceCreateInfo, NULL, &window.m_fences[i]);
|
|
|
|
stSemaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
|
vkCreateSemaphore(s_vkDevice, &stSemaphoreCreateInfo, NULL, &window.m_imageAvailable[i]);
|
|
vkCreateSemaphore(s_vkDevice, &stSemaphoreCreateInfo, NULL, &window.m_renderFinished[i]);
|
|
}
|
|
|
|
window.m_pWindow = pWindow;
|
|
return window;
|
|
}
|
|
|
|
void CVkRenderContext::DestroySwapchain( uint32_t uIndex )
|
|
{
|
|
for ( auto i: m_renderWindows[uIndex].m_images )
|
|
{
|
|
CVkImage *pImage = (CVkImage*)i;
|
|
vkDestroyImageView(s_vkDevice, pImage->m_imageView, NULL);
|
|
}
|
|
vkDestroySwapchainKHR(s_vkDevice, m_renderWindows[uIndex].m_swapchain, NULL);
|
|
m_renderWindows[uIndex].m_pWindow->DestroyVulkanSurface(s_vkInstance);
|
|
for ( int i = 0; i < FRAMES_IN_FLIGHT; i++ )
|
|
{
|
|
vkDestroyFence(s_vkDevice, m_renderWindows[uIndex].m_fences[i], NULL);
|
|
vkDestroySemaphore(s_vkDevice, m_renderWindows[uIndex].m_imageAvailable[i], NULL);
|
|
vkDestroySemaphore(s_vkDevice, m_renderWindows[uIndex].m_renderFinished[i], NULL);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// TODO: Move to the rendering context
|
|
//-----------------------------------------------------------------------------
|
|
void CVkRenderContext::Shutdown()
|
|
{
|
|
vkDestroyInstance(s_vkInstance, NULL);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Selects best device to be used in rendering.
|
|
// We want to get the best perfomance out of the GPU, so we need to select the
|
|
// best driver.
|
|
//-----------------------------------------------------------------------------
|
|
VkPhysicalDevice CVkRenderContext::SelectPhysicalDevice( CUtlVector<VkPhysicalDevice> physicalDevices )
|
|
{
|
|
uint32_t uMaxScore = 0;
|
|
VkPhysicalDevice selectedDevice = 0;
|
|
VkResult r;
|
|
|
|
for (auto &device: physicalDevices)
|
|
{
|
|
uint32_t nExtensionCount;
|
|
CUtlVector<VkExtensionProperties> extensions;
|
|
VkPhysicalDeviceFeatures stPhysicalDeviceFeatures;
|
|
VkPhysicalDeviceProperties stPhysicalDeviceProperties;
|
|
uint32_t uScore = 0;
|
|
|
|
r = vkEnumerateDeviceExtensionProperties(device, NULL, &nExtensionCount, NULL);
|
|
VULKAN_RESULT_PRINT(r, vkEnumeratePhysicalDevices);
|
|
extensions.Resize(nExtensionCount);
|
|
|
|
r = vkEnumerateDeviceExtensionProperties(device, NULL, &nExtensionCount, extensions.GetData());
|
|
VULKAN_RESULT_PRINT(r, vkEnumeratePhysicalDevices);
|
|
|
|
vkGetPhysicalDeviceProperties(device, &stPhysicalDeviceProperties);
|
|
vkGetPhysicalDeviceFeatures(device, &stPhysicalDeviceFeatures);
|
|
|
|
if (stPhysicalDeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
|
|
uScore += 1000;
|
|
if (stPhysicalDeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)
|
|
uScore += 500;
|
|
|
|
if (uScore >= uMaxScore)
|
|
{
|
|
selectedDevice = device;
|
|
uMaxScore = uScore;
|
|
}
|
|
}
|
|
|
|
return selectedDevice;
|
|
}
|
|
|
|
CUtlVector<const char *> CVkRenderContext::GetDeviceExtensions()
|
|
{
|
|
VkResult r;
|
|
int i;
|
|
|
|
uint32_t nExtensionCount;
|
|
CUtlVector<VkExtensionProperties> extensions;
|
|
|
|
CUtlVector<const char *> enabledExtensions;
|
|
|
|
const char *szExtensionName;
|
|
|
|
r = vkEnumerateDeviceExtensionProperties(s_vkPhysicalDevice, NULL, &nExtensionCount, NULL);
|
|
VULKAN_RESULT_PRINT(r, vkEnumeratePhysicalDevices);
|
|
extensions.Resize(nExtensionCount);
|
|
|
|
r = vkEnumerateDeviceExtensionProperties(s_vkPhysicalDevice, NULL, &nExtensionCount, extensions.GetData());
|
|
VULKAN_RESULT_PRINT(r, vkEnumeratePhysicalDevices);
|
|
|
|
|
|
#define REQUIRED_EXTENSION(ext) if (!V_strcmp(extension.extensionName, ext##_EXTENSION_NAME)) { g_vkAvailableExtensions.bIsSupported_##ext = true; enabledExtensions.AppendTail(ext##_EXTENSION_NAME); continue; };
|
|
#define OPTIONAL_EXTENSION(ext) REQUIRED_EXTENSION(ext);
|
|
|
|
|
|
for ( auto extension: extensions )
|
|
{
|
|
#include "device_extensions.h"
|
|
}
|
|
#undef REQUIRED_EXTENSION
|
|
#undef OPTIONAL_EXTENSION
|
|
|
|
return enabledExtensions;
|
|
}
|