Implement WSI layer swapchain functions for Tizen:
[platform/core/uifw/vulkan-wsi-tizen.git] / wsi / swapchain_base_tizen.cpp
1 #include <array>
2 #include <cassert>
3 #include <cerrno>
4 #include <cstdio>
5 #include <cstdlib>
6
7 #include <unistd.h>
8 #include <vulkan/vulkan.h>
9
10 #include "swapchain_base_tizen.hpp"
11
12 #if VULKAN_WSI_DEBUG > 0
13 #define WSI_PRINT_ERROR(...) fprintf(stderr, ##__VA_ARGS__)
14 #else
15 #define WSI_PRINT_ERROR(...) (void)0
16 #endif
17
18 namespace wsi
19 {
20
21 swapchain_base::swapchain_base(layer::device_private_data &dev_data, const VkAllocationCallbacks *callbacks)
22    : m_device_data(dev_data)
23    , m_allocator(callbacks, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)
24    , m_swapchain_images(m_allocator)
25    , m_surface(VK_NULL_HANDLE)
26    , m_present_mode(VK_PRESENT_MODE_IMMEDIATE_KHR)
27    , m_descendant(VK_NULL_HANDLE)
28    , m_ancestor(VK_NULL_HANDLE)
29    , m_device(VK_NULL_HANDLE)
30    , m_queue(VK_NULL_HANDLE)
31 {
32 }
33
34 VkResult swapchain_base::init(VkDevice device, const VkSwapchainCreateInfoKHR *swapchain_create_info)
35 {
36    assert(device != VK_NULL_HANDLE);
37    assert(swapchain_create_info != nullptr);
38    assert(swapchain_create_info->surface != VK_NULL_HANDLE);
39
40    VkResult result;
41
42    m_device = device;
43    m_surface = swapchain_create_info->surface;
44
45    /* We have allocated images, we can call the platform init function if something needs to be done. */
46    result = init_platform(device, swapchain_create_info);
47    if (result != VK_SUCCESS)
48    {
49       return result;
50    }
51
52    VkImageCreateInfo image_create_info = {};
53    image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
54    image_create_info.pNext = nullptr;
55    image_create_info.imageType = VK_IMAGE_TYPE_2D;
56    image_create_info.format = swapchain_create_info->imageFormat;
57    image_create_info.extent = { swapchain_create_info->imageExtent.width, swapchain_create_info->imageExtent.height, 1 };
58    image_create_info.mipLevels = 1;
59    image_create_info.arrayLayers = swapchain_create_info->imageArrayLayers;
60    image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
61    image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
62    image_create_info.usage = swapchain_create_info->imageUsage;
63    image_create_info.flags = 0;
64    image_create_info.sharingMode = swapchain_create_info->imageSharingMode;
65    image_create_info.queueFamilyIndexCount = swapchain_create_info->queueFamilyIndexCount;
66    image_create_info.pQueueFamilyIndices = swapchain_create_info->pQueueFamilyIndices;
67    image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
68
69    result = create_image(image_create_info);
70    if (result != VK_SUCCESS)
71    {
72       return result;
73    }
74
75    m_device_data.disp.GetDeviceQueue(m_device, 0, 0, &m_queue);
76    result = m_device_data.SetDeviceLoaderData(m_device, m_queue);
77    if (VK_SUCCESS != result)
78    {
79       return result;
80    }
81
82    if (swapchain_create_info->oldSwapchain != VK_NULL_HANDLE)
83    {
84       /* TO BE DONE - How to reuse the old swapchain */
85           /*
86       m_ancestor = swapchain_create_info->oldSwapchain;
87
88       auto *ancestor = reinterpret_cast<swapchain_base *>(m_ancestor);
89       ancestor->deprecate(reinterpret_cast<VkSwapchainKHR>(this));
90       */
91    }
92
93    return VK_SUCCESS;
94 }
95
96 void swapchain_base::teardown()
97 {
98    if (m_queue != VK_NULL_HANDLE)
99    {
100       /* Make sure the vkFences are done signaling. */
101       m_device_data.disp.QueueWaitIdle(m_queue);
102    }
103 }
104
105 VkResult swapchain_base::acquire_next_image(uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *image_index)
106 {
107    VkResult retval;
108
109    retval = acquire_image(image_index);
110    if (retval != VK_SUCCESS)
111       return retval;
112
113    if (VK_NULL_HANDLE != semaphore || VK_NULL_HANDLE != fence)
114    {
115       VkSubmitInfo submit = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
116
117       if (VK_NULL_HANDLE != semaphore)
118       {
119          submit.signalSemaphoreCount = 1;
120          submit.pSignalSemaphores = &semaphore;
121       }
122
123       submit.commandBufferCount = 0;
124       submit.pCommandBuffers = nullptr;
125       retval = m_device_data.disp.QueueSubmit(m_queue, 1, &submit, fence);
126       assert(retval == VK_SUCCESS);
127    }
128
129    return VK_SUCCESS;
130 }
131
132 VkResult swapchain_base::get_swapchain_images(uint32_t *swapchain_image_count, VkImage *swapchain_images)
133 {
134    if (swapchain_images == nullptr)
135    {
136       /* Return the number of swapchain images. */
137       *swapchain_image_count = m_swapchain_images.size();
138
139       return VK_SUCCESS;
140    }
141    else
142    {
143       assert(m_swapchain_images.size() > 0);
144       assert(*swapchain_image_count > 0);
145
146       /* Populate array, write actual number of images returned. */
147       uint32_t current_image = 0;
148
149       do
150       {
151          swapchain_images[current_image] = m_swapchain_images[current_image].image;
152
153          current_image++;
154
155          if (current_image == m_swapchain_images.size())
156          {
157             *swapchain_image_count = current_image;
158
159             return VK_SUCCESS;
160          }
161
162       } while (current_image < *swapchain_image_count);
163
164       /* If swapchain_image_count is smaller than the number of presentable images
165        * in the swapchain, VK_INCOMPLETE must be returned instead of VK_SUCCESS. */
166       *swapchain_image_count = current_image;
167
168       return VK_INCOMPLETE;
169    }
170 }
171
172 VkResult swapchain_base::queue_present(VkQueue queue, const VkPresentInfoKHR *present_info, const uint32_t image_index)
173 {
174    VkResult result;
175
176    /* When the semaphore that comes in is signalled, we know that all work is done. So, we do not
177     * want to block any future Vulkan queue work on it. So, we pass in BOTTOM_OF_PIPE bit as the
178     * wait flag.
179     */
180    VkPipelineStageFlags pipeline_stage_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
181
182    VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO,
183                                NULL,
184                                present_info->waitSemaphoreCount,
185                                present_info->pWaitSemaphores,
186                                &pipeline_stage_flags,
187                                0,
188                                NULL,
189                                0,
190                                NULL };
191
192    result = m_device_data.disp.ResetFences(m_device, 1, &m_swapchain_images[image_index].present_fence);
193    if (result != VK_SUCCESS)
194    {
195       return result;
196    }
197
198    result = m_device_data.disp.QueueSubmit(queue, 1, &submit_info, m_swapchain_images[image_index].present_fence);
199    if (result != VK_SUCCESS)
200    {
201       return result;
202    }
203
204    present_image(image_index);
205
206    return VK_SUCCESS;
207 }
208
209 void swapchain_base::deprecate(VkSwapchainKHR descendant)
210 {
211    // TO BE DONE - release old swapchain resources
212 }
213
214 void swapchain_base::clear_ancestor()
215 {
216    m_ancestor = VK_NULL_HANDLE;
217 }
218
219 void swapchain_base::clear_descendant()
220 {
221    m_descendant = VK_NULL_HANDLE;
222 }
223
224 #undef WSI_PRINT_ERROR
225
226 } /* namespace wsi */
227