yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Ellie Hermaszewskaformatf65d756bf

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