2 * Copyright (c) 2017-2019, 2021 Arm Limited.
4 * SPDX-License-Identifier: MIT
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 #define VK_USE_PLATFORM_WAYLAND_KHR 1
27 #include "swapchain.hpp"
36 #include <drm_fourcc.h>
38 #if VULKAN_WSI_DEBUG > 0
39 #define WSI_PRINT_ERROR(fmt, ...) fprintf(stderr, "[%s:%d - %s]" fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__)
41 #define WSI_PRINT_ERROR(...) (void)0
49 struct swapchain::tizen_image_data
52 tbm_surface_h tbm_buffer;
57 VkDeviceMemory memory;
60 swapchain::swapchain(layer::device_private_data &dev_data, const VkAllocationCallbacks *pAllocator)
61 : swapchain_base(dev_data, pAllocator)
65 swapchain::~swapchain()
69 tpl_surface_destroy_swapchain(m_tpl_surface);
70 tpl_object_unreference((tpl_object_t *)m_tpl_surface);
71 tpl_object_unreference((tpl_object_t *)m_tpl_display);
74 #define TBM_FORMAT_0 0
75 #define RETURN_FORMAT(comp, opaque, pre, post, inherit) \
77 if (comp == VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) \
78 return TBM_FORMAT_##opaque; \
79 else if (comp == VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) \
80 return TBM_FORMAT_##pre; \
81 else if (comp == VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) \
82 return TBM_FORMAT_##post; \
83 else if (comp == VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) \
84 return TBM_FORMAT_##inherit; \
90 static inline tbm_format
91 wsi_tizen_get_tbm_format(VkFormat format, VkCompositeAlphaFlagBitsKHR comp)
95 case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
96 RETURN_FORMAT(comp, RGBX4444, RGBA4444, 0, RGBA4444);
97 case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
98 RETURN_FORMAT(comp, BGRX4444, BGRA4444, 0, BGRA4444);
100 case VK_FORMAT_R5G6B5_UNORM_PACK16:
101 RETURN_FORMAT(comp, RGB565, RGB565, RGB565, RGB565);
102 case VK_FORMAT_B5G6R5_UNORM_PACK16:
103 RETURN_FORMAT(comp, BGR565, BGR565, BGR565, BGR565);
105 case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
106 RETURN_FORMAT(comp, RGBX5551, RGBA5551, 0, RGBA5551);
107 case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
108 RETURN_FORMAT(comp, BGRX5551, BGRA5551, 0, BGRA5551);
109 case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
110 RETURN_FORMAT(comp, XRGB1555, ARGB1555, 0, ARGB1555);
112 case VK_FORMAT_R8G8B8_UNORM:
113 RETURN_FORMAT(comp, BGR888, BGR888, BGR888, BGR888);
114 case VK_FORMAT_B8G8R8_UNORM:
115 RETURN_FORMAT(comp, RGB888, RGB888, RGB888, RGB888);
117 case VK_FORMAT_B8G8R8A8_UNORM:
118 RETURN_FORMAT(comp, XRGB8888, ARGB8888, 0, ARGB8888);
119 case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
120 RETURN_FORMAT(comp, XBGR8888, ABGR8888, 0, ABGR8888);
122 case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
123 RETURN_FORMAT(comp, XRGB2101010, ARGB2101010, 0, ARGB2101010);
124 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
125 RETURN_FORMAT(comp, XBGR2101010, ABGR2101010, 0, ABGR2101010);
133 VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKHR *pSwapchainCreateInfo)
135 VkIcdSurfaceWayland *vk_surf = reinterpret_cast<VkIcdSurfaceWayland *>(pSwapchainCreateInfo->surface);
137 int tpl_present_mode;
140 m_tpl_display = tpl_display_create(TPL_BACKEND_WAYLAND_VULKAN_WSI_THREAD, vk_surf->display);
141 if (m_tpl_display == NULL) {
142 WSI_PRINT_ERROR("create tpl display failed\n");
143 return VK_ERROR_INITIALIZATION_FAILED;
145 tpl_object_reference((tpl_object_t *)m_tpl_display);
147 format = wsi_tizen_get_tbm_format(pSwapchainCreateInfo->imageFormat, pSwapchainCreateInfo->compositeAlpha);
148 m_tpl_surface = tpl_surface_get(m_tpl_display, vk_surf->surface);
149 if (m_tpl_surface == NULL)
150 m_tpl_surface = tpl_surface_create(m_tpl_display, vk_surf->surface, TPL_SURFACE_TYPE_WINDOW, format);
152 if (m_tpl_surface == NULL) {
153 WSI_PRINT_ERROR("create tpl surface failed\n");
154 return VK_ERROR_INITIALIZATION_FAILED;
156 tpl_object_reference((tpl_object_t *)m_tpl_surface);
158 switch(pSwapchainCreateInfo->presentMode) {
159 case VK_PRESENT_MODE_IMMEDIATE_KHR:
160 tpl_present_mode = TPL_DISPLAY_PRESENT_MODE_IMMEDIATE;
162 case VK_PRESENT_MODE_MAILBOX_KHR:
163 tpl_present_mode = TPL_DISPLAY_PRESENT_MODE_MAILBOX;
165 case VK_PRESENT_MODE_FIFO_KHR:
166 tpl_present_mode = TPL_DISPLAY_PRESENT_MODE_FIFO;
168 case VK_PRESENT_MODE_FIFO_RELAXED_KHR:
169 tpl_present_mode = TPL_DISPLAY_PRESENT_MODE_FIFO_RELAXED;
172 WSI_PRINT_ERROR("unsupported present mode, presentMode[%d].", pSwapchainCreateInfo->presentMode);
173 return VK_ERROR_INITIALIZATION_FAILED;
176 res = tpl_surface_create_swapchain(m_tpl_surface, format,
177 pSwapchainCreateInfo->imageExtent.width, pSwapchainCreateInfo->imageExtent.height,
178 pSwapchainCreateInfo->minImageCount, tpl_present_mode);
179 if (res != TPL_ERROR_NONE) {
180 WSI_PRINT_ERROR("create swapchain failed, ret[%d].\n", res);
181 return VK_ERROR_INITIALIZATION_FAILED;
187 VkResult swapchain::allocate_image(const VkImageCreateInfo &image_create_info, tizen_image_data *image_data,
190 VkResult result = VK_SUCCESS;
192 assert(image_data->stride >= 0);
193 VkSubresourceLayout image_layout = {};
194 image_layout.offset = image_data->offset;
195 image_layout.rowPitch = static_cast<uint32_t>(image_data->stride);
196 VkImageDrmFormatModifierExplicitCreateInfoEXT drm_mod_info = {};
197 drm_mod_info.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT;
198 drm_mod_info.pNext = image_create_info.pNext;
199 drm_mod_info.drmFormatModifier = DRM_FORMAT_MOD_LINEAR;
200 drm_mod_info.drmFormatModifierPlaneCount = 1;
201 drm_mod_info.pPlaneLayouts = &image_layout;
203 VkExternalMemoryImageCreateInfoKHR external_info = {};
204 external_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR;
205 external_info.pNext = &drm_mod_info;
206 external_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
208 VkImageCreateInfo image_info = image_create_info;
209 image_info.pNext = &external_info;
210 image_info.tiling = VK_IMAGE_TILING_LINEAR;
211 result = m_device_data.disp.CreateImage(m_device, &image_info, get_allocation_callbacks(), image);
212 if (result != VK_SUCCESS)
214 WSI_PRINT_ERROR("Image creation failed.\n");
218 VkMemoryFdPropertiesKHR mem_props = {};
219 mem_props.sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR;
221 result = m_device_data.disp.GetMemoryFdPropertiesKHR(m_device, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
222 image_data->buffer_fd, &mem_props);
223 if (result != VK_SUCCESS)
225 WSI_PRINT_ERROR("Error querying Fd properties.\n");
230 for (mem_idx = 0; mem_idx < VK_MAX_MEMORY_TYPES; mem_idx++)
232 if (mem_props.memoryTypeBits & (1 << mem_idx))
237 off_t dma_buf_size = lseek(image_data->buffer_fd, 0, SEEK_END);
238 if (dma_buf_size < 0)
240 WSI_PRINT_ERROR("Failed to get DMA Buf size.\n");
241 return VK_ERROR_OUT_OF_HOST_MEMORY;
244 VkImportMemoryFdInfoKHR import_mem_info = {};
245 import_mem_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
246 import_mem_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
247 import_mem_info.fd = image_data->buffer_fd;
249 VkMemoryAllocateInfo alloc_info = {};
250 alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
251 alloc_info.pNext = &import_mem_info;
252 alloc_info.allocationSize = static_cast<uint64_t>(dma_buf_size);
253 alloc_info.memoryTypeIndex = mem_idx;
255 result = m_device_data.disp.AllocateMemory(m_device, &alloc_info, get_allocation_callbacks(), &image_data->memory);
257 if (result != VK_SUCCESS)
259 WSI_PRINT_ERROR("Failed to import memory.\n");
262 result = m_device_data.disp.BindImageMemory(m_device, *image, image_data->memory, 0);
267 VkResult swapchain::create_image(const VkImageCreateInfo &image_create_info)
269 VkResult result = VK_SUCCESS;
271 tbm_surface_h *buffers;
272 int tbm_buf_cnt, i = 0;
274 res = tpl_surface_get_swapchain_buffers(m_tpl_surface, &buffers, &tbm_buf_cnt);
275 if (res == TPL_ERROR_OUT_OF_MEMORY)
276 return VK_ERROR_OUT_OF_HOST_MEMORY;
277 else if (res != TPL_ERROR_NONE)
278 return VK_ERROR_INITIALIZATION_FAILED;
280 if (!m_swapchain_images.try_resize(tbm_buf_cnt))
281 return VK_ERROR_OUT_OF_HOST_MEMORY;
284 for (auto &image: m_swapchain_images) {
285 tizen_image_data *image_data = nullptr;
286 if (get_allocation_callbacks() != nullptr)
288 image_data = static_cast<tizen_image_data *>(
289 get_allocation_callbacks()->pfnAllocation(get_allocation_callbacks()->pUserData, sizeof(tizen_image_data),
290 alignof(tizen_image_data), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT));
292 image_data = static_cast<tizen_image_data *>(malloc(sizeof(tizen_image_data)));
295 tbm_surface_info_s info;
296 tbm_bo bo = tbm_surface_internal_get_bo(buffers[i], 0);
297 tbm_bo_handle bo_handle = tbm_bo_get_handle(bo, TBM_DEVICE_3D);
298 tbm_surface_get_info(buffers[i], &info);
300 image_data->tbm_buffer = buffers[i];
301 image_data->buffer_fd = bo_handle.u32;
302 image_data->stride = info.planes[0].stride;
303 image_data->offset = info.planes[0].offset;
304 image_data->memory = VK_NULL_HANDLE;
306 image.data = static_cast<void *>(image_data);
308 result = allocate_image(image_create_info, image_data, &image.image);
309 if (result != VK_SUCCESS)
311 WSI_PRINT_ERROR("Failed to allocate image.\n");
315 /* Initialize presentation fence. */
316 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, 0 };
317 result = m_device_data.disp.CreateFence(m_device, &fenceInfo, get_allocation_callbacks(), &image.present_fence);
331 VkResult swapchain::acquire_image(uint32_t *image_index)
333 tbm_surface_h tbm_buf = tpl_surface_dequeue_buffer_with_sync(m_tpl_surface, UINT64_MAX, NULL);
336 return VK_ERROR_SURFACE_LOST_KHR;
338 for (unsigned int i = 0; i < m_swapchain_images.size(); i++) {
339 tizen_image_data *image_data = reinterpret_cast<tizen_image_data *>(m_swapchain_images[i].data);
340 if (image_data->tbm_buffer == tbm_buf) {
346 return VK_ERROR_SURFACE_LOST_KHR;
349 void swapchain::present_image(uint32_t pendingIndex)
351 tizen_image_data *image_data = reinterpret_cast<tizen_image_data *>(m_swapchain_images[pendingIndex].data);
352 tpl_surface_enqueue_buffer_with_damage_and_sync(m_tpl_surface, image_data->tbm_buffer, 0, NULL, -1);
355 void swapchain::destroy_image(void)
357 for (auto &image: m_swapchain_images) {
358 if (image.present_fence != VK_NULL_HANDLE)
360 m_device_data.disp.DestroyFence(m_device, image.present_fence, get_allocation_callbacks());
361 image.present_fence = VK_NULL_HANDLE;
363 if (image.image != VK_NULL_HANDLE)
365 m_device_data.disp.DestroyImage(m_device, image.image, get_allocation_callbacks());
366 image.image = VK_NULL_HANDLE;
368 if (image.data != nullptr)
370 tizen_image_data *image_data = reinterpret_cast<tizen_image_data *>(image.data);
371 if (image_data->memory != VK_NULL_HANDLE)
373 m_device_data.disp.FreeMemory(m_device, image_data->memory, get_allocation_callbacks());
375 else if (image_data->buffer_fd >= 0)
377 close(image_data->buffer_fd);
379 if (get_allocation_callbacks() != nullptr)
381 get_allocation_callbacks()->pfnFree(get_allocation_callbacks()->pUserData, image_data);
387 image.data = nullptr;
392 } // namespace wayland