X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fvulkan%2Fwsi%2Fwsi_common.c;h=d9906091ed9528d944cc18f9aee1a4ad68f6941b;hb=69269a46f10f4ad67452a198fe6381953444d741;hp=783b954a5c5bbddcf5804a356f214c23eafd79f7;hpb=f1374805a86d0d506557e61efbc09e23caa7a038;p=mesa.git diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c index 783b954a5c5..d9906091ed9 100644 --- a/src/vulkan/wsi/wsi_common.c +++ b/src/vulkan/wsi/wsi_common.c @@ -24,19 +24,26 @@ #include "wsi_common_private.h" #include "drm-uapi/drm_fourcc.h" #include "util/macros.h" +#include "util/os_file.h" +#include "util/xmlconfig.h" #include "vk_util.h" +#include #include #include +#include +#include VkResult wsi_device_init(struct wsi_device *wsi, VkPhysicalDevice pdevice, WSI_FN_GetPhysicalDeviceProcAddr proc_addr, const VkAllocationCallbacks *alloc, - int display_fd) + int display_fd, + const struct driOptionCache *dri_options) { - VkResult result; + const char *present_mode; + UNUSED VkResult result; memset(wsi, 0, sizeof(*wsi)); @@ -59,6 +66,7 @@ wsi_device_init(struct wsi_device *wsi, GetPhysicalDeviceProperties2(pdevice, &pdp2); wsi->maxImageDimension2D = pdp2.properties.limits.maxImageDimension2D; + wsi->override_present_mode = VK_PRESENT_MODE_MAX_ENUM_KHR; GetPhysicalDeviceMemoryProperties(pdevice, &wsi->memory_props); GetPhysicalDeviceQueueFamilyProperties(pdevice, &wsi->queue_family_count, NULL); @@ -83,18 +91,20 @@ wsi_device_init(struct wsi_device *wsi, WSI_GET_CB(FreeMemory); WSI_GET_CB(FreeCommandBuffers); WSI_GET_CB(GetBufferMemoryRequirements); + WSI_GET_CB(GetImageDrmFormatModifierPropertiesEXT); WSI_GET_CB(GetImageMemoryRequirements); WSI_GET_CB(GetImageSubresourceLayout); WSI_GET_CB(GetMemoryFdKHR); WSI_GET_CB(GetPhysicalDeviceFormatProperties); WSI_GET_CB(GetPhysicalDeviceFormatProperties2KHR); + WSI_GET_CB(GetPhysicalDeviceImageFormatProperties2); WSI_GET_CB(ResetFences); WSI_GET_CB(QueueSubmit); WSI_GET_CB(WaitForFences); #undef WSI_GET_CB #ifdef VK_USE_PLATFORM_XCB_KHR - result = wsi_x11_init_wsi(wsi, alloc); + result = wsi_x11_init_wsi(wsi, alloc, dri_options); if (result != VK_SUCCESS) goto fail; #endif @@ -111,11 +121,38 @@ wsi_device_init(struct wsi_device *wsi, goto fail; #endif - return VK_SUCCESS; + present_mode = getenv("MESA_VK_WSI_PRESENT_MODE"); + if (present_mode) { + if (!strcmp(present_mode, "fifo")) { + wsi->override_present_mode = VK_PRESENT_MODE_FIFO_KHR; + } else if (!strcmp(present_mode, "mailbox")) { + wsi->override_present_mode = VK_PRESENT_MODE_MAILBOX_KHR; + } else if (!strcmp(present_mode, "immediate")) { + wsi->override_present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR; + } else { + fprintf(stderr, "Invalid MESA_VK_WSI_PRESENT_MODE value!\n"); + } + } + + if (dri_options) { + if (driCheckOption(dri_options, "adaptive_sync", DRI_BOOL)) + wsi->enable_adaptive_sync = driQueryOptionb(dri_options, + "adaptive_sync"); + + if (driCheckOption(dri_options, "vk_wsi_force_bgra8_unorm_first", DRI_BOOL)) { + wsi->force_bgra8_unorm_first = + driQueryOptionb(dri_options, "vk_wsi_force_bgra8_unorm_first"); + } + } + return VK_SUCCESS; +#if defined(VK_USE_PLATFORM_XCB_KHR) || \ + defined(VK_USE_PLATFORM_WAYLAND_KHR) || \ + defined(VK_USE_PLATFORM_DISPLAY_KHR) fail: wsi_device_finish(wsi, alloc); return result; +#endif } void @@ -170,6 +207,8 @@ wsi_swapchain_init(const struct wsi_device *wsi, memset(chain, 0, sizeof(*chain)); + vk_object_base_init(NULL, &chain->base, VK_OBJECT_TYPE_SWAPCHAIN_KHR); + chain->wsi = wsi; chain->device = device; chain->alloc = *pAllocator; @@ -201,17 +240,76 @@ fail: return result; } +static bool +wsi_swapchain_is_present_mode_supported(struct wsi_device *wsi, + const VkSwapchainCreateInfoKHR *pCreateInfo, + VkPresentModeKHR mode) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pCreateInfo->surface); + struct wsi_interface *iface = wsi->wsi[surface->platform]; + VkPresentModeKHR *present_modes; + uint32_t present_mode_count; + bool supported = false; + VkResult result; + + result = iface->get_present_modes(surface, &present_mode_count, NULL); + if (result != VK_SUCCESS) + return supported; + + present_modes = malloc(present_mode_count * sizeof(*present_modes)); + if (!present_modes) + return supported; + + result = iface->get_present_modes(surface, &present_mode_count, + present_modes); + if (result != VK_SUCCESS) + goto fail; + + for (uint32_t i = 0; i < present_mode_count; i++) { + if (present_modes[i] == mode) { + supported = true; + break; + } + } + +fail: + free(present_modes); + return supported; +} + +enum VkPresentModeKHR +wsi_swapchain_get_present_mode(struct wsi_device *wsi, + const VkSwapchainCreateInfoKHR *pCreateInfo) +{ + if (wsi->override_present_mode == VK_PRESENT_MODE_MAX_ENUM_KHR) + return pCreateInfo->presentMode; + + if (!wsi_swapchain_is_present_mode_supported(wsi, pCreateInfo, + wsi->override_present_mode)) { + fprintf(stderr, "Unsupported MESA_VK_WSI_PRESENT_MODE value!\n"); + return pCreateInfo->presentMode; + } + + return wsi->override_present_mode; +} + void wsi_swapchain_finish(struct wsi_swapchain *chain) { - for (unsigned i = 0; i < ARRAY_SIZE(chain->fences); i++) - chain->wsi->DestroyFence(chain->device, chain->fences[i], &chain->alloc); + if (chain->fences) { + for (unsigned i = 0; i < chain->image_count; i++) + chain->wsi->DestroyFence(chain->device, chain->fences[i], &chain->alloc); + + vk_free(&chain->alloc, chain->fences); + } for (uint32_t i = 0; i < chain->wsi->queue_family_count; i++) { chain->wsi->DestroyCommandPool(chain->device, chain->cmd_pools[i], &chain->alloc); } vk_free(&chain->alloc, chain->cmd_pools); + + vk_object_base_finish(&chain->base); } static uint32_t @@ -262,23 +360,68 @@ wsi_create_native_image(const struct wsi_swapchain *chain, for (int i = 0; i < ARRAY_SIZE(image->fds); i++) image->fds[i] = -1; - struct wsi_image_create_info image_wsi_info = { - .sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA, - .pNext = NULL, + VkImageCreateInfo image_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .flags = 0, + .imageType = VK_IMAGE_TYPE_2D, + .format = pCreateInfo->imageFormat, + .extent = { + .width = pCreateInfo->imageExtent.width, + .height = pCreateInfo->imageExtent.height, + .depth = 1, + }, + .mipLevels = 1, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = pCreateInfo->imageUsage, + .sharingMode = pCreateInfo->imageSharingMode, + .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount, + .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, }; + VkImageFormatListCreateInfoKHR image_format_list; + if (pCreateInfo->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) { + image_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | + VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR; + + const VkImageFormatListCreateInfoKHR *format_list = + vk_find_struct_const(pCreateInfo->pNext, + IMAGE_FORMAT_LIST_CREATE_INFO_KHR); + +#ifndef NDEBUG + assume(format_list && format_list->viewFormatCount > 0); + bool format_found = false; + for (int i = 0; i < format_list->viewFormatCount; i++) + if (pCreateInfo->imageFormat == format_list->pViewFormats[i]) + format_found = true; + assert(format_found); +#endif + + image_format_list = *format_list; + image_format_list.pNext = NULL; + __vk_append_struct(&image_info, &image_format_list); + } + + struct wsi_image_create_info image_wsi_info; + VkImageDrmFormatModifierListCreateInfoEXT image_modifier_list; + uint32_t image_modifier_count = 0, modifier_prop_count = 0; - struct wsi_format_modifier_properties *modifier_props = NULL; + struct VkDrmFormatModifierPropertiesEXT *modifier_props = NULL; uint64_t *image_modifiers = NULL; if (num_modifier_lists == 0) { /* If we don't have modifiers, fall back to the legacy "scanout" flag */ - image_wsi_info.scanout = true; + image_wsi_info = (struct wsi_image_create_info) { + .sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA, + .scanout = true, + }; + __vk_append_struct(&image_info, &image_wsi_info); } else { /* The winsys can't request modifiers if we don't support them. */ assert(wsi->supports_modifiers); - struct wsi_format_modifier_properties_list modifier_props_list = { - .sType = VK_STRUCTURE_TYPE_WSI_FORMAT_MODIFIER_PROPERTIES_LIST_MESA, - .pNext = NULL, + struct VkDrmFormatModifierPropertiesListEXT modifier_props_list = { + .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT, }; VkFormatProperties2 format_props = { .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, @@ -287,10 +430,10 @@ wsi_create_native_image(const struct wsi_swapchain *chain, wsi->GetPhysicalDeviceFormatProperties2KHR(wsi->pdevice, pCreateInfo->imageFormat, &format_props); - assert(modifier_props_list.modifier_count > 0); + assert(modifier_props_list.drmFormatModifierCount > 0); modifier_props = vk_alloc(&chain->alloc, sizeof(*modifier_props) * - modifier_props_list.modifier_count, + modifier_props_list.drmFormatModifierCount, 8, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (!modifier_props) { @@ -298,11 +441,50 @@ wsi_create_native_image(const struct wsi_swapchain *chain, goto fail; } - modifier_props_list.modifier_properties = modifier_props; + modifier_props_list.pDrmFormatModifierProperties = modifier_props; wsi->GetPhysicalDeviceFormatProperties2KHR(wsi->pdevice, pCreateInfo->imageFormat, &format_props); - modifier_prop_count = modifier_props_list.modifier_count; + + /* Call GetImageFormatProperties with every modifier and filter the list + * down to those that we know work. + */ + modifier_prop_count = 0; + for (uint32_t i = 0; i < modifier_props_list.drmFormatModifierCount; i++) { + VkPhysicalDeviceImageDrmFormatModifierInfoEXT mod_info = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT, + .drmFormatModifier = modifier_props[i].drmFormatModifier, + .sharingMode = pCreateInfo->imageSharingMode, + .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount, + .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices, + }; + VkPhysicalDeviceImageFormatInfo2 format_info = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, + .format = pCreateInfo->imageFormat, + .type = VK_IMAGE_TYPE_2D, + .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, + .usage = pCreateInfo->imageUsage, + .flags = image_info.flags, + }; + + VkImageFormatListCreateInfoKHR format_list; + if (image_info.flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) { + format_list = image_format_list; + format_list.pNext = NULL; + __vk_append_struct(&format_info, &format_list); + } + + VkImageFormatProperties2 format_props = { + .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, + .pNext = NULL, + }; + __vk_append_struct(&format_info, &mod_info); + result = wsi->GetPhysicalDeviceImageFormatProperties2(wsi->pdevice, + &format_info, + &format_props); + if (result == VK_SUCCESS) + modifier_props[modifier_prop_count++] = modifier_props[i]; + } uint32_t max_modifier_count = 0; for (uint32_t l = 0; l < num_modifier_lists; l++) @@ -325,7 +507,7 @@ wsi_create_native_image(const struct wsi_swapchain *chain, */ for (uint32_t i = 0; i < num_modifiers[l]; i++) { for (uint32_t j = 0; j < modifier_prop_count; j++) { - if (modifier_props[j].modifier == modifiers[l][i]) + if (modifier_props[j].drmFormatModifier == modifiers[l][i]) image_modifiers[image_modifier_count++] = modifiers[l][i]; } } @@ -336,8 +518,13 @@ wsi_create_native_image(const struct wsi_swapchain *chain, } if (image_modifier_count > 0) { - image_wsi_info.modifier_count = image_modifier_count; - image_wsi_info.modifiers = image_modifiers; + image_modifier_list = (VkImageDrmFormatModifierListCreateInfoEXT) { + .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT, + .drmFormatModifierCount = image_modifier_count, + .pDrmFormatModifiers = image_modifiers, + }; + image_info.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; + __vk_append_struct(&image_info, &image_modifier_list); } else { /* TODO: Add a proper error here */ assert(!"Failed to find a supported modifier! This should never " @@ -347,27 +534,6 @@ wsi_create_native_image(const struct wsi_swapchain *chain, } } - const VkImageCreateInfo image_info = { - .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .pNext = &image_wsi_info, - .flags = 0, - .imageType = VK_IMAGE_TYPE_2D, - .format = pCreateInfo->imageFormat, - .extent = { - .width = pCreateInfo->imageExtent.width, - .height = pCreateInfo->imageExtent.height, - .depth = 1, - }, - .mipLevels = 1, - .arrayLayers = 1, - .samples = VK_SAMPLE_COUNT_1_BIT, - .tiling = VK_IMAGE_TILING_OPTIMAL, - .usage = pCreateInfo->imageUsage, - .sharingMode = pCreateInfo->imageSharingMode, - .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount, - .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, - }; result = wsi->CreateImage(chain->device, &image_info, &chain->alloc, &image->image); if (result != VK_SUCCESS) @@ -421,12 +587,22 @@ wsi_create_native_image(const struct wsi_swapchain *chain, goto fail; if (num_modifier_lists > 0) { - image->drm_modifier = wsi->image_get_modifier(image->image); + VkImageDrmFormatModifierPropertiesEXT image_mod_props = { + .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT, + }; + result = wsi->GetImageDrmFormatModifierPropertiesEXT(chain->device, + image->image, + &image_mod_props); + if (result != VK_SUCCESS) { + close(fd); + goto fail; + } + image->drm_modifier = image_mod_props.drmFormatModifier; assert(image->drm_modifier != DRM_FORMAT_MOD_INVALID); for (uint32_t j = 0; j < modifier_prop_count; j++) { - if (modifier_props[j].modifier == image->drm_modifier) { - image->num_planes = modifier_props[j].modifier_plane_count; + if (modifier_props[j].drmFormatModifier == image->drm_modifier) { + image->num_planes = modifier_props[j].drmFormatModifierPlaneCount; break; } } @@ -446,11 +622,12 @@ wsi_create_native_image(const struct wsi_swapchain *chain, if (p == 0) { image->fds[p] = fd; } else { - image->fds[p] = dup(fd); + image->fds[p] = os_dupfd_cloexec(fd); if (image->fds[p] == -1) { for (uint32_t i = 0; i < p; i++) - close(image->fds[p]); + close(image->fds[i]); + result = VK_ERROR_OUT_OF_HOST_MEMORY; goto fail; } } @@ -870,6 +1047,15 @@ wsi_common_create_swapchain(struct wsi_device *wsi, if (result != VK_SUCCESS) return result; + swapchain->fences = vk_zalloc(pAllocator, + sizeof (*swapchain->fences) * swapchain->image_count, + sizeof (*swapchain->fences), + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!swapchain->fences) { + swapchain->destroy(swapchain, pAllocator); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + *pSwapchain = wsi_swapchain_to_handle(swapchain); return VK_SUCCESS; @@ -880,7 +1066,7 @@ wsi_common_destroy_swapchain(VkDevice device, VkSwapchainKHR _swapchain, const VkAllocationCallbacks *pAllocator) { - WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain); + VK_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain); if (!swapchain) return; @@ -892,7 +1078,7 @@ wsi_common_get_images(VkSwapchainKHR _swapchain, uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) { - WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain); + VK_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain); VK_OUTARRAY_MAKE(images, pSwapchainImages, pSwapchainImageCount); for (uint32_t i = 0; i < swapchain->image_count; i++) { @@ -910,9 +1096,35 @@ wsi_common_acquire_next_image2(const struct wsi_device *wsi, const VkAcquireNextImageInfoKHR *pAcquireInfo, uint32_t *pImageIndex) { - WSI_FROM_HANDLE(wsi_swapchain, swapchain, pAcquireInfo->swapchain); + VK_FROM_HANDLE(wsi_swapchain, swapchain, pAcquireInfo->swapchain); + + VkResult result = swapchain->acquire_next_image(swapchain, pAcquireInfo, + pImageIndex); + if (result != VK_SUCCESS) + return result; + + if (wsi->set_memory_ownership) { + VkDeviceMemory mem = swapchain->get_wsi_image(swapchain, *pImageIndex)->memory; + wsi->set_memory_ownership(swapchain->device, mem, true); + } + + if (pAcquireInfo->semaphore != VK_NULL_HANDLE && + wsi->signal_semaphore_for_memory != NULL) { + struct wsi_image *image = + swapchain->get_wsi_image(swapchain, *pImageIndex); + wsi->signal_semaphore_for_memory(device, pAcquireInfo->semaphore, + image->memory); + } + + if (pAcquireInfo->fence != VK_NULL_HANDLE && + wsi->signal_fence_for_memory != NULL) { + struct wsi_image *image = + swapchain->get_wsi_image(swapchain, *pImageIndex); + wsi->signal_fence_for_memory(device, pAcquireInfo->fence, + image->memory); + } - return swapchain->acquire_next_image(swapchain, pAcquireInfo, pImageIndex); + return VK_SUCCESS; } VkResult @@ -928,10 +1140,11 @@ wsi_common_queue_present(const struct wsi_device *wsi, vk_find_struct_const(pPresentInfo->pNext, PRESENT_REGIONS_KHR); for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) { - WSI_FROM_HANDLE(wsi_swapchain, swapchain, pPresentInfo->pSwapchains[i]); + VK_FROM_HANDLE(wsi_swapchain, swapchain, pPresentInfo->pSwapchains[i]); + uint32_t image_index = pPresentInfo->pImageIndices[i]; VkResult result; - if (swapchain->fences[0] == VK_NULL_HANDLE) { + if (swapchain->fences[image_index] == VK_NULL_HANDLE) { const VkFenceCreateInfo fence_info = { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = NULL, @@ -939,16 +1152,34 @@ wsi_common_queue_present(const struct wsi_device *wsi, }; result = wsi->CreateFence(device, &fence_info, &swapchain->alloc, - &swapchain->fences[0]); + &swapchain->fences[image_index]); if (result != VK_SUCCESS) goto fail_present; } else { - wsi->ResetFences(device, 1, &swapchain->fences[0]); + result = + wsi->WaitForFences(device, 1, &swapchain->fences[image_index], + true, ~0ull); + if (result != VK_SUCCESS) + goto fail_present; + + result = + wsi->ResetFences(device, 1, &swapchain->fences[image_index]); + if (result != VK_SUCCESS) + goto fail_present; } + struct wsi_image *image = + swapchain->get_wsi_image(swapchain, image_index); + + struct wsi_memory_signal_submit_info mem_signal = { + .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA, + .pNext = NULL, + .memory = image->memory, + }; + VkSubmitInfo submit_info = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - .pNext = NULL, + .pNext = &mem_signal, }; VkPipelineStageFlags *stage_flags = NULL; @@ -979,14 +1210,13 @@ wsi_common_queue_present(const struct wsi_device *wsi, /* If we are using prime blits, we need to perform the blit now. The * command buffer is attached to the image. */ - struct wsi_image *image = - swapchain->get_wsi_image(swapchain, pPresentInfo->pImageIndices[i]); submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &image->prime.blit_cmd_buffers[queue_family_index]; + mem_signal.memory = image->prime.memory; } - result = wsi->QueueSubmit(queue, 1, &submit_info, swapchain->fences[0]); + result = wsi->QueueSubmit(queue, 1, &submit_info, swapchain->fences[image_index]); vk_free(&swapchain->alloc, stage_flags); if (result != VK_SUCCESS) goto fail_present; @@ -995,19 +1225,13 @@ wsi_common_queue_present(const struct wsi_device *wsi, if (regions && regions->pRegions) region = ®ions->pRegions[i]; - result = swapchain->queue_present(swapchain, - pPresentInfo->pImageIndices[i], - region); + result = swapchain->queue_present(swapchain, image_index, region); if (result != VK_SUCCESS) goto fail_present; - VkFence last = swapchain->fences[2]; - swapchain->fences[2] = swapchain->fences[1]; - swapchain->fences[1] = swapchain->fences[0]; - swapchain->fences[0] = last; - - if (last != VK_NULL_HANDLE) { - wsi->WaitForFences(device, 1, &last, true, 1); + if (wsi->set_memory_ownership) { + VkDeviceMemory mem = swapchain->get_wsi_image(swapchain, image_index)->memory; + wsi->set_memory_ownership(swapchain->device, mem, false); } fail_present: @@ -1021,3 +1245,11 @@ wsi_common_queue_present(const struct wsi_device *wsi, return final_result; } + +uint64_t +wsi_common_get_current_time(void) +{ + struct timespec current; + clock_gettime(CLOCK_MONOTONIC, ¤t); + return current.tv_nsec + current.tv_sec * 1000000000ull; +}