yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
f65d756bf
master
1// vk-swap-chain.cpp 2#include "vk-swap-chain.h" 3 4#include "../apple/cocoa-util.h" 5#include "vk-util.h" 6 7namespace gfx 8{ 9 10using namespace Slang ; 11 12namespace vk 13{ 14 15ISwapchain * SwapchainImpl ::getInterface (const Guid & guid ) 16{ 17if (guid == GfxGUID ::IID_ISlangUnknown || guid == GfxGUID ::IID_ISwapchain ) 18return static_cast < ISwapchain *> (this ); 19return nullptr ; 20} 21 22void SwapchainImpl ::destroySwapchainAndImages () 23{ 24m_api -> vkQueueWaitIdle (m_queue -> m_queue ); 25if (m_swapChain != VK_NULL_HANDLE ) 26 { 27m_api -> vkDestroySwapchainKHR (m_api -> m_device ,m_swapChain ,nullptr ); 28m_swapChain = VK_NULL_HANDLE ; 29 } 30 31// Mark that it is no longer used 32m_images .clear (); 33} 34 35void SwapchainImpl ::getWindowSize (int * widthOut ,int * heightOut )const 36{ 37#if SLANG_WINDOWS_FAMILY 38RECT rc ; 39 ::GetClientRect ((HWND )m_windowHandle .handleValues [0 ],& rc ); 40* widthOut = rc .right - rc .left ; 41* heightOut = rc .bottom - rc .top ; 42#elif SLANG_APPLE_FAMILY 43CocoaUtil ::getNSWindowContentSize ((void * )m_windowHandle .handleValues [0 ],widthOut ,heightOut ); 44#elif defined(SLANG_ENABLE_XLIB ) 45XWindowAttributes winAttr = {}; 46XGetWindowAttributes ( 47 (Display * )m_windowHandle .handleValues [0 ], 48 (Window )m_windowHandle .handleValues [1 ], 49& winAttr ); 50 51* widthOut = winAttr .width ; 52* heightOut = winAttr .height ; 53#else 54* widthOut = 0 ; 55* heightOut = 0 ; 56#endif 57} 58 59Result SwapchainImpl ::createSwapchainAndImages () 60{ 61int width ,height ; 62getWindowSize (& width ,& height ); 63 64VkExtent2D imageExtent = {}; 65imageExtent .width = width ; 66imageExtent .height = height ; 67 68m_desc .width = width ; 69m_desc .height = height ; 70 71// catch this before throwing error 72if (width == 0 || height == 0 ) 73 { 74return SLANG_FAIL ; 75 } 76 77// It is necessary to query the caps -> otherwise the LunarG verification layer will 78// issue an error 79 { 80VkSurfaceCapabilitiesKHR surfaceCaps ; 81 82SLANG_VK_RETURN_ON_FAIL (m_api -> vkGetPhysicalDeviceSurfaceCapabilitiesKHR ( 83m_api -> m_physicalDevice , 84m_surface , 85& surfaceCaps )); 86 } 87 88VkPresentModeKHR presentMode ; 89List < VkPresentModeKHR > presentModes ; 90uint32_t numPresentModes = 0 ; 91m_api -> vkGetPhysicalDeviceSurfacePresentModesKHR ( 92m_api -> m_physicalDevice , 93m_surface , 94& numPresentModes , 95nullptr ); 96presentModes .setCount (numPresentModes ); 97m_api -> vkGetPhysicalDeviceSurfacePresentModesKHR ( 98m_api -> m_physicalDevice , 99m_surface , 100& numPresentModes , 101presentModes .getBuffer ()); 102 103 { 104int numCheckPresentOptions = 3 ; 105VkPresentModeKHR presentOptions []= { 106VK_PRESENT_MODE_IMMEDIATE_KHR , 107VK_PRESENT_MODE_MAILBOX_KHR , 108VK_PRESENT_MODE_FIFO_KHR }; 109if (m_desc .enableVSync ) 110 { 111presentOptions [0 ]= VK_PRESENT_MODE_FIFO_KHR ; 112presentOptions [1 ]= VK_PRESENT_MODE_IMMEDIATE_KHR ; 113presentOptions [2 ]= VK_PRESENT_MODE_MAILBOX_KHR ; 114 } 115 116presentMode = VK_PRESENT_MODE_MAX_ENUM_KHR ;// Invalid 117 118// Find the first option that's available on the device 119for (int j = 0 ;j < numCheckPresentOptions ;j ++ ) 120 { 121if (presentModes .indexOf (presentOptions [j ])!= Index (-1 )) 122 { 123presentMode = presentOptions [j ]; 124break ; 125 } 126 } 127 128if (presentMode == VK_PRESENT_MODE_MAX_ENUM_KHR ) 129 { 130return SLANG_FAIL ; 131 } 132 } 133 134VkSwapchainKHR oldSwapchain = VK_NULL_HANDLE ; 135 136VkSwapchainCreateInfoKHR swapchainDesc = {}; 137swapchainDesc .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR ; 138swapchainDesc .surface = m_surface ; 139swapchainDesc .minImageCount = m_desc .imageCount ; 140swapchainDesc .imageFormat = m_vkformat ; 141swapchainDesc .imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR ; 142swapchainDesc .imageExtent = imageExtent ; 143swapchainDesc .imageArrayLayers = 1 ; 144swapchainDesc .imageUsage = 145VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |VK_IMAGE_USAGE_TRANSFER_DST_BIT ; 146swapchainDesc .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE ; 147swapchainDesc .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR ; 148swapchainDesc .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR ; 149swapchainDesc .presentMode = presentMode ; 150swapchainDesc .clipped = VK_TRUE ; 151swapchainDesc .oldSwapchain = oldSwapchain ; 152 153SLANG_VK_RETURN_ON_FAIL ( 154m_api -> vkCreateSwapchainKHR (m_api -> m_device ,& swapchainDesc ,nullptr ,& m_swapChain )); 155 156uint32_t numSwapChainImages = 0 ; 157m_api -> vkGetSwapchainImagesKHR (m_api -> m_device ,m_swapChain ,& numSwapChainImages ,nullptr ); 158List < VkImage > vkImages ; 159 { 160vkImages .setCount (numSwapChainImages ); 161m_api -> vkGetSwapchainImagesKHR ( 162m_api -> m_device , 163m_swapChain , 164& numSwapChainImages , 165vkImages .getBuffer ()); 166 } 167 168for (GfxIndex i = 0 ;i < m_desc .imageCount ;i ++ ) 169 { 170ITextureResource ::Desc imageDesc = {}; 171imageDesc .allowedStates = ResourceStateSet ( 172ResourceState ::Present , 173ResourceState ::RenderTarget , 174ResourceState ::CopyDestination ); 175imageDesc .type = IResource ::Type ::Texture2D ; 176imageDesc .arraySize = 0 ; 177imageDesc .format = m_desc .format ; 178imageDesc .size .width = m_desc .width ; 179imageDesc .size .height = m_desc .height ; 180imageDesc .size .depth = 1 ; 181imageDesc .numMipLevels = 1 ; 182imageDesc .defaultState = ResourceState ::Present ; 183RefPtr < TextureResourceImpl > image = new TextureResourceImpl (imageDesc ,m_renderer ); 184image -> m_image = vkImages [i ]; 185image -> m_imageMemory = 0 ; 186image -> m_vkformat = m_vkformat ; 187image -> m_isWeakImageReference = true; 188m_images .add (image ); 189 } 190return SLANG_OK ; 191} 192 193SwapchainImpl ::~SwapchainImpl () 194{ 195destroySwapchainAndImages (); 196if (m_surface ) 197 { 198m_api -> vkDestroySurfaceKHR (m_api -> m_instance ,m_surface ,nullptr ); 199m_surface = VK_NULL_HANDLE ; 200 } 201m_renderer -> m_api .vkDestroySemaphore (m_renderer -> m_api .m_device ,m_nextImageSemaphore ,nullptr ); 202#if SLANG_APPLE_FAMILY 203CocoaUtil ::destroyMetalLayer (m_metalLayer ); 204#endif 205} 206 207Index SwapchainImpl ::_indexOfFormat (List < VkSurfaceFormatKHR >& formatsIn ,VkFormat format ) 208{ 209const Index numFormats = formatsIn .getCount (); 210const VkSurfaceFormatKHR * formats = formatsIn .getBuffer (); 211 212for (Index i = 0 ;i < numFormats ;++ i ) 213 { 214if (formats [i ].format == format ) 215 { 216return i ; 217 } 218 } 219return -1 ; 220} 221 222Result SwapchainImpl ::init (DeviceImpl * renderer ,const ISwapchain ::Desc & desc ,WindowHandle window ) 223{ 224m_desc = desc ; 225m_renderer = renderer ; 226m_api = & renderer -> m_api ; 227m_queue = static_cast < CommandQueueImpl *> (desc .queue ); 228m_windowHandle = window ; 229 230VkSemaphoreCreateInfo semaphoreCreateInfo = {}; 231semaphoreCreateInfo .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO ; 232SLANG_VK_RETURN_ON_FAIL (renderer -> m_api .vkCreateSemaphore ( 233renderer -> m_api .m_device , 234& semaphoreCreateInfo , 235nullptr , 236& m_nextImageSemaphore )); 237 238m_queue = static_cast < CommandQueueImpl *> (desc .queue ); 239 240// Make sure it's not set initially 241m_vkformat = VK_FORMAT_UNDEFINED ; 242 243#if SLANG_WINDOWS_FAMILY 244VkWin32SurfaceCreateInfoKHR surfaceCreateInfo = {}; 245surfaceCreateInfo .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR ; 246surfaceCreateInfo .hinstance = ::GetModuleHandle (nullptr ); 247surfaceCreateInfo .hwnd = (HWND )window .handleValues [0 ]; 248SLANG_VK_RETURN_ON_FAIL ( 249m_api -> vkCreateWin32SurfaceKHR (m_api -> m_instance ,& surfaceCreateInfo ,nullptr ,& m_surface )); 250#elif SLANG_APPLE_FAMILY 251m_metalLayer = CocoaUtil ::createMetalLayer ((void * )window .handleValues [0 ]); 252VkMetalSurfaceCreateInfoEXT surfaceCreateInfo = {}; 253surfaceCreateInfo .sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT ; 254surfaceCreateInfo .pLayer = (CAMetalLayer * )m_metalLayer ; 255SLANG_VK_RETURN_ON_FAIL ( 256m_api -> vkCreateMetalSurfaceEXT (m_api -> m_instance ,& surfaceCreateInfo ,nullptr ,& m_surface )); 257#elif SLANG_ENABLE_XLIB 258VkXlibSurfaceCreateInfoKHR surfaceCreateInfo = {}; 259surfaceCreateInfo .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR ; 260surfaceCreateInfo .dpy = (Display * )window .handleValues [0 ]; 261surfaceCreateInfo .window = (Window )window .handleValues [1 ]; 262SLANG_VK_RETURN_ON_FAIL ( 263m_api -> vkCreateXlibSurfaceKHR (m_api -> m_instance ,& surfaceCreateInfo ,nullptr ,& m_surface )); 264#else 265return SLANG_E_NOT_AVAILABLE ; 266#endif 267 268VkBool32 supported = false; 269m_api -> vkGetPhysicalDeviceSurfaceSupportKHR ( 270m_api -> m_physicalDevice , 271renderer -> m_queueFamilyIndex , 272m_surface , 273& supported ); 274 275uint32_t numSurfaceFormats = 0 ; 276List < VkSurfaceFormatKHR > surfaceFormats ; 277m_api -> vkGetPhysicalDeviceSurfaceFormatsKHR ( 278m_api -> m_physicalDevice , 279m_surface , 280& numSurfaceFormats , 281nullptr ); 282surfaceFormats .setCount (int (numSurfaceFormats )); 283m_api -> vkGetPhysicalDeviceSurfaceFormatsKHR ( 284m_api -> m_physicalDevice , 285m_surface , 286& numSurfaceFormats , 287surfaceFormats .getBuffer ()); 288 289// Look for a suitable format 290List < VkFormat > formats ; 291formats .add (VulkanUtil ::getVkFormat (desc .format )); 292// HACK! To check for a different format if couldn't be found 293if (desc .format == Format ::R8G8B8A8_UNORM ) 294 { 295formats .add (VK_FORMAT_B8G8R8A8_UNORM ); 296 } 297 298for (Index i = 0 ;i < formats .getCount ();++ i ) 299 { 300VkFormat format = formats [i ]; 301if (_indexOfFormat (surfaceFormats ,format ) >=0 ) 302 { 303m_vkformat = format ; 304 } 305 } 306 307if (m_vkformat == VK_FORMAT_UNDEFINED ) 308 { 309return SLANG_FAIL ; 310 } 311 312// Save the desc 313m_desc = desc ; 314if (m_desc .format == Format ::R8G8B8A8_UNORM && m_vkformat == VK_FORMAT_B8G8R8A8_UNORM ) 315 { 316m_desc .format = Format ::B8G8R8A8_UNORM ; 317 } 318 319createSwapchainAndImages (); 320return SLANG_OK ; 321} 322 323Result SwapchainImpl ::getImage (GfxIndex index ,ITextureResource ** outResource ) 324{ 325if (m_images .getCount () <= (Index )index ) 326return SLANG_FAIL ; 327returnComPtr (outResource ,m_images [index ]); 328return SLANG_OK ; 329} 330 331Result SwapchainImpl ::resize (GfxCount width ,GfxCount height ) 332{ 333SLANG_UNUSED (width ); 334SLANG_UNUSED (height ); 335destroySwapchainAndImages (); 336return createSwapchainAndImages (); 337} 338 339Result SwapchainImpl ::present () 340{ 341// If there are pending fence wait operations, flush them as an 342// empty vkQueueSubmit. 343if (m_queue -> m_pendingWaitFences .getCount ()!= 0 ) 344 { 345m_queue -> queueSubmitImpl (0 ,nullptr ,nullptr ,0 ); 346 } 347 348uint32_t swapChainIndices []= {uint32_t (m_currentImageIndex )}; 349 350VkPresentInfoKHR presentInfo = {}; 351presentInfo .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR ; 352presentInfo .swapchainCount = 1 ; 353presentInfo .pSwapchains = & m_swapChain ; 354presentInfo .pImageIndices = swapChainIndices ; 355Array < VkSemaphore ,2 > waitSemaphores ; 356for (auto s :m_queue -> m_pendingWaitSemaphores ) 357 { 358if (s != VK_NULL_HANDLE ) 359 { 360waitSemaphores .add (s ); 361 } 362 } 363m_queue -> m_pendingWaitSemaphores [0 ]= VK_NULL_HANDLE ; 364m_queue -> m_pendingWaitSemaphores [1 ]= VK_NULL_HANDLE ; 365presentInfo .waitSemaphoreCount = (uint32_t )waitSemaphores .getCount (); 366if (presentInfo .waitSemaphoreCount ) 367 { 368presentInfo .pWaitSemaphores = waitSemaphores .getBuffer (); 369 } 370if (m_currentImageIndex != -1 ) 371m_api -> vkQueuePresentKHR (m_queue -> m_queue ,& presentInfo ); 372return SLANG_OK ; 373} 374 375int SwapchainImpl ::acquireNextImage () 376{ 377if (!m_images .getCount ()) 378 { 379m_queue -> m_pendingWaitSemaphores [1 ]= VK_NULL_HANDLE ; 380return -1 ; 381 } 382 383m_currentImageIndex = -1 ; 384VkResult result = m_api -> vkAcquireNextImageKHR ( 385m_api -> m_device , 386m_swapChain , 387UINT64_MAX , 388m_nextImageSemaphore , 389VK_NULL_HANDLE , 390 (uint32_t * )& m_currentImageIndex ); 391 392if (result != VK_SUCCESS 393#if SLANG_APPLE_FAMILY 394&& result != VK_SUBOPTIMAL_KHR 395#endif 396 ) 397 { 398m_currentImageIndex = -1 ; 399destroySwapchainAndImages (); 400return m_currentImageIndex ; 401 } 402// Make the queue's next submit wait on `m_nextImageSemaphore`. 403m_queue -> m_pendingWaitSemaphores [1 ]= m_nextImageSemaphore ; 404return m_currentImageIndex ; 405} 406 407Result SwapchainImpl ::setFullScreenMode (bool mode ) 408{ 409return SLANG_FAIL ; 410} 411 412}// namespace vk 413}// namespace gfx