diff --git a/src/vulkan/wsi/wsi_common_display.c b/src/vulkan/wsi/wsi_common_display.c index 60829ce38d9..72bb2ec3a91 100644 --- a/src/vulkan/wsi/wsi_common_display.c +++ b/src/vulkan/wsi/wsi_common_display.c @@ -20,6 +20,7 @@ * OF THIS SOFTWARE. */ +#include "util/u_atomic.h" #include "util/macros.h" #include #include @@ -89,6 +90,7 @@ typedef struct wsi_display_connector { char *name; bool connected; bool active; + int refcount; /* swapchains using this connector */ struct list_head display_modes; wsi_display_mode *current_mode; drmModeModeInfo current_drm_mode; @@ -294,6 +296,18 @@ wsi_display_find_connector(struct wsi_device *wsi_device, return NULL; } + +static uint32_t +wsi_display_is_crtc_available(const struct wsi_display * const wsi, + const uint32_t crtc_id) +{ + wsi_for_each_connector(connector, wsi) + if (connector->crtc_id == crtc_id) + return false; + + return true; +} + static struct wsi_display_connector * wsi_display_alloc_connector(struct wsi_display *wsi, uint32_t connector_id) @@ -1231,7 +1245,13 @@ wsi_display_swapchain_destroy(struct wsi_swapchain *drv_chain, mtx_destroy(&chain->present_id_mutex); u_cnd_monotonic_destroy(&chain->present_id_cond); + wsi_display_mode *display_mode = + wsi_display_mode_from_handle(chain->surface->displayMode); + if (p_atomic_dec_zero(&display_mode->connector->refcount)) + display_mode->connector->crtc_id = 0; + wsi_swapchain_finish(&chain->base); + vk_free(allocator, chain); return VK_SUCCESS; } @@ -1581,7 +1601,8 @@ wsi_display_select_crtc(const struct wsi_display_connector *connector, uint32_t crtc_id = 0; for (int c = 0; crtc_id == 0 && c < mode_res->count_crtcs; c++) { drmModeCrtcPtr crtc = drmModeGetCrtc(wsi->fd, mode_res->crtcs[c]); - if (crtc && crtc->buffer_id == 0) + if (crtc && crtc->buffer_id == 0 && + wsi_display_is_crtc_available(wsi, crtc->crtc_id)) crtc_id = crtc->crtc_id; drmModeFreeCrtc(crtc); } @@ -1959,13 +1980,6 @@ _wsi_display_queue_next(struct wsi_swapchain *drv_chain) } if (ret == -EINVAL) { - VkResult result = wsi_display_setup_connector(connector, display_mode); - - if (result != VK_SUCCESS) { - image->state = WSI_IMAGE_IDLE; - return result; - } - /* XXX allow setting of position */ ret = drmModeSetCrtc(wsi->fd, connector->crtc_id, image->fb_id, 0, 0, @@ -2178,6 +2192,15 @@ wsi_display_surface_create_swapchain( chain->surface = (VkIcdSurfaceDisplay *) icd_surface; + wsi_display_mode *display_mode = + wsi_display_mode_from_handle(chain->surface->displayMode); + + result = wsi_display_setup_connector(display_mode->connector, display_mode); + if (result != VK_SUCCESS) + return result; + + p_atomic_inc(&display_mode->connector->refcount); + for (uint32_t image = 0; image < chain->base.image_count; image++) { result = wsi_display_image_init(&chain->base, create_info,