#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 g_vkFences; CUtlVector g_vkGraphicsSemaphores; CUtlVector g_vkPresentSemaphores; CUtlVector g_vkCommandPools; CUtlVector 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 physicalDevices ); CUtlVector 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 enabledInstanceExtensions; CUtlVector enabledDeviceExtensions; uint32_t nPhysicalDevicesCount; CUtlVector physicalDevices; uint32_t nNumQueueFamilies = 0; CUtlVector 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; VkPhysicalDeviceVulkan13Features vk13Features = {}; vk13Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; vk13Features.synchronization2 = 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 = &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 ); CVkFunctionsPipelineLibrary functions = {}; functions.SetVertex("funnygame/shaders/flat.spv", "vsMain"); functions.SetPixel("funnygame/shaders/flat.spv", "psMain"); 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 surfaceFormats; VkSurfaceCapabilitiesKHR surfaceCapatibilities = {}; uint32_t nSurfacePresentModes = 0; CUtlVector surfacePresentModes; const VkFormat preferedSurfaceFormats[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, }; VkSurfaceFormatKHR stSelectedFormat; VkSwapchainCreateInfoKHR stSwapchainCreateInfo = {}; VkFenceCreateInfo stFenceCreateInfo = {}; VkSemaphoreCreateInfo stSemaphoreCreateInfo = {}; uint32_t nSwapchainImages; CUtlVector 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 physicalDevices ) { uint32_t uMaxScore = 0; VkPhysicalDevice selectedDevice = 0; VkResult r; for (auto &device: physicalDevices) { uint32_t nExtensionCount; CUtlVector 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 CVkRenderContext::GetDeviceExtensions() { VkResult r; int i; uint32_t nExtensionCount; CUtlVector extensions; CUtlVector 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; }