743 lines
23 KiB
C++
743 lines
23 KiB
C++
#include "SDL3/SDL_vulkan.h"
|
|
#include "commands.h"
|
|
#include "materialsystem/imaterialsystem.h"
|
|
#include "tier0/lib.h"
|
|
#include "tier0/platform.h"
|
|
#include "tier1/interface.h"
|
|
#include "tier1/utlstring.h"
|
|
#include "tier1/utlvector.h"
|
|
#define VK_NO_PROTOTYPES
|
|
#include "vulkan/vulkan_core.h"
|
|
#include "vulkan_state.h"
|
|
#include "igamewindow.h"
|
|
#include "raster_libraries.h"
|
|
|
|
|
|
#define REQUIRED_EXTENSION(ext) ext##_EXTENSION_NAME,
|
|
#define OPTIONAL_EXTENSION(ext) ext##_EXTENSION_NAME,
|
|
const char *g_vkDeviceExtensions[] = {
|
|
#include "device_extensions.h"
|
|
};
|
|
#undef REQUIRED_EXTENSION
|
|
#undef OPTIONAL_EXTENSION
|
|
|
|
SupportedVulkanExtensions_t g_vkAvailableExtensions;
|
|
|
|
|
|
uint32_t g_iDrawFamily;
|
|
uint32_t g_iPresentFamily;
|
|
|
|
VkQueue g_vkDrawQueue;
|
|
VkQueue g_vkPresentQueue;
|
|
|
|
VkInstance g_vkInstance;
|
|
VkPhysicalDevice g_vkPhysicalDevice;
|
|
VkDevice g_vkDevice;
|
|
VkSwapchainKHR g_vkSwapchain;
|
|
|
|
CUtlVector<VkFence> g_vkFences;
|
|
CUtlVector<VkSemaphore> g_vkGraphicsSemaphores;
|
|
CUtlVector<VkSemaphore> g_vkPresentSemaphores;
|
|
|
|
CUtlVector<VkCommandPool> g_vkCommandPools;
|
|
|
|
CUtlVector<IImage*> g_vkSwapchainImages;
|
|
VkFormat g_vkWindowImageFormat;
|
|
|
|
|
|
CVkImage::CVkImage()
|
|
{
|
|
|
|
}
|
|
|
|
CVkImage::CVkImage( uint32_t nWidth, uint32_t nHeight, EImageFormat eFormat, EMultisampleType eMultisampleType)
|
|
{
|
|
CreateImage(nWidth, nHeight, eFormat, eMultisampleType);
|
|
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_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_SFLOAT:
|
|
return VK_FORMAT_R16G16B16A16_SFLOAT;
|
|
case IMAGE_FORMAT_RGBA32_SFLOAT:
|
|
return VK_FORMAT_R32G32B32A32_SFLOAT;
|
|
case IMAGE_FORMAT_D32_SFLOAT:
|
|
return VK_FORMAT_D32_SFLOAT;
|
|
case IMAGE_FORMAT_WINDOW:
|
|
return g_vkWindowImageFormat;
|
|
}
|
|
}
|
|
|
|
void CVkImage::CreateImage( uint32_t nWidth, uint32_t nHeight, EImageFormat eFormat, EMultisampleType eMultisampleType )
|
|
{
|
|
|
|
}
|
|
|
|
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(g_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 )
|
|
{
|
|
}
|
|
|
|
CVkBuffer::~CVkBuffer()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
void CVkBuffer::SetDebugName( const char *szName )
|
|
{
|
|
|
|
}
|
|
|
|
void CVkBuffer::Lock()
|
|
{
|
|
|
|
}
|
|
|
|
void CVkBuffer::Unlock()
|
|
{
|
|
|
|
}
|
|
|
|
void *CVkBuffer::Map()
|
|
{
|
|
|
|
}
|
|
|
|
void CVkBuffer::Unmap()
|
|
{
|
|
|
|
}
|
|
|
|
uint32_t CVkBuffer::GetSize()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
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 void DestroyBuffer( IBuffer *pBuffer ) override;
|
|
|
|
virtual IImage *CreateRenderTarget( 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 *pMaterial ) override;
|
|
|
|
virtual IMaterial *CreateMaterial( IShader *pShader ) override;
|
|
virtual void DestroyMaterial( IMaterial *pMaterial ) override;
|
|
|
|
virtual void SetMaterial( IMaterial *pMaterial ) override;
|
|
virtual void SetVertexBuffer( 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;
|
|
private:
|
|
VkPhysicalDevice SelectPhysicalDevice( CUtlVector<VkPhysicalDevice> physicalDevices );
|
|
CUtlVector<const char *> GetDeviceExtensions();
|
|
|
|
VkCommandBuffer GetCommandBuffer();
|
|
|
|
void CreateSwapchain();
|
|
void DestroySwapchain();
|
|
};
|
|
|
|
CVkRenderContext s_vkRenderContext;
|
|
IRenderContext *g_pVkRenderContext = &s_vkRenderContext;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Creates vertex buffer. Wrapper over CreateBuffer
|
|
//-----------------------------------------------------------------------------
|
|
IVertexBuffer *CVkRenderContext::CreateVertexBuffer( uint32_t nSize )
|
|
{
|
|
return (IVertexBuffer*)CreateBuffer(nSize, VK_BUFFER_USAGE_2_VERTEX_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);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Creates basic vulkan buffer
|
|
//-----------------------------------------------------------------------------
|
|
IBuffer *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 *CreateBufferAligned( uint32_t nSize, uint32_t nAlignment, VkBufferUsageFlags2 eUsage )
|
|
{
|
|
|
|
}
|
|
|
|
|
|
IImage *CVkRenderContext::CreateRenderTarget( uint32_t x, uint32_t y, EImageFormat eFormat, EMultisampleType eMultisampleType )
|
|
{
|
|
|
|
}
|
|
|
|
IImage *CVkRenderContext::CreateStorageImage( uint32_t x, uint32_t y, EImageFormat eFormat, EMultisampleType eMultisampleType )
|
|
{
|
|
|
|
}
|
|
|
|
|
|
void CVkRenderContext::DestroyBuffer( IBuffer *pBuffer )
|
|
{
|
|
delete (CVkBuffer*)pBuffer;
|
|
}
|
|
|
|
void CVkRenderContext::DestroyImage( IImage *pImage )
|
|
{
|
|
|
|
}
|
|
|
|
IShader *CVkRenderContext::CreateShader( const char *szName )
|
|
{
|
|
|
|
}
|
|
|
|
void CVkRenderContext::DestroyShader( IShader *pMaterial )
|
|
{
|
|
|
|
}
|
|
|
|
IMaterial *CVkRenderContext::CreateMaterial( IShader *pShader )
|
|
{
|
|
|
|
}
|
|
|
|
void CVkRenderContext::DestroyMaterial( IMaterial *pMaterial )
|
|
{
|
|
|
|
}
|
|
void CVkRenderContext::SetMaterial( IMaterial *pMaterial )
|
|
{
|
|
|
|
}
|
|
|
|
void CVkRenderContext::SetVertexBuffer( IVertexBuffer *pBuffer )
|
|
{
|
|
|
|
}
|
|
|
|
void CVkRenderContext::SetIndexBuffer( IVertexBuffer *pBuffer )
|
|
{
|
|
|
|
}
|
|
|
|
void CVkRenderContext::DrawPrimitives( uint32_t nVertexCount, uint32_t nFirstVertex, uint32_t nInstanceCount, uint32_t nFirstInstance )
|
|
{
|
|
|
|
}
|
|
|
|
void CVkRenderContext::DrawPrimitivesIndexed( uint32_t nIndexCount, uint32_t nFirstIndex, uint32_t nVertexOffset, uint32_t nInstanceCount, uint32_t nFirstInstance )
|
|
{
|
|
|
|
}
|
|
|
|
IVkCommandBuffer *pCommandBuffer;
|
|
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);
|
|
|
|
// Get extensions required by game window
|
|
nExtensionCount = gamewindow->GetVulkanInstanceExtensionCount();
|
|
enabledInstanceExtensions.Resize(nExtensionCount);
|
|
V_memcpy(enabledInstanceExtensions.GetData(), gamewindow->GetVulkanInstanceExtensions(), enabledInstanceExtensions.GetSize()*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, &g_vkInstance);
|
|
VULKAN_RESULT_PRINT(r, vkCreateInstance);
|
|
|
|
// volk requires to load instance this way
|
|
volkLoadInstance(g_vkInstance);
|
|
|
|
|
|
// Get amount of physical devices
|
|
r = vkEnumeratePhysicalDevices(g_vkInstance, &nPhysicalDevicesCount, NULL);
|
|
VULKAN_RESULT_PRINT(r, vkEnumeratePhysicalDevices);
|
|
physicalDevices.Resize(nPhysicalDevicesCount);
|
|
|
|
// Read all physical devices
|
|
r = vkEnumeratePhysicalDevices(g_vkInstance, &nPhysicalDevicesCount, physicalDevices.GetData());
|
|
VULKAN_RESULT_PRINT(r, vkEnumeratePhysicalDevices);
|
|
|
|
g_vkPhysicalDevice = SelectPhysicalDevice(physicalDevices);
|
|
|
|
enabledDeviceExtensions = GetDeviceExtensions();
|
|
|
|
|
|
// Get all queues
|
|
vkGetPhysicalDeviceQueueFamilyProperties(g_vkPhysicalDevice, &nNumQueueFamilies, NULL);
|
|
queueFamilyProperties.Resize(nNumQueueFamilies);
|
|
|
|
uint32_t i = 0;
|
|
vkGetPhysicalDeviceQueueFamilyProperties(g_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.synchronization2 = VK_TRUE;
|
|
vk13Features.pNext = &gplFeatures;
|
|
|
|
stDeviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
|
stDeviceCreateInfo.queueCreateInfoCount = 1;
|
|
stDeviceCreateInfo.pQueueCreateInfos = &stDeviceQueueCreateInfo;
|
|
stDeviceCreateInfo.enabledExtensionCount = enabledDeviceExtensions.GetSize();
|
|
stDeviceCreateInfo.ppEnabledExtensionNames = enabledDeviceExtensions.GetData();
|
|
stDeviceCreateInfo.pNext = &vk13Features;
|
|
r = vkCreateDevice(g_vkPhysicalDevice, &stDeviceCreateInfo, NULL, &g_vkDevice);
|
|
VULKAN_RESULT_PRINT(r, vkEnumeratePhysicalDevices);
|
|
for (auto &extension: enabledDeviceExtensions)
|
|
V_printf("%s\n", extension);
|
|
vkGetDeviceQueue(g_vkDevice, g_iDrawFamily, 0, &g_vkDrawQueue);
|
|
vkGetDeviceQueue(g_vkDevice, g_iPresentFamily, 0, &g_vkPresentQueue);
|
|
|
|
CreateSwapchain();
|
|
|
|
g_vkCommandPools.Resize(g_vkSwapchainImages.GetSize());
|
|
|
|
for (auto &pool: g_vkCommandPools)
|
|
{
|
|
VkCommandPoolCreateInfo commandPoolCreateInfo = {};
|
|
commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
|
commandPoolCreateInfo.queueFamilyIndex = g_iDrawFamily;
|
|
commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
|
vkCreateCommandPool(g_vkDevice, &commandPoolCreateInfo, NULL, &pool);
|
|
}
|
|
|
|
g_pCommandBufferManager = (IVkCommandBufferManager*)CreateInterface(VULKAN_COMMAND_BUFFER_MANAGER_INTERFACE_NAME, NULL);
|
|
g_pCommandBufferManager->Init();
|
|
|
|
pCommandBuffer = g_pCommandBufferManager->CreateCommandBuffer();
|
|
s_pPresentCommandBuffer = g_pCommandBufferManager->CreateCommandBuffer();
|
|
|
|
CVkClearColorCommand *pCommand = (CVkClearColorCommand*)g_pCommandBufferManager->CreateCommand("ClearColor");
|
|
|
|
pCommand->pImage = NULL;
|
|
pCommand->ppSwapchainImages = g_vkSwapchainImages.GetData();
|
|
pCommand->r = 1;
|
|
pCommand->b = 1;
|
|
pCommand->g = 0;
|
|
pCommand->AddSwapchainDependency( (IRenderingObject**)g_vkSwapchainImages.GetData(), DEPENDENCY_MODE_COLOR_CLEAR_DESTINATION );
|
|
|
|
CVkVertexDescriptionPipelineLibrary functions = {};
|
|
functions.AddAttribute(0, 0, VERTEX_FORMAT_XYZ32_SFLOAT, 0);
|
|
functions.AddLayout(0, 12);
|
|
functions.SetTopology(TOPOLOGY_MODE_TRIANGLE_LIST);
|
|
functions.Build();
|
|
|
|
CVkEmptyCommand *pPresentCommand = (CVkEmptyCommand*)g_pCommandBufferManager->CreateCommand("Empty");
|
|
pPresentCommand->AddSwapchainDependency( (IRenderingObject**)g_vkSwapchainImages.GetData(), DEPENDENCY_MODE_IMAGE_PRESENT );
|
|
|
|
CVkBeginCommand *pBeginCommand = (CVkBeginCommand*)g_pCommandBufferManager->CreateCommand("Empty");
|
|
pBeginCommand->AddSwapchainDependency((IRenderingObject**)g_vkSwapchainImages.GetData(), DEPENDENCY_MODE_DRAWCALL_OUTPUT_IMAGE);
|
|
CVkBeginCommand *pEndCommand = (CVkBeginCommand*)g_pCommandBufferManager->CreateCommand("Empty");
|
|
|
|
pCommandBuffer->Reset();
|
|
pCommandBuffer->AddCommand(pCommand);
|
|
pCommandBuffer->Render();
|
|
|
|
s_pPresentCommandBuffer->Reset();
|
|
s_pPresentCommandBuffer->AddCommand(pPresentCommand);
|
|
s_pPresentCommandBuffer->Render();
|
|
}
|
|
|
|
void CVkRenderContext::Frame( float fDeltaTime )
|
|
{
|
|
vkDeviceWaitIdle(g_vkDevice);
|
|
pCommandBuffer->Render();
|
|
s_pPresentCommandBuffer->Render();
|
|
|
|
static uint32_t s_nImageIndex = 0;
|
|
uint32_t nImageIndex = 0;
|
|
|
|
vkWaitForFences(g_vkDevice, 1, &g_vkFences[s_nImageIndex], VK_TRUE, UINT64_MAX);
|
|
VkResult r = vkAcquireNextImageKHR(g_vkDevice, g_vkSwapchain, UINT64_MAX, g_vkGraphicsSemaphores[s_nImageIndex], NULL, &nImageIndex);
|
|
|
|
vkResetFences(g_vkDevice, 1, &g_vkFences[s_nImageIndex]);
|
|
|
|
g_vkCommandBuffers = {};
|
|
|
|
pCommandBuffer->Submit(nImageIndex);
|
|
s_pPresentCommandBuffer->Submit(nImageIndex);
|
|
|
|
VkPipelineStageFlags uPipelineStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
VkSubmitInfo stSubmitInfo = {};
|
|
stSubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
stSubmitInfo.waitSemaphoreCount = 1;
|
|
stSubmitInfo.pWaitSemaphores = &g_vkGraphicsSemaphores[s_nImageIndex];
|
|
stSubmitInfo.pWaitDstStageMask = &uPipelineStageFlags;
|
|
|
|
stSubmitInfo.commandBufferCount = g_vkCommandBuffers.GetSize();
|
|
stSubmitInfo.pCommandBuffers = g_vkCommandBuffers.GetData();
|
|
|
|
stSubmitInfo.signalSemaphoreCount = 1;
|
|
stSubmitInfo.pSignalSemaphores = &g_vkPresentSemaphores[nImageIndex];
|
|
|
|
|
|
vkQueueSubmit(g_vkDrawQueue, 1, &stSubmitInfo, g_vkFences[s_nImageIndex]);
|
|
|
|
VkPresentInfoKHR stPresentInfo = {};
|
|
stPresentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
|
stPresentInfo.waitSemaphoreCount = 1;
|
|
stPresentInfo.pWaitSemaphores = &g_vkPresentSemaphores[nImageIndex];
|
|
stPresentInfo.swapchainCount = 1;
|
|
stPresentInfo.pSwapchains = &g_vkSwapchain;
|
|
stPresentInfo.pImageIndices = &nImageIndex;
|
|
|
|
vkQueuePresentKHR(g_vkPresentQueue, &stPresentInfo);
|
|
|
|
s_nImageIndex = (s_nImageIndex + 1) % g_vkSwapchainImages.GetSize();
|
|
}
|
|
|
|
void CVkRenderContext::CreateSwapchain()
|
|
{
|
|
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;
|
|
|
|
gamewindow->CreateVulkanSurface(g_vkInstance);
|
|
|
|
|
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_vkPhysicalDevice, (VkSurfaceKHR)gamewindow->GetVulkanSurface(), &surfaceCapatibilities);
|
|
|
|
|
|
vkGetPhysicalDeviceSurfaceFormatsKHR(g_vkPhysicalDevice, (VkSurfaceKHR)gamewindow->GetVulkanSurface(), &numSurfaceFormats, NULL);
|
|
surfaceFormats.Resize(numSurfaceFormats);
|
|
vkGetPhysicalDeviceSurfaceFormatsKHR(g_vkPhysicalDevice, (VkSurfaceKHR)gamewindow->GetVulkanSurface(), &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(g_vkPhysicalDevice, (VkSurfaceKHR)gamewindow->GetVulkanSurface(), &nSurfacePresentModes, NULL);
|
|
surfacePresentModes.Resize(nSurfacePresentModes);
|
|
vkGetPhysicalDeviceSurfacePresentModesKHR(g_vkPhysicalDevice, (VkSurfaceKHR)gamewindow->GetVulkanSurface(), &nSurfacePresentModes, surfacePresentModes.GetData());
|
|
|
|
stSwapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
|
stSwapchainCreateInfo.surface = (VkSurfaceKHR)gamewindow->GetVulkanSurface();
|
|
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 = surfaceCapatibilities.minImageExtent;
|
|
stSwapchainCreateInfo.minImageCount = surfaceCapatibilities.minImageCount;
|
|
vkCreateSwapchainKHR(g_vkDevice, &stSwapchainCreateInfo, NULL, &g_vkSwapchain);
|
|
|
|
g_vkWindowImageFormat = stSwapchainCreateInfo.imageFormat;
|
|
|
|
vkGetSwapchainImagesKHR(g_vkDevice, g_vkSwapchain, &nSwapchainImages, NULL);
|
|
g_vkSwapchainImages.Resize(nSwapchainImages);
|
|
swapchainImages.Resize(nSwapchainImages);
|
|
g_vkFences.Resize(nSwapchainImages);
|
|
g_vkGraphicsSemaphores.Resize(nSwapchainImages);
|
|
g_vkPresentSemaphores.Resize(nSwapchainImages);
|
|
vkGetSwapchainImagesKHR(g_vkDevice, g_vkSwapchain, &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_WINDOW;
|
|
pImage->CreateImageView();
|
|
g_vkSwapchainImages[i] = pImage;
|
|
|
|
stFenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
|
stFenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
|
vkCreateFence(g_vkDevice, &stFenceCreateInfo, NULL, &g_vkFences[i]);
|
|
|
|
stSemaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
|
vkCreateSemaphore(g_vkDevice, &stSemaphoreCreateInfo, NULL, &g_vkGraphicsSemaphores[i]);
|
|
vkCreateSemaphore(g_vkDevice, &stSemaphoreCreateInfo, NULL, &g_vkPresentSemaphores[i]);
|
|
}
|
|
|
|
}
|
|
|
|
void CVkRenderContext::DestroySwapchain()
|
|
{
|
|
vkDestroySwapchainKHR(g_vkDevice, g_vkSwapchain, NULL);
|
|
gamewindow->DestroyVulkanSurface(g_vkInstance);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// TODO: Move to the rendering context
|
|
//-----------------------------------------------------------------------------
|
|
void CVkRenderContext::Shutdown()
|
|
{
|
|
vkDestroyInstance(g_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(g_vkPhysicalDevice, NULL, &nExtensionCount, NULL);
|
|
VULKAN_RESULT_PRINT(r, vkEnumeratePhysicalDevices);
|
|
extensions.Resize(nExtensionCount);
|
|
|
|
r = vkEnumerateDeviceExtensionProperties(g_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;
|
|
}
|
|
|