From cef34cc5d433e1e34b5da2ed8859f8926e8a9bc2 Mon Sep 17 00:00:00 2001 From: Tianhao Ni Date: Mon, 12 Apr 2021 10:16:23 +0800 Subject: [PATCH] Implement WSI layer swapchain functions for Tizen: 1. Create TPL swapchain for Tizen platform; 2. Alloc tbm buffer for vulkan image; 3. Acquire and present image via dequeue/enqueue tpl buffer queue. Change-Id: I5319c45fe0aa7f0f508b6279532412467d4fe438 Signed-off-by: Tianhao Ni --- CMakeLists.txt | 49 +-- wsi/swapchain_base_tizen.cpp | 227 +++++++++++ wsi/swapchain_base_tizen.hpp | 235 +++++++++++ wsi/tizen/surface_properties.cpp | 27 +- wsi/tizen/swapchain.cpp | 779 ++++++++++++------------------------- wsi/tizen/swapchain.hpp | 73 +--- wsi/tizen/swapchain_wl_helpers.cpp | 130 ------- wsi/tizen/swapchain_wl_helpers.hpp | 49 --- wsi/wsi_factory.cpp | 36 +- wsi/wsi_factory.hpp | 4 + 10 files changed, 775 insertions(+), 834 deletions(-) create mode 100644 wsi/swapchain_base_tizen.cpp create mode 100644 wsi/swapchain_base_tizen.hpp delete mode 100644 wsi/tizen/swapchain_wl_helpers.cpp delete mode 100644 wsi/tizen/swapchain_wl_helpers.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 23cf287..0b43e99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,10 +59,6 @@ if(BUILD_WSI_WAYLAND) set(BUILD_DRM_UTILS True) endif() -if(BUILD_WSI_TIZEN) - set(BUILD_DRM_UTILS True) -endif() - # DRM Utilities if(BUILD_DRM_UTILS) add_library(drm_utils STATIC util/drm/drm_utils.cpp) @@ -145,51 +141,30 @@ if(BUILD_WSI_WAYLAND) elseif(BUILD_WSI_TIZEN) add_library(tizen_wsi STATIC wsi/tizen/surface_properties.cpp - wsi/tizen/swapchain_wl_helpers.cpp wsi/tizen/swapchain.cpp) - pkg_check_modules(WAYLAND_CLIENT REQUIRED wayland-client) - message(STATUS "Using Wayland client include directories: ${WAYLAND_CLIENT_INCLUDE_DIRS}") - message(STATUS "Using Wayland client cflags: ${WAYLAND_CLIENT_CFLAGS}") - message(STATUS "Using Wayland client ldflags: ${WAYLAND_CLIENT_LDFLAGS}") - - pkg_check_modules(WAYLAND_SCANNER REQUIRED wayland-scanner) - pkg_get_variable(WAYLAND_SCANNER_EXEC wayland-scanner wayland_scanner) - message(STATUS "Using wayland-scanner : ${WAYLAND_SCANNER_EXEC}") - - pkg_check_modules(WAYLAND_PROTOCOLS REQUIRED wayland-protocols) - pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) - message(STATUS "Using wayland protocols dir : ${WAYLAND_PROTOCOLS_DIR}") - - add_custom_target(wayland_generated_files - COMMAND ${WAYLAND_SCANNER_EXEC} client-header - ${WAYLAND_PROTOCOLS_DIR}/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml - ${CMAKE_CURRENT_BINARY_DIR}/linux-dmabuf-unstable-v1-client-protocol.h - COMMAND ${WAYLAND_SCANNER_EXEC} code - ${WAYLAND_PROTOCOLS_DIR}/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml - ${CMAKE_CURRENT_BINARY_DIR}/linux-dmabuf-unstable-v1-protocol.c - BYPRODUCTS linux-dmabuf-unstable-v1-protocol.c linux-dmabuf-unstable-v1-client-protocol.h) - - target_sources(tizen_wsi PRIVATE - ${CMAKE_CURRENT_BINARY_DIR}/linux-dmabuf-unstable-v1-protocol.c - ${CMAKE_CURRENT_BINARY_DIR}/linux-dmabuf-unstable-v1-client-protocol.h) - add_dependencies(tizen_wsi wayland_generated_files) + pkg_check_modules(LIBDRM REQUIRED libdrm) + message(STATUS "Using libdrm include directories: ${LIBDRM_INCLUDE_DIRS}") target_include_directories(tizen_wsi PRIVATE ${PROJECT_SOURCE_DIR} ${VULKAN_CXX_INCLUDE} - ${WAYLAND_CLIENT_INCLUDE_DIRS} - ${CMAKE_CURRENT_BINARY_DIR}) + ${CMAKE_CURRENT_BINARY_DIR} + ${LIBDRM_INCLUDE_DIRS}) - target_compile_options(tizen_wsi PRIVATE ${WAYLAND_CLIENT_CFLAGS}) target_compile_options(tizen_wsi INTERFACE "-DBUILD_WSI_TIZEN=1") - target_link_libraries(tizen_wsi dlog tbm tpl-egl drm_utils ${WAYLAND_CLIENT_LDFLAGS}) + target_link_libraries(tizen_wsi dlog tbm tpl-egl) list(APPEND LINK_WSI_LIBS tizen_wsi) else() list(APPEND JSON_COMMANDS COMMAND sed -i '/VK_KHR_wayland_surface/d' ${CMAKE_CURRENT_BINARY_DIR}/VkLayer_window_system_integration.json) endif() # Layer +if(BUILD_WSI_TIZEN) + set(WSI_PLATFORM_SPECIFIED wsi/swapchain_base_tizen.cpp) +else() + set(WSI_PLATFORM_SPECIFIED wsi/swapchain_base.cpp wsi/headless/surface_properties.cpp wsi/headless/swapchain.cpp) +endif() add_library(${PROJECT_NAME} SHARED layer/layer.cpp layer/private_data.cpp @@ -198,10 +173,8 @@ add_library(${PROJECT_NAME} SHARED util/timed_semaphore.cpp util/custom_allocator.cpp util/extension_list.cpp - wsi/swapchain_base.cpp wsi/wsi_factory.cpp - wsi/headless/surface_properties.cpp - wsi/headless/swapchain.cpp) + ${WSI_PLATFORM_SPECIFIED}) target_compile_definitions(${PROJECT_NAME} PRIVATE ${WSI_DEFINES}) target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${VULKAN_CXX_INCLUDE}) diff --git a/wsi/swapchain_base_tizen.cpp b/wsi/swapchain_base_tizen.cpp new file mode 100644 index 0000000..acbafb6 --- /dev/null +++ b/wsi/swapchain_base_tizen.cpp @@ -0,0 +1,227 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include "swapchain_base_tizen.hpp" + +#if VULKAN_WSI_DEBUG > 0 +#define WSI_PRINT_ERROR(...) fprintf(stderr, ##__VA_ARGS__) +#else +#define WSI_PRINT_ERROR(...) (void)0 +#endif + +namespace wsi +{ + +swapchain_base::swapchain_base(layer::device_private_data &dev_data, const VkAllocationCallbacks *callbacks) + : m_device_data(dev_data) + , m_allocator(callbacks, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT) + , m_swapchain_images(m_allocator) + , m_surface(VK_NULL_HANDLE) + , m_present_mode(VK_PRESENT_MODE_IMMEDIATE_KHR) + , m_descendant(VK_NULL_HANDLE) + , m_ancestor(VK_NULL_HANDLE) + , m_device(VK_NULL_HANDLE) + , m_queue(VK_NULL_HANDLE) +{ +} + +VkResult swapchain_base::init(VkDevice device, const VkSwapchainCreateInfoKHR *swapchain_create_info) +{ + assert(device != VK_NULL_HANDLE); + assert(swapchain_create_info != nullptr); + assert(swapchain_create_info->surface != VK_NULL_HANDLE); + + VkResult result; + + m_device = device; + m_surface = swapchain_create_info->surface; + + /* We have allocated images, we can call the platform init function if something needs to be done. */ + result = init_platform(device, swapchain_create_info); + if (result != VK_SUCCESS) + { + return result; + } + + VkImageCreateInfo image_create_info = {}; + image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + image_create_info.pNext = nullptr; + image_create_info.imageType = VK_IMAGE_TYPE_2D; + image_create_info.format = swapchain_create_info->imageFormat; + image_create_info.extent = { swapchain_create_info->imageExtent.width, swapchain_create_info->imageExtent.height, 1 }; + image_create_info.mipLevels = 1; + image_create_info.arrayLayers = swapchain_create_info->imageArrayLayers; + image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; + image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; + image_create_info.usage = swapchain_create_info->imageUsage; + image_create_info.flags = 0; + image_create_info.sharingMode = swapchain_create_info->imageSharingMode; + image_create_info.queueFamilyIndexCount = swapchain_create_info->queueFamilyIndexCount; + image_create_info.pQueueFamilyIndices = swapchain_create_info->pQueueFamilyIndices; + image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + result = create_image(image_create_info); + if (result != VK_SUCCESS) + { + return result; + } + + m_device_data.disp.GetDeviceQueue(m_device, 0, 0, &m_queue); + result = m_device_data.SetDeviceLoaderData(m_device, m_queue); + if (VK_SUCCESS != result) + { + return result; + } + + if (swapchain_create_info->oldSwapchain != VK_NULL_HANDLE) + { + /* TO BE DONE - How to reuse the old swapchain */ + /* + m_ancestor = swapchain_create_info->oldSwapchain; + + auto *ancestor = reinterpret_cast(m_ancestor); + ancestor->deprecate(reinterpret_cast(this)); + */ + } + + return VK_SUCCESS; +} + +void swapchain_base::teardown() +{ + if (m_queue != VK_NULL_HANDLE) + { + /* Make sure the vkFences are done signaling. */ + m_device_data.disp.QueueWaitIdle(m_queue); + } +} + +VkResult swapchain_base::acquire_next_image(uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *image_index) +{ + VkResult retval; + + retval = acquire_image(image_index); + if (retval != VK_SUCCESS) + return retval; + + if (VK_NULL_HANDLE != semaphore || VK_NULL_HANDLE != fence) + { + VkSubmitInfo submit = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; + + if (VK_NULL_HANDLE != semaphore) + { + submit.signalSemaphoreCount = 1; + submit.pSignalSemaphores = &semaphore; + } + + submit.commandBufferCount = 0; + submit.pCommandBuffers = nullptr; + retval = m_device_data.disp.QueueSubmit(m_queue, 1, &submit, fence); + assert(retval == VK_SUCCESS); + } + + return VK_SUCCESS; +} + +VkResult swapchain_base::get_swapchain_images(uint32_t *swapchain_image_count, VkImage *swapchain_images) +{ + if (swapchain_images == nullptr) + { + /* Return the number of swapchain images. */ + *swapchain_image_count = m_swapchain_images.size(); + + return VK_SUCCESS; + } + else + { + assert(m_swapchain_images.size() > 0); + assert(*swapchain_image_count > 0); + + /* Populate array, write actual number of images returned. */ + uint32_t current_image = 0; + + do + { + swapchain_images[current_image] = m_swapchain_images[current_image].image; + + current_image++; + + if (current_image == m_swapchain_images.size()) + { + *swapchain_image_count = current_image; + + return VK_SUCCESS; + } + + } while (current_image < *swapchain_image_count); + + /* If swapchain_image_count is smaller than the number of presentable images + * in the swapchain, VK_INCOMPLETE must be returned instead of VK_SUCCESS. */ + *swapchain_image_count = current_image; + + return VK_INCOMPLETE; + } +} + +VkResult swapchain_base::queue_present(VkQueue queue, const VkPresentInfoKHR *present_info, const uint32_t image_index) +{ + VkResult result; + + /* When the semaphore that comes in is signalled, we know that all work is done. So, we do not + * want to block any future Vulkan queue work on it. So, we pass in BOTTOM_OF_PIPE bit as the + * wait flag. + */ + VkPipelineStageFlags pipeline_stage_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + + VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO, + NULL, + present_info->waitSemaphoreCount, + present_info->pWaitSemaphores, + &pipeline_stage_flags, + 0, + NULL, + 0, + NULL }; + + result = m_device_data.disp.ResetFences(m_device, 1, &m_swapchain_images[image_index].present_fence); + if (result != VK_SUCCESS) + { + return result; + } + + result = m_device_data.disp.QueueSubmit(queue, 1, &submit_info, m_swapchain_images[image_index].present_fence); + if (result != VK_SUCCESS) + { + return result; + } + + present_image(image_index); + + return VK_SUCCESS; +} + +void swapchain_base::deprecate(VkSwapchainKHR descendant) +{ + // TO BE DONE - release old swapchain resources +} + +void swapchain_base::clear_ancestor() +{ + m_ancestor = VK_NULL_HANDLE; +} + +void swapchain_base::clear_descendant() +{ + m_descendant = VK_NULL_HANDLE; +} + +#undef WSI_PRINT_ERROR + +} /* namespace wsi */ + diff --git a/wsi/swapchain_base_tizen.hpp b/wsi/swapchain_base_tizen.hpp new file mode 100644 index 0000000..9c6ff27 --- /dev/null +++ b/wsi/swapchain_base_tizen.hpp @@ -0,0 +1,235 @@ +#pragma once + +#include + +#include +#include +#include + +namespace wsi +{ +struct swapchain_image +{ + /* Implementation specific data */ + void *data{nullptr}; + + VkImage image{VK_NULL_HANDLE}; + VkFence present_fence{VK_NULL_HANDLE}; +}; + +/** + * @brief Base swapchain class + * + * - the swapchain implementations inherit from this class. + * - the VkSwapchain will hold a pointer to this class. + * - much of the swapchain implementation is done by this class, as the only things needed + * in the implementation are how to create a presentable image and how to present an image. + */ +class swapchain_base +{ +public: + swapchain_base(layer::device_private_data &dev_data, const VkAllocationCallbacks *allocator); + + virtual ~swapchain_base() + { + /* nop */ + } + + /** + * @brief Create swapchain. + * + * Perform all swapchain initialization, create presentable images etc. + */ + VkResult init(VkDevice device, const VkSwapchainCreateInfoKHR *swapchain_create_info); + + /** + * @brief Acquires a free image. + * + * Current implementation blocks until a free image is available. + * + * @param timeout Unused since we block until a free image is available. + * + * @param semaphore A semaphore signaled once an image is acquired. + * + * @param fence A fence signaled once an image is acquired. + * + * @param pImageIndex The index of the acquired image. + * + * @return VK_SUCCESS on completion. + */ + VkResult acquire_next_image(uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *image_index); + + /** + * @brief Gets the number of swapchain images or a number of at most + * m_num_swapchain_images images. + * + * @param pSwapchainImageCount Used to return number of images in + * the swapchain if second parameter is nullptr or represents the + * number of images to be returned in second parameter. + * + * @param pSwapchainImage Array of VkImage handles. + * + * @return If number of requested images is less than the number of available + * images in the swapchain returns VK_INCOMPLETE otherwise VK_SUCCESS. + */ + VkResult get_swapchain_images(uint32_t *swapchain_image_count, VkImage *swapchain_image); + + /** + * @brief Submits a present request for the supplied image. + * + * @param queue The queue to which the submission will be made to. + * + * @param pPresentInfo Information about the swapchain and image to be presented. + * + * @param imageIndex The index of the image to be presented. + * + * @return If queue submission fails returns error of vkQueueSubmit, if the + * swapchain has a descendant who started presenting returns VK_ERROR_OUT_OF_DATE_KHR, + * otherwise returns VK_SUCCESS. + */ + VkResult queue_present(VkQueue queue, const VkPresentInfoKHR *present_info, const uint32_t image_index); + +protected: + + layer::device_private_data &m_device_data; + + /** + * @brief User provided memory allocation callbacks. + */ + const util::allocator m_allocator; + + /** + * @brief Vector of images in the swapchain. + */ + util::vector m_swapchain_images; + + /** + * @brief Handle to the surface object this swapchain will present images to. + */ + VkSurfaceKHR m_surface; + + /** + * @brief present mode to use for this swapchain + */ + VkPresentModeKHR m_present_mode; + + /** + * @brief Descendant of this swapchain. + * Used to check whether or not a descendant of this swapchain has started + * presenting images to the surface already. If it has, any calls to queuePresent + * for this swapchain will return VK_ERROR_OUT_OF_DATE_KHR. + */ + VkSwapchainKHR m_descendant; + + /** + * @brief Ancestor of this swapchain. + * Used to check whether the ancestor swapchain has completed all of its + * pending page flips (this is required before this swapchain presents for the + * first time. + */ + VkSwapchainKHR m_ancestor; + + /** + * @brief Handle to the logical device the swapchain is created for. + */ + VkDevice m_device; + + /** + * @brief Handle to the queue used for signalling submissions + */ + VkQueue m_queue; + + /** + * @brief Return the VkAllocationCallbacks passed in this object constructor. + */ + const VkAllocationCallbacks *get_allocation_callbacks() + { + return m_allocator.get_original_callbacks(); + } + + /** + * @brief Method to wait on all pending buffers to be displayed. + */ + void wait_for_pending_buffers(); + + /** + * @brief Remove cached ancestor. + */ + void clear_ancestor(); + + /** + * @brief Remove cached descendant. + */ + void clear_descendant(); + + /** + * @brief Deprecate this swapchain. + * + * If an application replaces an old swapchain with a new one, the older swapchain + * needs to be deprecated. This method releases all the FREE images and sets the + * descendant of the swapchain. We do not need to care about images in other states + * at this point since they will be released by the page flip thread. + * + * @param descendant Handle to the descendant swapchain. + */ + void deprecate(VkSwapchainKHR descendant); + + /** + * @brief Platform specific initialization + */ + virtual VkResult init_platform(VkDevice device, const VkSwapchainCreateInfoKHR *swapchain_create_info) = 0; + + /** + * @brief Base swapchain teardown. + * + * Even though the inheritance gives us a nice way to defer display specific allocation + * and presentation outside of the base class, it however robs the children classes - which + * also happen to do some of their state setting - the oppurtunity to do the last clean up + * call, as the base class' destructor is called at the end. This method provides a way to do it. + * The destructor is a virtual function and much of the swapchain teardown happens in this method + * which gets called from the child's destructor. + */ + void teardown(); + + /** + * @brief Creates a new swapchain image. + * + * @param image_create_info Data to be used to create the image. + * + * @param image Handle to the image. + * + * @return If image creation is successful returns VK_SUCCESS, otherwise + * will return VK_ERROR_OUT_OF_DEVICE_MEMORY or VK_ERROR_INITIALIZATION_FAILED + * depending on the error that occured. + */ + virtual VkResult create_image(const VkImageCreateInfo &image_create_info) = 0; + + virtual VkResult acquire_image(uint32_t *image_index) = 0; + + /** + * @brief Method to present and image + * + * @param pending_index Index of the pending image to be presented. + * + */ + virtual void present_image(uint32_t pending_index) = 0; + + /** + * @brief Transition a presented image to free. + * + * Called by swapchain implementation when a new image has been presented. + * + * @param presented_index Index of the image to be marked as free. + */ + void unpresent_image(uint32_t presented_index); + + /** + * @brief Method to release a swapchain image + * + * @param image Handle to the image about to be released. + */ + virtual void destroy_image(void){}; +}; + +} /* namespace wsi */ + diff --git a/wsi/tizen/surface_properties.cpp b/wsi/tizen/surface_properties.cpp index 28fc5cb..3bd73d7 100644 --- a/wsi/tizen/surface_properties.cpp +++ b/wsi/tizen/surface_properties.cpp @@ -21,10 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#define VK_USE_PLATFORM_WAYLAND_KHR 1 extern "C" { -#include -#include +#include +#include } #include @@ -51,10 +52,26 @@ surface_properties &surface_properties::get_instance() VkResult surface_properties::get_surface_capabilities(VkPhysicalDevice physical_device, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) { + VkIcdSurfaceWayland *vk_surf = reinterpret_cast(surface); + tpl_result_t res; + + if (vk_surf == NULL || vk_surf->display == NULL || vk_surf->surface == NULL) + return VK_ERROR_SURFACE_LOST_KHR; + + tpl_display_t *tpl_display = tpl_display_create(TPL_BACKEND_WAYLAND_VULKAN_WSI, vk_surf->display); + if (tpl_display == NULL) { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + int cnt_min = 0, cnt_max = 0; + res = tpl_display_query_supported_buffer_count_from_native_window(tpl_display, vk_surf->display, &cnt_min, &cnt_max); + if (res != TPL_ERROR_NONE) { + return VK_ERROR_SURFACE_LOST_KHR; + } + /* Image count limits */ - pSurfaceCapabilities->minImageCount = 2; - /* There is no maximum theoretically speaking */ - pSurfaceCapabilities->maxImageCount = UINT32_MAX; + pSurfaceCapabilities->minImageCount = cnt_min; + pSurfaceCapabilities->maxImageCount = cnt_max; /* Surface extents */ pSurfaceCapabilities->currentExtent = { 0xffffffff, 0xffffffff }; diff --git a/wsi/tizen/swapchain.cpp b/wsi/tizen/swapchain.cpp index edc6453..77d6983 100644 --- a/wsi/tizen/swapchain.cpp +++ b/wsi/tizen/swapchain.cpp @@ -25,7 +25,6 @@ #define VK_USE_PLATFORM_WAYLAND_KHR 1 #include "swapchain.hpp" -#include "swapchain_wl_helpers.hpp" #include #include @@ -36,10 +35,8 @@ #include #include -#include "util/drm/drm_utils.hpp" - #if VULKAN_WSI_DEBUG > 0 -#define WSI_PRINT_ERROR(...) fprintf(stderr, __FILE__, __LINE__, __func__, ##__VA_ARGS__) +#define WSI_PRINT_ERROR(fmt, ...) fprintf(stderr, "[%s:%d - %s]" fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__) #else #define WSI_PRINT_ERROR(...) (void)0 #endif @@ -49,645 +46,347 @@ namespace wsi namespace tizen { -struct swapchain::wayland_image_data +struct swapchain::tizen_image_data { int buffer_fd; + tbm_surface_h tbm_buffer; + int stride; uint32_t offset; - wl_buffer *buffer; VkDeviceMemory memory; }; swapchain::swapchain(layer::device_private_data &dev_data, const VkAllocationCallbacks *pAllocator) : swapchain_base(dev_data, pAllocator) - , m_display(nullptr) - , m_surface(nullptr) - , m_dmabuf_interface(nullptr) - , m_surface_queue(nullptr) - , m_buffer_queue(nullptr) - , m_present_pending(false) { } swapchain::~swapchain() { - //int res; teardown(); - if (m_dmabuf_interface != nullptr) - { - zwp_linux_dmabuf_v1_destroy(m_dmabuf_interface); - } - /* - res = wsialloc_delete(&m_wsi_allocator); - if (res != 0) - { - WSI_PRINT_ERROR("error deleting the allocator: %d\n", res); - }*/ - if (m_surface_queue != nullptr) - { - wl_event_queue_destroy(m_surface_queue); - } - if (m_buffer_queue != nullptr) - { - wl_event_queue_destroy(m_buffer_queue); - } + destroy_image(); + tpl_surface_destroy_swapchain(m_tpl_surface); + tpl_object_unreference((tpl_object_t *)m_tpl_surface); + tpl_object_unreference((tpl_object_t *)m_tpl_display); } -static void roundtrip_cb_done(void *data, wl_callback *cb, uint32_t cb_data) +#define TBM_FORMAT_0 0 +#define RETURN_FORMAT(comp, opaque, pre, post, inherit) \ + do { \ + if (comp == VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) \ + return TBM_FORMAT_##opaque; \ + else if (comp == VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) \ + return TBM_FORMAT_##pre; \ + else if (comp == VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) \ + return TBM_FORMAT_##post; \ + else if (comp == VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) \ + return TBM_FORMAT_##inherit; \ + else \ + return 0; \ + } while (0) + + +static inline tbm_format +wsi_tizen_get_tbm_format(VkFormat format, VkCompositeAlphaFlagBitsKHR comp) { - (void)cb_data; - - bool *cb_recvd = reinterpret_cast(data); - assert(cb_recvd); - - *cb_recvd = true; + switch (format) { + /* 4 4 4 4 */ + case VK_FORMAT_R4G4B4A4_UNORM_PACK16: + RETURN_FORMAT(comp, RGBX4444, RGBA4444, 0, RGBA4444); + case VK_FORMAT_B4G4R4A4_UNORM_PACK16: + RETURN_FORMAT(comp, BGRX4444, BGRA4444, 0, BGRA4444); + /* 5 6 5 */ + case VK_FORMAT_R5G6B5_UNORM_PACK16: + RETURN_FORMAT(comp, RGB565, RGB565, RGB565, RGB565); + case VK_FORMAT_B5G6R5_UNORM_PACK16: + RETURN_FORMAT(comp, BGR565, BGR565, BGR565, BGR565); + /* 5 5 5 1 */ + case VK_FORMAT_R5G5B5A1_UNORM_PACK16: + RETURN_FORMAT(comp, RGBX5551, RGBA5551, 0, RGBA5551); + case VK_FORMAT_B5G5R5A1_UNORM_PACK16: + RETURN_FORMAT(comp, BGRX5551, BGRA5551, 0, BGRA5551); + case VK_FORMAT_A1R5G5B5_UNORM_PACK16: + RETURN_FORMAT(comp, XRGB1555, ARGB1555, 0, ARGB1555); + /* 8 8 8 */ + case VK_FORMAT_R8G8B8_UNORM: + RETURN_FORMAT(comp, BGR888, BGR888, BGR888, BGR888); + case VK_FORMAT_B8G8R8_UNORM: + RETURN_FORMAT(comp, RGB888, RGB888, RGB888, RGB888); + /* 8 8 8 8 */ + case VK_FORMAT_B8G8R8A8_UNORM: + RETURN_FORMAT(comp, XRGB8888, ARGB8888, 0, ARGB8888); + case VK_FORMAT_A8B8G8R8_UNORM_PACK32: + RETURN_FORMAT(comp, XBGR8888, ABGR8888, 0, ABGR8888); + /* 2 10 10 10 */ + case VK_FORMAT_A2R10G10B10_UNORM_PACK32: + RETURN_FORMAT(comp, XRGB2101010, ARGB2101010, 0, ARGB2101010); + case VK_FORMAT_A2B10G10R10_UNORM_PACK32: + RETURN_FORMAT(comp, XBGR2101010, ABGR2101010, 0, ABGR2101010); + default: + break; + } + + return 0; } -int swapchain::roundtrip() +VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKHR *pSwapchainCreateInfo) { - int res; - const wl_callback_listener listener = { roundtrip_cb_done }; - bool cb_recvd = false; + VkIcdSurfaceWayland *vk_surf = reinterpret_cast(pSwapchainCreateInfo->surface); + tbm_format format; + int tpl_present_mode; + tpl_result_t res; - wl_callback *cb = wl_display_sync(m_display); - if (!cb) - { - WSI_PRINT_ERROR("failed to create wl_display::sync callback\n"); - res = -1; - goto exit; + m_tpl_display = tpl_display_create(TPL_BACKEND_WAYLAND_VULKAN_WSI_THREAD, vk_surf->display); + if (m_tpl_display == NULL) { + WSI_PRINT_ERROR("create tpl display failed\n"); + return VK_ERROR_INITIALIZATION_FAILED; } + tpl_object_reference((tpl_object_t *)m_tpl_display); - wl_proxy_set_queue((wl_proxy *)cb, m_surface_queue); + format = wsi_tizen_get_tbm_format(pSwapchainCreateInfo->imageFormat, pSwapchainCreateInfo->compositeAlpha); + m_tpl_surface = tpl_surface_get(m_tpl_display, vk_surf->surface); + if (m_tpl_surface == NULL) + m_tpl_surface = tpl_surface_create(m_tpl_display, vk_surf->surface, TPL_SURFACE_TYPE_WINDOW, format); - res = wl_callback_add_listener(cb, &listener, &cb_recvd); - if (res == -1) - { - WSI_PRINT_ERROR("error setting wl_display::sync callback listener\n"); - goto exit; + if (m_tpl_surface == NULL) { + WSI_PRINT_ERROR("create tpl surface failed\n"); + return VK_ERROR_INITIALIZATION_FAILED; } + tpl_object_reference((tpl_object_t *)m_tpl_surface); - res = wl_display_flush(m_display); - if (res == -1) - { - WSI_PRINT_ERROR("error performing a flush on the display\n"); - goto exit; + switch(pSwapchainCreateInfo->presentMode) { + case VK_PRESENT_MODE_IMMEDIATE_KHR: + tpl_present_mode = TPL_DISPLAY_PRESENT_MODE_IMMEDIATE; + break; + case VK_PRESENT_MODE_MAILBOX_KHR: + tpl_present_mode = TPL_DISPLAY_PRESENT_MODE_MAILBOX; + break; + case VK_PRESENT_MODE_FIFO_KHR: + tpl_present_mode = TPL_DISPLAY_PRESENT_MODE_FIFO; + break; + case VK_PRESENT_MODE_FIFO_RELAXED_KHR: + tpl_present_mode = TPL_DISPLAY_PRESENT_MODE_FIFO_RELAXED; + break; + default: + WSI_PRINT_ERROR("unsupported present mode, presentMode[%d].", pSwapchainCreateInfo->presentMode); + return VK_ERROR_INITIALIZATION_FAILED; } - do - { - res = dispatch_queue(m_display, m_surface_queue, 1000); - } while (res > 0 && !cb_recvd); - if (res < 0) - { - WSI_PRINT_ERROR("error dispatching on the surface queue\n"); - goto exit; - } - else if (res == 0) - { - WSI_PRINT_ERROR("timeout waiting for roundtrip callback\n"); - goto exit; + res = tpl_surface_create_swapchain(m_tpl_surface, format, + pSwapchainCreateInfo->imageExtent.width, pSwapchainCreateInfo->imageExtent.height, + pSwapchainCreateInfo->minImageCount, tpl_present_mode); + if (res != TPL_ERROR_NONE) { + WSI_PRINT_ERROR("create swapchain failed, ret[%d].\n", res); + return VK_ERROR_INITIALIZATION_FAILED; } -exit: - if (cb) - { - wl_callback_destroy(cb); - } - return res; + return VK_SUCCESS; } -struct display_queue -{ - wl_display *display; - wl_event_queue *queue; -}; - -VkResult swapchain::init_platform(VkDevice device, const VkSwapchainCreateInfoKHR *pSwapchainCreateInfo) +VkResult swapchain::allocate_image(const VkImageCreateInfo &image_create_info, tizen_image_data *image_data, + VkImage *image) { - VkIcdSurfaceWayland *vk_surf = reinterpret_cast(pSwapchainCreateInfo->surface); - - m_display = vk_surf->display; - m_surface = vk_surf->surface; -#if 0 - m_surface_queue = wl_display_create_queue(m_display); - if (m_surface_queue == nullptr) - { - WSI_PRINT_ERROR("Failed to create wl surface display_queue.\n"); - return VK_ERROR_INITIALIZATION_FAILED; - } - - m_buffer_queue = wl_display_create_queue(m_display); - if (m_buffer_queue == nullptr) - { - WSI_PRINT_ERROR("Failed to create wl buffer display_queue.\n"); - return VK_ERROR_INITIALIZATION_FAILED; - } + VkResult result = VK_SUCCESS; - wl_registry *registry = wl_display_get_registry(m_display); - if (registry == nullptr) + assert(image_data->stride >= 0); + VkSubresourceLayout image_layout = {}; + image_layout.offset = image_data->offset; + image_layout.rowPitch = static_cast(image_data->stride); + VkImageDrmFormatModifierExplicitCreateInfoEXT drm_mod_info = {}; + drm_mod_info.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT; + drm_mod_info.pNext = image_create_info.pNext; + drm_mod_info.drmFormatModifier = DRM_FORMAT_MOD_LINEAR; + drm_mod_info.drmFormatModifierPlaneCount = 1; + drm_mod_info.pPlaneLayouts = &image_layout; + + VkExternalMemoryImageCreateInfoKHR external_info = {}; + external_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR; + external_info.pNext = &drm_mod_info; + external_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; + + VkImageCreateInfo image_info = image_create_info; + image_info.pNext = &external_info; + image_info.tiling = VK_IMAGE_TILING_LINEAR; + result = m_device_data.disp.CreateImage(m_device, &image_info, get_allocation_callbacks(), image); + if (result != VK_SUCCESS) { - WSI_PRINT_ERROR("Failed to get wl display registry.\n"); - return VK_ERROR_INITIALIZATION_FAILED; + WSI_PRINT_ERROR("Image creation failed.\n"); + return result; } - wl_proxy_set_queue((struct wl_proxy *)registry, m_surface_queue); + VkMemoryFdPropertiesKHR mem_props = {}; + mem_props.sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR; - const wl_registry_listener registry_listener = { registry_handler }; - int res = wl_registry_add_listener(registry, ®istry_listener, &m_dmabuf_interface); - if (res < 0) + result = m_device_data.disp.GetMemoryFdPropertiesKHR(m_device, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + image_data->buffer_fd, &mem_props); + if (result != VK_SUCCESS) { - WSI_PRINT_ERROR("Failed to add registry listener.\n"); - return VK_ERROR_INITIALIZATION_FAILED; + WSI_PRINT_ERROR("Error querying Fd properties.\n"); + return result; } - res = roundtrip(); - if (res < 0) + uint32_t mem_idx; + for (mem_idx = 0; mem_idx < VK_MAX_MEMORY_TYPES; mem_idx++) { - WSI_PRINT_ERROR("Roundtrip failed.\n"); - return VK_ERROR_INITIALIZATION_FAILED; + if (mem_props.memoryTypeBits & (1 << mem_idx)) + { + break; + } } - - /* we should have the dma_buf interface by now */ - assert(m_dmabuf_interface); - - wl_registry_destroy(registry); - - res = wsialloc_new(-1, &m_wsi_allocator); - if (res != 0) + off_t dma_buf_size = lseek(image_data->buffer_fd, 0, SEEK_END); + if (dma_buf_size < 0) { - WSI_PRINT_ERROR("Failed to create wsi allocator.\n"); - return VK_ERROR_INITIALIZATION_FAILED; + WSI_PRINT_ERROR("Failed to get DMA Buf size.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; } -#endif - return VK_SUCCESS; -} -static void create_succeeded(void *data, struct zwp_linux_buffer_params_v1 *params, struct wl_buffer *buffer) -{ - struct wl_buffer **wayland_buffer = (struct wl_buffer **)data; - *wayland_buffer = buffer; -} + VkImportMemoryFdInfoKHR import_mem_info = {}; + import_mem_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; + import_mem_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; + import_mem_info.fd = image_data->buffer_fd; -static const struct zwp_linux_buffer_params_v1_listener params_listener = { create_succeeded, NULL }; + VkMemoryAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.pNext = &import_mem_info; + alloc_info.allocationSize = static_cast(dma_buf_size); + alloc_info.memoryTypeIndex = mem_idx; -static void buffer_release(void *data, struct wl_buffer *wayl_buffer) -{ - swapchain *sc = (swapchain *)data; - sc->release_buffer(wayl_buffer); -} + result = m_device_data.disp.AllocateMemory(m_device, &alloc_info, get_allocation_callbacks(), &image_data->memory); -void swapchain::release_buffer(struct wl_buffer *wayl_buffer) -{ - uint32_t i; - for (i = 0; i < m_swapchain_images.size(); i++) + if (result != VK_SUCCESS) { - wayland_image_data *data; - data = (wayland_image_data *)m_swapchain_images[i].data; - if (data->buffer == wayl_buffer) - { - unpresent_image(i); - break; - } + WSI_PRINT_ERROR("Failed to import memory.\n"); + return result; } + result = m_device_data.disp.BindImageMemory(m_device, *image, image_data->memory, 0); - /* check we found a buffer to unpresent */ - assert(i < m_swapchain_images.size()); + return result; } -static struct wl_buffer_listener buffer_listener = { buffer_release }; - -VkResult swapchain::allocate_image(const VkImageCreateInfo &image_create_info, wayland_image_data *image_data, - VkImage *image) +VkResult swapchain::create_image(const VkImageCreateInfo &image_create_info) { VkResult result = VK_SUCCESS; - - image_data->buffer = nullptr; - image_data->buffer_fd = -1; - image_data->memory = VK_NULL_HANDLE; - - VkExternalImageFormatPropertiesKHR external_props = {}; - external_props.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR; - - VkImageFormatProperties2KHR format_props = {}; - format_props.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR; - format_props.pNext = &external_props; - { - VkPhysicalDeviceExternalImageFormatInfoKHR external_info = {}; - external_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR; - external_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; - - VkPhysicalDeviceImageDrmFormatModifierInfoEXT drm_mod_info = {}; - drm_mod_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT; - drm_mod_info.pNext = &external_info; - drm_mod_info.drmFormatModifier = DRM_FORMAT_MOD_LINEAR; - drm_mod_info.sharingMode = image_create_info.sharingMode; - drm_mod_info.queueFamilyIndexCount = image_create_info.queueFamilyIndexCount; - drm_mod_info.pQueueFamilyIndices = image_create_info.pQueueFamilyIndices; - - VkPhysicalDeviceImageFormatInfo2KHR info = {}; - info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR; - info.pNext = &drm_mod_info; - info.format = image_create_info.format; - info.type = image_create_info.imageType; - info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; - info.usage = image_create_info.usage; - info.flags = image_create_info.flags; - - result = m_device_data.instance_data.disp.GetPhysicalDeviceImageFormatProperties2KHR(m_device_data.physical_device, - &info, &format_props); - } - if (result != VK_SUCCESS) - { - WSI_PRINT_ERROR("Failed to get physical device format support.\n"); - return result; - } - if (format_props.imageFormatProperties.maxExtent.width < image_create_info.extent.width || - format_props.imageFormatProperties.maxExtent.height < image_create_info.extent.height || - format_props.imageFormatProperties.maxExtent.depth < image_create_info.extent.depth) - { - WSI_PRINT_ERROR("Physical device does not support required extent.\n"); + tpl_result_t res; + tbm_surface_h *buffers; + int tbm_buf_cnt, i = 0; + + res = tpl_surface_get_swapchain_buffers(m_tpl_surface, &buffers, &tbm_buf_cnt); + if (res == TPL_ERROR_OUT_OF_MEMORY) + return VK_ERROR_OUT_OF_HOST_MEMORY; + else if (res != TPL_ERROR_NONE) return VK_ERROR_INITIALIZATION_FAILED; - } - if (format_props.imageFormatProperties.maxMipLevels < image_create_info.mipLevels || - format_props.imageFormatProperties.maxArrayLayers < image_create_info.arrayLayers) - { - WSI_PRINT_ERROR("Physical device does not support required array layers or mip levels.\n"); - return VK_ERROR_INITIALIZATION_FAILED; - } - if ((format_props.imageFormatProperties.sampleCounts & image_create_info.samples) != image_create_info.samples) - { - WSI_PRINT_ERROR("Physical device does not support required sample count.\n"); - return VK_ERROR_INITIALIZATION_FAILED; - } - if (external_props.externalMemoryProperties.externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR) - { - /* TODO: Handle exportable images which use ICD allocated memory in preference to an external allocator. */ - } - if (!(external_props.externalMemoryProperties.externalMemoryFeatures & - VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR)) - { - WSI_PRINT_ERROR("Export/Import not supported.\n"); - return VK_ERROR_INITIALIZATION_FAILED; - } - else - { - /* TODO: Handle Dedicated allocation bit. */ - uint32_t fourcc = util::drm::vk_to_drm_format(image_create_info.format); -/* - int res = - wsialloc_alloc(&m_wsi_allocator, fourcc, image_create_info.extent.width, image_create_info.extent.height, - &image_data->stride, &image_data->buffer_fd, &image_data->offset, nullptr); - if (res != 0) - { - WSI_PRINT_ERROR("Failed allocation of DMA Buffer.\n"); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } -*/ - { - assert(image_data->stride >= 0); - VkSubresourceLayout image_layout = {}; - image_layout.offset = image_data->offset; - image_layout.rowPitch = static_cast(image_data->stride); - VkImageDrmFormatModifierExplicitCreateInfoEXT drm_mod_info = {}; - drm_mod_info.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT; - drm_mod_info.pNext = image_create_info.pNext; - drm_mod_info.drmFormatModifier = DRM_FORMAT_MOD_LINEAR; - drm_mod_info.drmFormatModifierPlaneCount = 1; - drm_mod_info.pPlaneLayouts = &image_layout; - - VkExternalMemoryImageCreateInfoKHR external_info = {}; - external_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR; - external_info.pNext = &drm_mod_info; - external_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; - - VkImageCreateInfo image_info = image_create_info; - image_info.pNext = &external_info; - image_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; - result = m_device_data.disp.CreateImage(m_device, &image_info, get_allocation_callbacks(), image); - } - if (result != VK_SUCCESS) + if (!m_swapchain_images.try_resize(tbm_buf_cnt)) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + i = 0; + for (auto &image: m_swapchain_images) { + tizen_image_data *image_data = nullptr; + if (get_allocation_callbacks() != nullptr) { - WSI_PRINT_ERROR("Image creation failed.\n"); - return result; + image_data = static_cast( + get_allocation_callbacks()->pfnAllocation(get_allocation_callbacks()->pUserData, sizeof(tizen_image_data), + alignof(tizen_image_data), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)); + } else { + image_data = static_cast(malloc(sizeof(tizen_image_data))); } - { - VkMemoryFdPropertiesKHR mem_props = {}; - mem_props.sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR; - - result = m_device_data.disp.GetMemoryFdPropertiesKHR(m_device, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, - image_data->buffer_fd, &mem_props); - if (result != VK_SUCCESS) - { - WSI_PRINT_ERROR("Error querying Fd properties.\n"); - return result; - } - uint32_t mem_idx; - for (mem_idx = 0; mem_idx < VK_MAX_MEMORY_TYPES; mem_idx++) - { - if (mem_props.memoryTypeBits & (1 << mem_idx)) - { - break; - } - } - off_t dma_buf_size = lseek(image_data->buffer_fd, 0, SEEK_END); - if (dma_buf_size < 0) - { - WSI_PRINT_ERROR("Failed to get DMA Buf size.\n"); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } + tbm_surface_info_s info; + tbm_bo bo = tbm_surface_internal_get_bo(buffers[i], 0); + tbm_bo_handle bo_handle = tbm_bo_get_handle(bo, TBM_DEVICE_3D); + tbm_surface_get_info(buffers[i], &info); - VkImportMemoryFdInfoKHR import_mem_info = {}; - import_mem_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; - import_mem_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; - import_mem_info.fd = image_data->buffer_fd; + image_data->tbm_buffer = buffers[i]; + image_data->buffer_fd = bo_handle.u32; + image_data->stride = info.planes[0].stride; + image_data->offset = info.planes[0].offset; + image_data->memory = VK_NULL_HANDLE; - VkMemoryAllocateInfo alloc_info = {}; - alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - alloc_info.pNext = &import_mem_info; - alloc_info.allocationSize = static_cast(dma_buf_size); - alloc_info.memoryTypeIndex = mem_idx; + image.data = static_cast(image_data); - result = m_device_data.disp.AllocateMemory(m_device, &alloc_info, get_allocation_callbacks(), &image_data->memory); - } + result = allocate_image(image_create_info, image_data, &image.image); if (result != VK_SUCCESS) { - WSI_PRINT_ERROR("Failed to import memory.\n"); - return result; + WSI_PRINT_ERROR("Failed to allocate image.\n"); + goto out; } - result = m_device_data.disp.BindImageMemory(m_device, *image, image_data->memory, 0); - } - - return result; -} -VkResult swapchain::create_image(const VkImageCreateInfo &image_create_info, swapchain_image &image) -{ - uint32_t fourcc = util::drm::vk_to_drm_format(image_create_info.format); + /* Initialize presentation fence. */ + VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, 0 }; + result = m_device_data.disp.CreateFence(m_device, &fenceInfo, get_allocation_callbacks(), &image.present_fence); - int res; - VkResult result = VK_SUCCESS; - - wayland_image_data *image_data = nullptr; - VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, 0 }; - - /* Create image_data */ - if (get_allocation_callbacks() != nullptr) - { - image_data = static_cast( - get_allocation_callbacks()->pfnAllocation(get_allocation_callbacks()->pUserData, sizeof(wayland_image_data), - alignof(wayland_image_data), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)); - } - else - { - image_data = static_cast(malloc(sizeof(wayland_image_data))); - } - if (image_data == nullptr) - { - result = VK_ERROR_OUT_OF_HOST_MEMORY; - goto out; + i++; } - image.data = reinterpret_cast(image_data); - image.status = swapchain_image::FREE; - result = allocate_image(image_create_info, image_data, &image.image); - if (result != VK_SUCCESS) - { - WSI_PRINT_ERROR("Failed to allocate image.\n"); - goto out; - } - - /* create a wl_buffer using the dma_buf protocol */ - struct zwp_linux_buffer_params_v1 *params; - params = zwp_linux_dmabuf_v1_create_params(m_dmabuf_interface); - zwp_linux_buffer_params_v1_add(params, image_data->buffer_fd, 0, image_data->offset, image_data->stride, 0, 0); - wl_proxy_set_queue((struct wl_proxy *)params, m_surface_queue); - res = zwp_linux_buffer_params_v1_add_listener(params, ¶ms_listener, &image_data->buffer); - if (res < 0) - { - result = VK_ERROR_INITIALIZATION_FAILED; - goto out; - } - zwp_linux_buffer_params_v1_create(params, image_create_info.extent.width, image_create_info.extent.height, fourcc, - 0); - - /* TODO: don't roundtrip - we should be able to send the create request now, - * and only wait for it on first present. only do this once, not for all buffers created */ - res = roundtrip(); - if (res < 0) - { - result = VK_ERROR_INITIALIZATION_FAILED; - goto out; - } + return VK_SUCCESS; - /* should now have a wl_buffer */ - assert(image_data->buffer); - zwp_linux_buffer_params_v1_destroy(params); - wl_proxy_set_queue((struct wl_proxy *)image_data->buffer, m_buffer_queue); - res = wl_buffer_add_listener(image_data->buffer, &buffer_listener, this); - if (res < 0) - { - result = VK_ERROR_INITIALIZATION_FAILED; - goto out; - } +out: - /* Initialize presentation fence. */ - result = m_device_data.disp.CreateFence(m_device, &fenceInfo, get_allocation_callbacks(), &image.present_fence); + destroy_image(); -out: - if (result != VK_SUCCESS) - { - destroy_image(image); - return result; - } return result; } -static void frame_done(void *data, wl_callback *cb, uint32_t cb_data) +VkResult swapchain::acquire_image(uint32_t *image_index) { - (void)cb_data; + tbm_surface_h tbm_buf = tpl_surface_dequeue_buffer_with_sync(m_tpl_surface, UINT64_MAX, NULL); - bool *present_pending = reinterpret_cast(data); - assert(present_pending); + if (tbm_buf == NULL) + return VK_ERROR_SURFACE_LOST_KHR; - *present_pending = false; + for (unsigned int i = 0; i < m_swapchain_images.size(); i++) { + tizen_image_data *image_data = reinterpret_cast(m_swapchain_images[i].data); + if (image_data->tbm_buffer == tbm_buf) { + *image_index = i; + return VK_SUCCESS; + } + } - wl_callback_destroy(cb); + return VK_ERROR_SURFACE_LOST_KHR; } void swapchain::present_image(uint32_t pendingIndex) { - int res; - wayland_image_data *image_data = reinterpret_cast(m_swapchain_images[pendingIndex].data); - /* if a frame is already pending, wait for a hint to present again */ - if (m_present_pending) - { - assert(m_present_mode == VK_PRESENT_MODE_FIFO_KHR); - do - { - /* block waiting for the compositor to return the wl_surface::frame - * callback. We may want to change this to timeout after a period of - * time if the compositor isn't responding (perhaps because the - * window is hidden). - */ - res = dispatch_queue(m_display, m_surface_queue, -1); - } while (res > 0 && m_present_pending); - - if (res <= 0) - { - WSI_PRINT_ERROR("error waiting for Wayland compositor frame hint\n"); - m_is_valid = false; - /* try to present anyway */ - } - } - - wl_surface_attach(m_surface, image_data->buffer, 0, 0); - /* TODO: work out damage */ - wl_surface_damage(m_surface, 0, 0, INT32_MAX, INT32_MAX); - - if (m_present_mode == VK_PRESENT_MODE_FIFO_KHR) - { - /* request a hint when we can present the _next_ frame */ - wl_callback *cb = wl_surface_frame(m_surface); - if (cb) - { - wl_proxy_set_queue((wl_proxy *)cb, m_surface_queue); - static const wl_callback_listener frame_listener = { frame_done }; - m_present_pending = true; - wl_callback_add_listener(cb, &frame_listener, &m_present_pending); - } - } - else - { - assert(m_present_mode == VK_PRESENT_MODE_MAILBOX_KHR); - /* weston only _queues_ wl_buffer::release events. This means when the - * compositor flushes the client it only sends the events if some other events - * have been posted. - * - * As such we have to request a sync callback - we discard it straight away - * as we don't actually need the callback, but it means the - * wl_buffer::release event is actually sent. - */ - wl_callback *cb = wl_display_sync(m_display); - assert(cb); - if (cb) - { - wl_callback_destroy(cb); - } - } - - wl_surface_commit(m_surface); - res = wl_display_flush(m_display); - if (res < 0) - { - WSI_PRINT_ERROR("error flushing the display\n"); - /* Setting the swapchain as invalid */ - m_is_valid = false; - } + tizen_image_data *image_data = reinterpret_cast(m_swapchain_images[pendingIndex].data); + tpl_surface_enqueue_buffer_with_damage_and_sync(m_tpl_surface, image_data->tbm_buffer, 0, NULL, -1); } -void swapchain::destroy_image(swapchain_image &image) +void swapchain::destroy_image(void) { - if (image.status != swapchain_image::INVALID) - { + for (auto &image: m_swapchain_images) { if (image.present_fence != VK_NULL_HANDLE) { m_device_data.disp.DestroyFence(m_device, image.present_fence, get_allocation_callbacks()); image.present_fence = VK_NULL_HANDLE; } - if (image.image != VK_NULL_HANDLE) { m_device_data.disp.DestroyImage(m_device, image.image, get_allocation_callbacks()); image.image = VK_NULL_HANDLE; } - } - if (image.data != nullptr) - { - auto image_data = reinterpret_cast(image.data); - if (image_data->buffer != nullptr) - { - wl_buffer_destroy(image_data->buffer); - } - if (image_data->memory != VK_NULL_HANDLE) - { - m_device_data.disp.FreeMemory(m_device, image_data->memory, get_allocation_callbacks()); - } - else if (image_data->buffer_fd >= 0) - { - close(image_data->buffer_fd); - } - - if (get_allocation_callbacks() != nullptr) + if (image.data != nullptr) { - get_allocation_callbacks()->pfnFree(get_allocation_callbacks()->pUserData, image_data); - } - else - { - free(image_data); - } - image.data = nullptr; - } - - image.status = swapchain_image::INVALID; -} - -bool swapchain::free_image_found() -{ - for (auto &img : m_swapchain_images) - { - if (img.status == swapchain_image::FREE) - { - return true; - } - } - return false; -} - -VkResult swapchain::get_free_buffer(uint64_t *timeout) -{ - int ms_timeout, res; - - if (*timeout >= INT_MAX * 1000llu * 1000llu) - { - ms_timeout = INT_MAX; - } - else - { - ms_timeout = *timeout / 1000llu / 1000llu; - } - - /* The current dispatch_queue implementation will return if any - * events are returned, even if no events are dispatched to the buffer - * queue. Therefore dispatch repeatedly until a buffer has been freed. - */ - do - { - res = dispatch_queue(m_display, m_buffer_queue, ms_timeout); - } while (!free_image_found() && res > 0); - - if (res > 0) - { - *timeout = 0; - return VK_SUCCESS; - } - else if (res == 0) - { - if (*timeout == 0) - { - return VK_NOT_READY; - } - else - { - return VK_TIMEOUT; + tizen_image_data *image_data = reinterpret_cast(image.data); + if (image_data->memory != VK_NULL_HANDLE) + { + m_device_data.disp.FreeMemory(m_device, image_data->memory, get_allocation_callbacks()); + } + else if (image_data->buffer_fd >= 0) + { + close(image_data->buffer_fd); + } + if (get_allocation_callbacks() != nullptr) + { + get_allocation_callbacks()->pfnFree(get_allocation_callbacks()->pUserData, image_data); + } + else + { + free(image_data); + } + image.data = nullptr; } } - else - { - return VK_ERROR_DEVICE_LOST; - } } } // namespace wayland diff --git a/wsi/tizen/swapchain.hpp b/wsi/tizen/swapchain.hpp index 7151b87..3a6e41a 100644 --- a/wsi/tizen/swapchain.hpp +++ b/wsi/tizen/swapchain.hpp @@ -24,13 +24,14 @@ #pragma once -#include "wsi/swapchain_base.hpp" +#include "wsi/swapchain_base_tizen.hpp" extern "C" { #include -//#include -#include -#include +#include +#include +#include +#include } namespace wsi @@ -45,9 +46,6 @@ public: ~swapchain(); - /* TODO: make the buffer destructor a friend? so this can be protected */ - void release_buffer(struct wl_buffer *wl_buffer); - protected: /** * @brief Initialize platform specifics. @@ -55,17 +53,17 @@ protected: VkResult init_platform(VkDevice device, const VkSwapchainCreateInfoKHR *pSwapchainCreateInfo) override; /** - * @brief Creates a new swapchain image. + * @brief Creates swapchain images. * * @param image_create_info Data to be used to create the image. * - * @param image Handle to the image. - * * @return If image creation is successful returns VK_SUCCESS, otherwise * will return VK_ERROR_OUT_OF_DEVICE_MEMORY or VK_ERROR_INITIALIZATION_FAILED * depending on the error that occurred. */ - VkResult create_image(const VkImageCreateInfo &image_create_info, swapchain_image &image) override; + VkResult create_image(const VkImageCreateInfo &image_create_info) override; + + VkResult acquire_image(uint32_t *image_index) override; /** * @brief Method to present an image @@ -79,58 +77,15 @@ protected: * * @param image Handle to the image about to be released. */ - void destroy_image(swapchain_image &image) override; - - /** - * @brief Method to perform a rountrip to the Wayland compositor - * - * @return -1 on error. Otherwise non-negative. - */ - int roundtrip(); - - /** - * @brief Method to check if there are any free images - * - * @return true if any images are free, otherwise false. - */ - bool free_image_found(); - - /** - * @brief Hook for any actions to free up a buffer for acquire - * - * @param[in,out] timeout time to wait, in nanoseconds. 0 doesn't block, - * UINT64_MAX waits indefinitely. The timeout should - * be updated if a sleep is required - this can - * be set to 0 if the semaphore is now not expected - * block. - */ - VkResult get_free_buffer(uint64_t *timeout) override; + void destroy_image(void) override; private: - struct wayland_image_data; - VkResult allocate_image(const VkImageCreateInfo &image_create_info, wayland_image_data *image_data, VkImage *image); - - struct wl_display *m_display; - struct wl_surface *m_surface; - struct zwp_linux_dmabuf_v1 *m_dmabuf_interface; + struct tizen_image_data; + VkResult allocate_image(const VkImageCreateInfo &image_create_info, tizen_image_data *image_data, VkImage *image); - /* The queue on which we dispatch the swapchain related events, mostly frame completion */ - struct wl_event_queue *m_surface_queue; - /* The queue on which we dispatch buffer related events, mostly buffer_release */ - struct wl_event_queue *m_buffer_queue; + tpl_display_t *m_tpl_display; + tpl_surface_t *m_tpl_surface; - /** - * @brief Handle to the WSI allocator. - */ - //wsialloc_allocator m_wsi_allocator; - - /** - * @brief true when waiting for the server hint to present a buffer - * - * true if a buffer has been presented and we've not had a wl_surface::frame - * callback to indicate the server is ready for the next buffer. - */ - bool m_present_pending; }; } // namespace wayland } // namespace wsi diff --git a/wsi/tizen/swapchain_wl_helpers.cpp b/wsi/tizen/swapchain_wl_helpers.cpp deleted file mode 100644 index 197ca04..0000000 --- a/wsi/tizen/swapchain_wl_helpers.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2017-2019, 2021 Arm Limited. - * - * SPDX-License-Identifier: MIT - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "swapchain_wl_helpers.hpp" - -#include -#include -#include -#include -#include -#include - -extern "C" { - - void registry_handler(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface, - uint32_t version) - { - zwp_linux_dmabuf_v1 **dmabuf_interface = (zwp_linux_dmabuf_v1 **)data; - - if (!strcmp(interface, "zwp_linux_dmabuf_v1")) - { - *dmabuf_interface = - (zwp_linux_dmabuf_v1 *)wl_registry_bind(wl_registry, name, &zwp_linux_dmabuf_v1_interface, version); - assert(*dmabuf_interface); - } - } - - int dispatch_queue(struct wl_display *display, struct wl_event_queue *queue, int timeout) - { - int err; - struct pollfd pfd = {}; - int retval; - - /* Before we sleep, dispatch any pending events. prepare_read_queue will return 0 whilst there are pending - * events to dispatch on the queue. */ - while (0 != wl_display_prepare_read_queue(display, queue)) - { - /* dispatch_queue_pending returns -1 on error, or the number of events dispatched otherwise. If we - * already dispatched some events, then we might not need to sleep, as we might have just dispatched - * the event we want, so return immediately. */ - err = wl_display_dispatch_queue_pending(display, queue); - if (err) - { - return (0 > err) ? -1 : 1; - } - } - - /* wl_display_read_events performs a non-blocking read. */ - pfd.fd = wl_display_get_fd(display); - pfd.events = POLLIN; - while (true) - { - /* Timeout is given in milliseconds. A return value of 0, or -1 with errno set to EINTR means that we - * should retry as the timeout was exceeded or we were interrupted by a signal, respectively. A - * return value of 1 means that something happened, and we should inspect the pollfd structure to see - * just what that was. - */ - err = poll(&pfd, 1, timeout); - if (0 == err) - { - /* Timeout. */ - wl_display_cancel_read(display); - return 0; - } - else if (-1 == err) - { - if (EINTR == errno) - { - /* Interrupted by a signal; restart. This resets the timeout. */ - continue; - } - else - { - /* Something else bad happened; abort. */ - wl_display_cancel_read(display); - return -1; - } - } - else - { - if (POLLIN == pfd.revents) - { - /* We have data to read, and no errors; proceed to read_events. */ - break; - } - else - { - /* An error occurred, e.g. file descriptor was closed from underneath us. */ - wl_display_cancel_read(display); - return -1; - } - } - } - - /* Actually read the events from the display. A failure in read_events calls cancel_read internally for us, - * so we don't need to do that here. */ - err = wl_display_read_events(display); - if (0 != err) - { - return -1; - } - - /* Finally, if we read any events relevant to our queue, we can dispatch them. */ - err = wl_display_dispatch_queue_pending(display, queue); - retval = err < 0 ? -1 : 1; - - return retval; - } -} diff --git a/wsi/tizen/swapchain_wl_helpers.hpp b/wsi/tizen/swapchain_wl_helpers.hpp deleted file mode 100644 index 5318682..0000000 --- a/wsi/tizen/swapchain_wl_helpers.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2017-2019, 2021 Arm Limited. - * - * SPDX-License-Identifier: MIT - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#pragma once - -#include - -extern "C" { - void registry_handler(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface, - uint32_t version); - - /** - * @brief Dispatch events from a Wayland event queue - * - * Dispatch events from a given Wayland display event queue, including calling event handlers, and flush out any - * requests the event handlers may have written. Specification of a timeout allows the wait to be bounded. If any - * events are already pending dispatch (have been read from the display by another thread or event queue), they - * will be dispatched and the function will return immediately, without waiting for new events to arrive. - * - * @param display Wayland display to dispatch events from - * @param queue Event queue to dispatch events from; other event queues will not have their handlers called from - * within this function - * @param timeout Maximum time to wait for events to arrive, in milliseconds - * @return 1 if one or more events were dispatched on this queue, 0 if the timeout was reached without any - * events being dispatched, or -1 on error. - */ - int dispatch_queue(struct wl_display *display, struct wl_event_queue *queue, int timeout); -} diff --git a/wsi/wsi_factory.cpp b/wsi/wsi_factory.cpp index 5da2394..51e5e86 100644 --- a/wsi/wsi_factory.cpp +++ b/wsi/wsi_factory.cpp @@ -28,8 +28,6 @@ */ #include "wsi_factory.hpp" -#include "headless/surface_properties.hpp" -#include "headless/swapchain.hpp" #include #include @@ -38,14 +36,18 @@ #include +#if BUILD_WSI_TIZEN +#include +#include "tizen/surface_properties.hpp" +#include "tizen/swapchain.hpp" +#else +#include "headless/surface_properties.hpp" +#include "headless/swapchain.hpp" #if BUILD_WSI_WAYLAND #include #include "wayland/surface_properties.hpp" #include "wayland/swapchain.hpp" -#elif BUILD_WSI_TIZEN -#include -#include "tizen/surface_properties.hpp" -#include "tizen/swapchain.hpp" +#endif #endif namespace wsi @@ -56,24 +58,30 @@ static struct wsi_extension VkExtensionProperties extension; VkIcdWsiPlatform platform; } const supported_wsi_extensions[] = { +#if BUILD_WSI_TIZEN + { { VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_SPEC_VERSION }, VK_ICD_WSI_PLATFORM_WAYLAND }, +#else { { VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME, VK_EXT_HEADLESS_SURFACE_SPEC_VERSION }, VK_ICD_WSI_PLATFORM_HEADLESS }, -#if BUILD_WSI_WAYLAND || BUILD_WSI_TIZEN +#if BUILD_WSI_WAYLAND { { VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_SPEC_VERSION }, VK_ICD_WSI_PLATFORM_WAYLAND }, #endif +#endif }; static surface_properties *get_surface_properties(VkIcdWsiPlatform platform) { switch (platform) { +#if BUILD_WSI_TIZEN + case VK_ICD_WSI_PLATFORM_WAYLAND: + return &tizen::surface_properties::get_instance(); +#else case VK_ICD_WSI_PLATFORM_HEADLESS: return &headless::surface_properties::get_instance(); #if BUILD_WSI_WAYLAND case VK_ICD_WSI_PLATFORM_WAYLAND: return &wayland::surface_properties::get_instance(); -#elif BUILD_WSI_TIZEN - case VK_ICD_WSI_PLATFORM_WAYLAND: - return &tizen::surface_properties::get_instance(); +#endif #endif default: return nullptr; @@ -106,14 +114,16 @@ swapchain_base *allocate_surface_swapchain(VkSurfaceKHR surface, layer::device_p switch (surface_base->platform) { +#if BUILD_WSI_TIZEN + case VK_ICD_WSI_PLATFORM_WAYLAND: + return allocate_swapchain(dev_data, pAllocator); +#else case VK_ICD_WSI_PLATFORM_HEADLESS: return allocate_swapchain(dev_data, pAllocator); #if BUILD_WSI_WAYLAND case VK_ICD_WSI_PLATFORM_WAYLAND: return allocate_swapchain(dev_data, pAllocator); -#elif BUILD_WSI_TIZEN - case VK_ICD_WSI_PLATFORM_WAYLAND: - return allocate_swapchain(dev_data, pAllocator); +#endif #endif default: return nullptr; diff --git a/wsi/wsi_factory.hpp b/wsi/wsi_factory.hpp index 1c8174f..73b751e 100644 --- a/wsi/wsi_factory.hpp +++ b/wsi/wsi_factory.hpp @@ -29,7 +29,11 @@ #pragma once +#if BUILD_WSI_TIZEN +#include "swapchain_base_tizen.hpp" +#else #include "swapchain_base.hpp" +#endif #include "surface_properties.hpp" #include "util/platform_set.hpp" -- 2.7.4