static VkResult x11_swapchain_destroy(struct wsi_swapchain *anv_chain, const VkAllocationCallbacks *pAllocator) { struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain; xcb_void_cookie_t cookie; for (uint32_t i = 0; i < chain->image_count; i++) x11_image_finish(chain, pAllocator, &chain->images[i]); if (chain->threaded) { chain->status = VK_ERROR_OUT_OF_DATE_KHR; /* Push a UINT32_MAX to wake up the manager */ wsi_queue_push(&chain->present_queue, UINT32_MAX); pthread_join(chain->queue_manager, NULL); wsi_queue_destroy(&chain->acquire_queue); wsi_queue_destroy(&chain->present_queue); } xcb_unregister_for_special_event(chain->conn, chain->special_event); cookie = xcb_present_select_input_checked(chain->conn, chain->event_id, chain->window, XCB_PRESENT_EVENT_MASK_NO_EVENT); xcb_discard_reply(chain->conn, cookie.sequence); vk_free(pAllocator, chain); return VK_SUCCESS; }
static void vl_dri3_screen_destroy(struct vl_screen *vscreen) { struct vl_dri3_screen *scrn = (struct vl_dri3_screen *)vscreen; int i; assert(vscreen); dri3_flush_present_events(scrn); if (scrn->front_buffer) { dri3_free_front_buffer(scrn, scrn->front_buffer); scrn->front_buffer = NULL; return; } for (i = 0; i < BACK_BUFFER_NUM; ++i) { if (scrn->back_buffers[i]) { dri3_free_back_buffer(scrn, scrn->back_buffers[i]); scrn->back_buffers[i] = NULL; } } if (scrn->special_event) xcb_unregister_for_special_event(scrn->conn, scrn->special_event); scrn->base.pscreen->destroy(scrn->base.pscreen); pipe_loader_release(&scrn->base.dev, 1); FREE(scrn); return; }
static bool dri3_set_drawable(struct vl_dri3_screen *scrn, Drawable drawable) { xcb_get_geometry_cookie_t geom_cookie; xcb_get_geometry_reply_t *geom_reply; xcb_void_cookie_t cookie; xcb_generic_error_t *error; xcb_present_event_t peid; bool ret = true; assert(drawable); if (scrn->drawable == drawable) return true; scrn->drawable = drawable; geom_cookie = xcb_get_geometry(scrn->conn, scrn->drawable); geom_reply = xcb_get_geometry_reply(scrn->conn, geom_cookie, NULL); if (!geom_reply) return false; scrn->width = geom_reply->width; scrn->height = geom_reply->height; scrn->depth = geom_reply->depth; free(geom_reply); if (scrn->special_event) { xcb_unregister_for_special_event(scrn->conn, scrn->special_event); scrn->special_event = NULL; } scrn->is_pixmap = false; peid = xcb_generate_id(scrn->conn); cookie = xcb_present_select_input_checked(scrn->conn, peid, scrn->drawable, XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY | XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY | XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY); error = xcb_request_check(scrn->conn, cookie); if (error) { if (error->error_code != BadWindow) ret = false; else { scrn->is_pixmap = true; if (scrn->front_buffer) { dri3_free_front_buffer(scrn, scrn->front_buffer); scrn->front_buffer = NULL; } } free(error); } else scrn->special_event = xcb_register_for_special_xge(scrn->conn, &xcb_present_id, peid, 0); dri3_flush_present_events(scrn); return ret; }
static BOOL PRESENTPrivChangeWindow(PRESENTpriv *present_priv, XID window) { xcb_void_cookie_t cookie; xcb_generic_error_t *error; xcb_present_event_t eid; PRESENTForceReleases(present_priv); PRESENTFreeXcbQueue(present_priv); present_priv->window = window; if (window) { cookie = xcb_present_select_input_checked(present_priv->xcb_connection, (eid = xcb_generate_id(present_priv->xcb_connection)), window, XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY| XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY); present_priv->special_event = xcb_register_for_special_xge(present_priv->xcb_connection, &xcb_present_id, eid, NULL); error = xcb_request_check(present_priv->xcb_connection, cookie); /* performs a flush */ if (error || !present_priv->special_event) { ERR("FAILED to use the X PRESENT extension. Was the destination a window ?\n"); if (present_priv->special_event) xcb_unregister_for_special_event(present_priv->xcb_connection, present_priv->special_event); present_priv->special_event = NULL; present_priv->window = 0; } } return (present_priv->window != 0); }
static void PRESENTFreeXcbQueue(PRESENTpriv *present_priv) { if (present_priv->window) { xcb_unregister_for_special_event(present_priv->xcb_connection, present_priv->special_event); present_priv->last_msc = 0; present_priv->last_target = 0; present_priv->special_event = NULL; } }
void loader_dri3_drawable_fini(struct loader_dri3_drawable *draw) { int i; (draw->ext->core->destroyDrawable)(draw->dri_drawable); for (i = 0; i < LOADER_DRI3_NUM_BUFFERS; i++) { if (draw->buffers[i]) dri3_free_render_buffer(draw, draw->buffers[i]); } if (draw->special_event) xcb_unregister_for_special_event(draw->conn, draw->special_event); }
void loader_dri3_drawable_fini(struct loader_dri3_drawable *draw) { int i; (draw->ext->core->destroyDrawable)(draw->dri_drawable); for (i = 0; i < LOADER_DRI3_NUM_BUFFERS; i++) { if (draw->buffers[i]) dri3_free_render_buffer(draw, draw->buffers[i]); } if (draw->special_event) { xcb_void_cookie_t cookie = xcb_present_select_input_checked(draw->conn, draw->eid, draw->drawable, XCB_PRESENT_EVENT_MASK_NO_EVENT); xcb_discard_reply(draw->conn, cookie.sequence); xcb_unregister_for_special_event(draw->conn, draw->special_event); } }
static void vl_dri3_screen_destroy(struct vl_screen *vscreen) { struct vl_dri3_screen *scrn = (struct vl_dri3_screen *)vscreen; int i; assert(vscreen); dri3_flush_present_events(scrn); if (scrn->front_buffer) { dri3_free_front_buffer(scrn, scrn->front_buffer); scrn->front_buffer = NULL; } for (i = 0; i < BACK_BUFFER_NUM; ++i) { if (scrn->back_buffers[i]) { dri3_free_back_buffer(scrn, scrn->back_buffers[i]); scrn->back_buffers[i] = NULL; } } if (scrn->special_event) { xcb_void_cookie_t cookie = xcb_present_select_input_checked(scrn->conn, scrn->eid, scrn->drawable, XCB_PRESENT_EVENT_MASK_NO_EVENT); xcb_discard_reply(scrn->conn, cookie.sequence); xcb_unregister_for_special_event(scrn->conn, scrn->special_event); } scrn->pipe->destroy(scrn->pipe); scrn->base.pscreen->destroy(scrn->base.pscreen); pipe_loader_release(&scrn->base.dev, 1); FREE(scrn); return; }
virtual void unregister_for_special_event(xcb_special_event_t * se) const { xcb_unregister_for_special_event(m_c.get(), se); }
/** loader_dri3_update_drawable * * Called the first time we use the drawable and then * after we receive present configure notify events to * track the geometry of the drawable */ static int dri3_update_drawable(__DRIdrawable *driDrawable, struct loader_dri3_drawable *draw) { if (draw->first_init) { xcb_get_geometry_cookie_t geom_cookie; xcb_get_geometry_reply_t *geom_reply; xcb_void_cookie_t cookie; xcb_generic_error_t *error; xcb_present_query_capabilities_cookie_t present_capabilities_cookie; xcb_present_query_capabilities_reply_t *present_capabilities_reply; draw->first_init = false; /* Try to select for input on the window. * * If the drawable is a window, this will get our events * delivered. * * Otherwise, we'll get a BadWindow error back from this request which * will let us know that the drawable is a pixmap instead. */ draw->eid = xcb_generate_id(draw->conn); cookie = xcb_present_select_input_checked(draw->conn, draw->eid, draw->drawable, XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY | XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY | XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY); present_capabilities_cookie = xcb_present_query_capabilities(draw->conn, draw->drawable); /* Create an XCB event queue to hold present events outside of the usual * application event queue */ draw->special_event = xcb_register_for_special_xge(draw->conn, &xcb_present_id, draw->eid, draw->stamp); geom_cookie = xcb_get_geometry(draw->conn, draw->drawable); geom_reply = xcb_get_geometry_reply(draw->conn, geom_cookie, NULL); if (!geom_reply) return false; draw->width = geom_reply->width; draw->height = geom_reply->height; draw->depth = geom_reply->depth; draw->vtable->set_drawable_size(draw, draw->width, draw->height); free(geom_reply); draw->is_pixmap = false; /* Check to see if our select input call failed. If it failed with a * BadWindow error, then assume the drawable is a pixmap. Destroy the * special event queue created above and mark the drawable as a pixmap */ error = xcb_request_check(draw->conn, cookie); present_capabilities_reply = xcb_present_query_capabilities_reply(draw->conn, present_capabilities_cookie, NULL); if (present_capabilities_reply) { draw->present_capabilities = present_capabilities_reply->capabilities; free(present_capabilities_reply); } else draw->present_capabilities = 0; if (error) { if (error->error_code != BadWindow) { free(error); return false; } draw->is_pixmap = true; xcb_unregister_for_special_event(draw->conn, draw->special_event); draw->special_event = NULL; } } dri3_flush_present_events(draw); return true; }
static VkResult x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, VkDevice device, struct wsi_device *wsi_device, const VkSwapchainCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks* pAllocator, const struct wsi_image_fns *image_fns, struct wsi_swapchain **swapchain_out) { struct x11_swapchain *chain; xcb_void_cookie_t cookie; VkResult result; assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); const unsigned num_images = pCreateInfo->minImageCount; size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]); chain = vk_alloc(pAllocator, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (chain == NULL) return VK_ERROR_OUT_OF_HOST_MEMORY; xcb_connection_t *conn = x11_surface_get_connection(icd_surface); xcb_window_t window = x11_surface_get_window(icd_surface); xcb_get_geometry_reply_t *geometry = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, window), NULL); if (geometry == NULL) return VK_ERROR_SURFACE_LOST_KHR; chain->base.device = device; chain->base.destroy = x11_swapchain_destroy; chain->base.get_images = x11_get_images; chain->base.acquire_next_image = x11_acquire_next_image; chain->base.queue_present = x11_queue_present; chain->base.image_fns = image_fns; chain->base.present_mode = pCreateInfo->presentMode; chain->conn = conn; chain->window = window; chain->depth = geometry->depth; chain->extent = pCreateInfo->imageExtent; chain->image_count = num_images; chain->send_sbc = 0; chain->last_present_msc = 0; chain->threaded = false; chain->status = VK_SUCCESS; free(geometry); chain->event_id = xcb_generate_id(chain->conn); xcb_present_select_input(chain->conn, chain->event_id, chain->window, XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY | XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY | XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY); /* Create an XCB event queue to hold present events outside of the usual * application event queue */ chain->special_event = xcb_register_for_special_xge(chain->conn, &xcb_present_id, chain->event_id, NULL); chain->gc = xcb_generate_id(chain->conn); if (!chain->gc) { /* FINISHME: Choose a better error. */ result = VK_ERROR_OUT_OF_HOST_MEMORY; goto fail_register; } cookie = xcb_create_gc(chain->conn, chain->gc, chain->window, XCB_GC_GRAPHICS_EXPOSURES, (uint32_t []) { 0 }); xcb_discard_reply(chain->conn, cookie.sequence); uint32_t image = 0; for (; image < chain->image_count; image++) { result = x11_image_init(device, chain, pCreateInfo, pAllocator, &chain->images[image]); if (result != VK_SUCCESS) goto fail_init_images; } if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) { chain->threaded = true; /* Initialize our queues. We make them image_count + 1 because we will * occasionally use UINT32_MAX to signal the other thread that an error * has occurred and we don't want an overflow. */ int ret; ret = wsi_queue_init(&chain->acquire_queue, chain->image_count + 1); if (ret) { goto fail_init_images; } ret = wsi_queue_init(&chain->present_queue, chain->image_count + 1); if (ret) { wsi_queue_destroy(&chain->acquire_queue); goto fail_init_images; } for (unsigned i = 0; i < chain->image_count; i++) wsi_queue_push(&chain->acquire_queue, i); ret = pthread_create(&chain->queue_manager, NULL, x11_manage_fifo_queues, chain); if (ret) { wsi_queue_destroy(&chain->present_queue); wsi_queue_destroy(&chain->acquire_queue); goto fail_init_images; } } *swapchain_out = &chain->base; return VK_SUCCESS; fail_init_images: for (uint32_t j = 0; j < image; j++) x11_image_finish(chain, pAllocator, &chain->images[j]); fail_register: xcb_unregister_for_special_event(chain->conn, chain->special_event); vk_free(pAllocator, chain); return result; }